From b29dbd45d95287a08db648bb886f8273bc904bfb Mon Sep 17 00:00:00 2001 From: awwit Date: Thu, 18 Sep 2014 22:13:56 +0300 Subject: [PATCH 01/31] Replaced 'select' on 'epoll/poll/WSAPoll' --- httpserverapp.userprefs | 12 +- httpserverapp/FileIncoming.cpp | 4 +- httpserverapp/ResourceAbstract.cpp | 35 ----- httpserverapp/ResourceAbstract.h | 32 ----- httpserverapp/ResourceMethodAbstract.h | 24 ---- httpserverapp/ResourceMethodOptions.cpp | 28 ---- httpserverapp/ResourceMethodOptions.h | 14 -- httpserverapp/Socket.cpp | 166 +++++++++--------------- httpserverapp/Socket.h | 2 + httpserverapp/Test.cpp | 35 +++-- httpserverapp/Utils.cpp | 94 +++++++++++++- httpserverapp/Utils.h | 5 +- httpserverapp/httpserverapp.cproj | 5 - 13 files changed, 180 insertions(+), 276 deletions(-) delete mode 100644 httpserverapp/ResourceAbstract.cpp delete mode 100644 httpserverapp/ResourceAbstract.h delete mode 100644 httpserverapp/ResourceMethodAbstract.h delete mode 100644 httpserverapp/ResourceMethodOptions.cpp delete mode 100644 httpserverapp/ResourceMethodOptions.h diff --git a/httpserverapp.userprefs b/httpserverapp.userprefs index 5caf378..2d6da20 100644 --- a/httpserverapp.userprefs +++ b/httpserverapp.userprefs @@ -1,21 +1,21 @@  - + - + - + - + - + - + diff --git a/httpserverapp/FileIncoming.cpp b/httpserverapp/FileIncoming.cpp index ee590d2..4f20f95 100644 --- a/httpserverapp/FileIncoming.cpp +++ b/httpserverapp/FileIncoming.cpp @@ -18,10 +18,8 @@ namespace HttpServer } FileIncoming::FileIncoming(FileIncoming &&file) - : file_name(file.file_name), file_type(file.file_type), file_size(file.file_size) + : file_name(std::move(file.file_name) ), file_type(std::move(file.file_type) ), file_size(file.file_size) { - file.file_name.clear(); - file.file_type.clear(); file.file_size = 0; } diff --git a/httpserverapp/ResourceAbstract.cpp b/httpserverapp/ResourceAbstract.cpp deleted file mode 100644 index aa51959..0000000 --- a/httpserverapp/ResourceAbstract.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "ResourceAbstract.h" - -#include "ResourceMethodAbstract.h" -#include "ResourceMethodOptions.h" - -namespace HttpServer -{ - ResourceAbstract::ResourceAbstract() - { - addMethod(new ResourceMethodOptions() ); - } - - ResourceAbstract::~ResourceAbstract() - { - for (auto &method : methods) - { - delete method.second; - } - - for (auto &resource : resources) - { - delete resource.second; - } - } - - void ResourceAbstract::addMethod(ResourceMethodAbstract *method) - { - methods.emplace(method->getName(), method); - } - - void ResourceAbstract::addResource(ResourceAbstract *resource) - { - resources.emplace(resource->getName(), resource); - } -}; diff --git a/httpserverapp/ResourceAbstract.h b/httpserverapp/ResourceAbstract.h deleted file mode 100644 index 3df64af..0000000 --- a/httpserverapp/ResourceAbstract.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -namespace HttpServer -{ - class ResourceMethodAbstract; - - class ResourceAbstract - { - protected: - std::string resource_name; - - public: - std::unordered_map methods; - - std::unordered_map resources; - - private: - void addMethod(ResourceMethodAbstract *); - void addResource(ResourceAbstract *); - - public: - ResourceAbstract(); - ~ResourceAbstract(); - - inline std::string getName() const - { - return resource_name; - } - }; -}; diff --git a/httpserverapp/ResourceMethodAbstract.h b/httpserverapp/ResourceMethodAbstract.h deleted file mode 100644 index 42d87a0..0000000 --- a/httpserverapp/ResourceMethodAbstract.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "ServerRequest.h" -#include "ServerResponse.h" -#include "ResourceAbstract.h" - -#include - -namespace HttpServer -{ - class ResourceMethodAbstract - { - protected: - std::string resource_method_name; - - public: - inline std::string getName() const - { - return resource_method_name; - } - - virtual void execute(ResourceAbstract *, ServerRequest &, ServerResponse &) = 0; - }; -}; diff --git a/httpserverapp/ResourceMethodOptions.cpp b/httpserverapp/ResourceMethodOptions.cpp deleted file mode 100644 index e895240..0000000 --- a/httpserverapp/ResourceMethodOptions.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "ResourceMethodOptions.h" - -namespace HttpServer -{ - ResourceMethodOptions::ResourceMethodOptions() - { - resource_method_name = "OPTIONS"; - } - - void ResourceMethodOptions::execute(ResourceAbstract *resource, ServerRequest &request, ServerResponse &response) - { - std::string options; - - for (auto &method : resource->methods) - { - if (method.second != this) - { - options += method.first; - options.push_back(','); - } - } - - if (options.length() ) - { - options.pop_back(); - } - } -}; diff --git a/httpserverapp/ResourceMethodOptions.h b/httpserverapp/ResourceMethodOptions.h deleted file mode 100644 index 2a170a4..0000000 --- a/httpserverapp/ResourceMethodOptions.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "ResourceMethodAbstract.h" - -namespace HttpServer -{ - class ResourceMethodOptions: public ResourceMethodAbstract - { - public: - ResourceMethodOptions(); - - virtual void execute(ResourceAbstract *, ServerRequest &, ServerResponse &) override; - }; -}; diff --git a/httpserverapp/Socket.cpp b/httpserverapp/Socket.cpp index bd79fbd..f81d03e 100644 --- a/httpserverapp/Socket.cpp +++ b/httpserverapp/Socket.cpp @@ -110,28 +110,24 @@ namespace HttpServer { System::native_socket_type client_socket = ~0; #ifdef WIN32 - ::fd_set readset; - FD_ZERO(&readset); - FD_SET(socket_handle, &readset); + WSAPOLLFD event = {0}; - if (0 < ::select(socket_handle + 1, &readset, nullptr, nullptr, nullptr) ) + event.fd = socket_handle; + event.events = POLLRDNORM; + + if (1 == ::WSAPoll(&event, 1, ~0) && event.revents | POLLRDNORM) { - if (FD_ISSET(socket_handle, &readset) ) - { - client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); - } + client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #elif POSIX - ::fd_set readset; - FD_ZERO(&readset); - FD_SET(socket_handle, &readset); + struct ::pollfd event = {0}; + + event.fd = socket_handle; + event.events = POLLIN; - if (0 < ::select(socket_handle + 1, &readset, nullptr, nullptr, nullptr) ) + if (1 == ::poll(&event, 1, ~0) && event.revents | POLLIN) { - if (FD_ISSET(socket_handle, &readset) ) - { - client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); - } + client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #else #error "Undefine platform" @@ -143,34 +139,24 @@ namespace HttpServer { System::native_socket_type client_socket = ~0; #ifdef WIN32 - ::fd_set readset; - FD_ZERO(&readset); - FD_SET(socket_handle, &readset); + WSAPOLLFD event = {0}; - long seconds = timeWait.count() / 1000; - ::timeval timeout {seconds, (timeWait.count() - seconds * 1000) * 1000}; + event.fd = socket_handle; + event.events = POLLRDNORM; - if (0 < ::select(socket_handle + 1, &readset, nullptr, nullptr, &timeout) ) + if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents | POLLRDNORM) { - if (FD_ISSET(socket_handle, &readset) ) - { - client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); - } + client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #elif POSIX - ::fd_set readset; - FD_ZERO(&readset); - FD_SET(socket_handle, &readset); + struct ::pollfd event = {0}; - long seconds = timeWait.count() / 1000; - ::timeval timeout {seconds, (timeWait.count() - seconds * 1000) * 1000}; + event.fd = socket_handle; + event.events = POLLIN; - if (0 < ::select(socket_handle + 1, &readset, nullptr, nullptr, &timeout) ) + if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents | POLLIN) { - if (FD_ISSET(socket_handle, &readset) ) - { - client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); - } + client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #else #error "Undefine platform" @@ -231,43 +217,31 @@ namespace HttpServer size_t Socket::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeWait) const { + size_t recv_len = ~0; #ifdef WIN32 - ::fd_set readset; - FD_ZERO(&readset); - FD_SET(socket_handle, &readset); + WSAPOLLFD event = {0}; - long seconds = timeWait.count() / 1000; - ::timeval timeout {seconds, (timeWait.count() - seconds * 1000) * 1000}; + event.fd = socket_handle; + event.events = POLLRDNORM; - if (0 < ::select(socket_handle + 1, &readset, nullptr, nullptr, &timeout) ) + if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents | POLLRDNORM) { - if (FD_ISSET(socket_handle, &readset) ) - { - return ::recv(socket_handle, buf.data(), buf.size(), 0); - } + recv_len = ::recv(socket_handle, buf.data(), buf.size(), 0); } - - return std::numeric_limits::max(); #elif POSIX - ::fd_set readset; - FD_ZERO(&readset); - FD_SET(socket_handle, &readset); + struct ::pollfd event = {0}; - long seconds = timeWait.count() / 1000; - ::timeval timeout {seconds, (timeWait.count() - seconds * 1000) * 1000}; + event.fd = socket_handle; + event.events = POLLIN; - if (0 < ::select(socket_handle + 1, &readset, nullptr, nullptr, &timeout) ) + if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents | POLLIN) { - if (FD_ISSET(socket_handle, &readset) ) - { - return ::recv(socket_handle, buf.data(), buf.size(), MSG_NOSIGNAL); - } + recv_len = ::recv(socket_handle, buf.data(), buf.size(), MSG_NOSIGNAL); } - - return std::numeric_limits::max(); #else #error "Undefine platform" #endif + return recv_len; } size_t Socket::send(const std::string &buf) const @@ -294,84 +268,60 @@ namespace HttpServer size_t Socket::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeWait) const { + size_t send_len = ~0; #ifdef WIN32 - ::fd_set writeset; - FD_ZERO(&writeset); - FD_SET(socket_handle, &writeset); + WSAPOLLFD event = {0}; - long seconds = timeWait.count() / 1000; - ::timeval timeout {seconds, (timeWait.count() - seconds * 1000) * 1000}; + event.fd = socket_handle; + event.events = POLLWRNORM; - if (0 < ::select(socket_handle + 1, nullptr, &writeset, nullptr, &timeout) ) + if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents | POLLWRNORM) { - if (FD_ISSET(socket_handle, &writeset) ) - { - return ::send(socket_handle, buf.data(), buf.length(), 0); - } + send_len = ::send(socket_handle, buf.data(), buf.length(), 0); } - - return std::numeric_limits::max(); #elif POSIX - ::fd_set writeset; - FD_ZERO(&writeset); - FD_SET(socket_handle, &writeset); + struct ::pollfd event = {0}; - long seconds = timeWait.count() / 1000; - ::timeval timeout {seconds, (timeWait.count() - seconds * 1000) * 1000}; + event.fd = socket_handle; + event.events = POLLOUT; - if (0 < ::select(socket_handle + 1, nullptr, &writeset, nullptr, &timeout) ) + if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents | POLLOUT) { - if (FD_ISSET(socket_handle, &writeset) ) - { - return ::send(socket_handle, buf.data(), buf.length(), MSG_NOSIGNAL); - } + send_len = ::send(socket_handle, buf.data(), buf.length(), MSG_NOSIGNAL); } - - return std::numeric_limits::max(); #else #error "Undefine platform" #endif + return send_len; } size_t Socket::nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeWait) const { + size_t send_len = ~0; #ifdef WIN32 - ::fd_set writeset; - FD_ZERO(&writeset); - FD_SET(socket_handle, &writeset); + WSAPOLLFD event = {0}; - long seconds = timeWait.count() / 1000; - ::timeval timeout {seconds, (timeWait.count() - seconds * 1000) * 1000}; + event.fd = socket_handle; + event.events = POLLWRNORM; - if (0 < ::select(socket_handle + 1, nullptr, &writeset, nullptr, &timeout) ) + if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents | POLLWRNORM) { - if (FD_ISSET(socket_handle, &writeset) ) - { - return ::send(socket_handle, buf.data(), length, 0); - } + send_len = ::send(socket_handle, buf.data(), length, 0); } - - return std::numeric_limits::max(); #elif POSIX - ::fd_set writeset; - FD_ZERO(&writeset); - FD_SET(socket_handle, &writeset); + struct ::pollfd event = {0}; - long seconds = timeWait.count() / 1000; - ::timeval timeout {seconds, (timeWait.count() - seconds * 1000) * 1000}; + event.fd = socket_handle; + event.events = POLLOUT; - if (0 < ::select(socket_handle + 1, nullptr, &writeset, nullptr, &timeout) ) + if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents | POLLOUT) { - if (FD_ISSET(socket_handle, &writeset) ) - { - return ::send(socket_handle, buf.data(), length, MSG_WAITALL | MSG_NOSIGNAL); - } + send_len = ::send(socket_handle, buf.data(), length, MSG_WAITALL | MSG_NOSIGNAL); } - - return std::numeric_limits::max(); #else #error "Undefine platform" #endif + return send_len; } Socket &Socket::operator=(const Socket s) diff --git a/httpserverapp/Socket.h b/httpserverapp/Socket.h index 4774055..91b15ec 100644 --- a/httpserverapp/Socket.h +++ b/httpserverapp/Socket.h @@ -7,6 +7,8 @@ #elif POSIX #include #include + #include + #include #include #include #include diff --git a/httpserverapp/Test.cpp b/httpserverapp/Test.cpp index 24bf3ab..21fa908 100644 --- a/httpserverapp/Test.cpp +++ b/httpserverapp/Test.cpp @@ -13,27 +13,34 @@ bool test(HttpServer::ServerRequest &request, HttpServer::ServerResponse &respon for (auto h = incoming_headers.cbegin(); h != incoming_headers.cend(); ++h) { - s += h->first + ":" + h->second + "\n"; + s += h->first + ": " + h->second + '\n'; } - s += "\n"; + s += '\n'; for (auto v = incoming_data.cbegin(); v != incoming_data.cend(); ++v) { - s += v->first + ": " + v->second + "\n"; + s += v->first + ": " + v->second + '\n'; } -/* s = "\ -\ -\ - \ -\ - \ -
1\ - 2\ -
3\ - 4\ -
";*/ + s += '\n'; + + for (auto &p : request.params) + { + s += p.first + ": " + p.second + '\n'; + } + + s = R"( + + + + + +
1 + 2 +
3 + 4 +
)"; headers_outgoing[""] = "HTTP/1.1 200 OK"; headers_outgoing["Content-Type"] = "text/plain; charset=utf-8"; diff --git a/httpserverapp/Utils.cpp b/httpserverapp/Utils.cpp index 498bc6d..e75c023 100644 --- a/httpserverapp/Utils.cpp +++ b/httpserverapp/Utils.cpp @@ -2,6 +2,7 @@ #include "Utils.h" #include +#include namespace Utils { @@ -119,7 +120,7 @@ namespace Utils { for (size_t i = 0; i < count; ++i) { - map.emplace(raw[i].key ? raw[i].key : "", raw[i].value); + map.emplace(raw[i].key ? raw[i].key : "", raw[i].value ? raw[i].value : ""); } } @@ -127,7 +128,7 @@ namespace Utils { for (size_t i = 0; i < count; ++i) { - map.emplace(raw[i].key, raw[i].value); + map.emplace(raw[i].key ? raw[i].key : "", raw[i].value ? raw[i].value : ""); } } @@ -135,7 +136,7 @@ namespace Utils { for (size_t i = 0; i < count; ++i) { - map.emplace(raw[i].key, raw[i].value); + map.emplace(raw[i].key ? raw[i].key : "", raw[i].value ? raw[i].value : ""); } } @@ -143,7 +144,7 @@ namespace Utils { for (size_t i = 0; i < count; ++i) { - map.emplace(raw[i].key, HttpServer::FileIncoming(raw[i].file_name, raw[i].file_type, raw[i].file_size) ); + map.emplace(raw[i].key ? raw[i].key : "", HttpServer::FileIncoming(raw[i].file_name, raw[i].file_type, raw[i].file_size) ); } } @@ -224,7 +225,7 @@ namespace Utils ::time_t cur_time = tTime; - if (std::numeric_limits<::time_t>::max() == tTime) + if ( (time_t)~0 == tTime) { ::time(&cur_time); } @@ -278,7 +279,7 @@ namespace Utils for (size_t cur_pos = 0, next_value; std::string::npos != cur_pos; cur_pos = next_value) { - next_value = cookieHeader.find(' ', cur_pos); + next_value = cookieHeader.find(';', cur_pos); size_t delimiter = cookieHeader.find('=', cur_pos); @@ -289,11 +290,13 @@ namespace Utils std::string key = cookieHeader.substr(cur_pos, delimiter - cur_pos); trim(key); + key = urlDecode(key); ++delimiter; std::string value = cookieHeader.substr(delimiter, std::string::npos != next_value ? next_value - delimiter : next_value); trim(value); + value = urlDecode(value); cookies.emplace(std::move(key), std::move(value) ); @@ -305,4 +308,83 @@ namespace Utils return true; } + + inline bool isUrlAllowed(const std::string::value_type c) + { + static const std::string special("-_.~"); + + return std::string::npos != special.find(c); + } + + std::string urlEncode(const std::string &str) + { + std::ostringstream encoded; + encoded.fill('0'); + encoded << std::hex; + + for (auto it = str.cbegin(); str.cend() != it; ++it) + { + const std::string::value_type &c = *it; + + if (' ' == c) + { + encoded << '+'; + } + else if (std::isalnum(c) || isUrlAllowed(c) ) + { + encoded << c; + } + else + { + encoded << '%' << std::setw(2) << (int) ( (unsigned char) c); + } + } + + return encoded.str(); + } + + std::string urlDecode(const std::string &str) + { + std::string decoded; + + std::string::value_type ch[3] = {0}; + + for (auto it = str.cbegin(); str.cend() != it; ++it) + { + const std::string::value_type &c = *it; + + if ('%' == c) + { + ++it; + + if (str.cend() == it) + { + break; + } + + ch[0] = *it; + + ++it; + + if (str.cend() == it) + { + break; + } + + ch[1] = *it; + + decoded.push_back(strtoul(ch, nullptr, 16) ); + } + else if ('+' == c) + { + decoded.push_back(' '); + } + else + { + decoded.push_back(c); + } + } + + return decoded; + } }; \ No newline at end of file diff --git a/httpserverapp/Utils.h b/httpserverapp/Utils.h index 103dccb..ce42994 100644 --- a/httpserverapp/Utils.h +++ b/httpserverapp/Utils.h @@ -49,9 +49,12 @@ namespace Utils time_t stringTimeToTimestamp(const std::string &); - std::string getDatetimeStringValue(const ::time_t = std::numeric_limits<::time_t>::max(), const bool = false); + std::string getDatetimeStringValue(const ::time_t tTime = ~0, const bool isGmtTime = false); size_t getNumberLength(const size_t number); bool parseCookies(const std::string &, std::unordered_multimap &); + + std::string urlEncode(const std::string &); + std::string urlDecode(const std::string &); }; diff --git a/httpserverapp/httpserverapp.cproj b/httpserverapp/httpserverapp.cproj index 3393b9c..a511002 100644 --- a/httpserverapp/httpserverapp.cproj +++ b/httpserverapp/httpserverapp.cproj @@ -32,9 +32,6 @@ - - - @@ -46,8 +43,6 @@ - - From 54f8e420aef030f23b2ea99d9c3f13d3a3c95212 Mon Sep 17 00:00:00 2001 From: awwit Date: Mon, 16 Nov 2015 14:27:41 +0300 Subject: [PATCH 02/31] Reorganization of the directory structure --- .gitignore | 1 + README.md | 1 + httpserverapp.sln | 20 -- httpserverapp.userprefs | 25 -- httpserverapp/Test.cpp | 81 ------- httpserverapp/Utils.h | 60 ----- httpserverapp/httpserverapp.cproj | 51 ---- httpserverapp/httpserverapp.md.pc | 5 - projects/qt-creator/httpserverapp.pro | 43 ++++ projects/qt-creator/httpserverapp.pro.user | 270 +++++++++++++++++++++ {httpserverapp => src}/FileIncoming.cpp | 12 +- {httpserverapp => src}/FileIncoming.h | 7 +- {httpserverapp => src}/Main.cpp | 20 +- {httpserverapp => src}/Main.h | 0 {httpserverapp => src}/RawData.h | 0 {httpserverapp => src}/ServerRequest.h | 0 {httpserverapp => src}/ServerResponse.h | 0 {httpserverapp => src}/Socket.cpp | 210 ++++++++++------ {httpserverapp => src}/Socket.h | 37 +-- {httpserverapp => src}/System.cpp | 80 +++++- {httpserverapp => src}/System.h | 52 ++-- src/Test.cpp | 125 ++++++++++ {httpserverapp => src}/Test.h | 0 {httpserverapp => src}/Utils.cpp | 139 ++++------- src/Utils.h | 83 +++++++ 25 files changed, 839 insertions(+), 483 deletions(-) create mode 100644 .gitignore delete mode 100644 httpserverapp.sln delete mode 100644 httpserverapp.userprefs delete mode 100644 httpserverapp/Test.cpp delete mode 100644 httpserverapp/Utils.h delete mode 100644 httpserverapp/httpserverapp.cproj delete mode 100644 httpserverapp/httpserverapp.md.pc create mode 100644 projects/qt-creator/httpserverapp.pro create mode 100644 projects/qt-creator/httpserverapp.pro.user rename {httpserverapp => src}/FileIncoming.cpp (54%) rename {httpserverapp => src}/FileIncoming.h (72%) rename {httpserverapp => src}/Main.cpp (77%) rename {httpserverapp => src}/Main.h (100%) rename {httpserverapp => src}/RawData.h (100%) rename {httpserverapp => src}/ServerRequest.h (100%) rename {httpserverapp => src}/ServerResponse.h (100%) rename {httpserverapp => src}/Socket.cpp (57%) rename {httpserverapp => src}/Socket.h (51%) rename {httpserverapp => src}/System.cpp (54%) rename {httpserverapp => src}/System.h (66%) create mode 100644 src/Test.cpp rename {httpserverapp => src}/Test.h (100%) rename {httpserverapp => src}/Utils.cpp (65%) create mode 100644 src/Utils.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build diff --git a/README.md b/README.md index c55f835..4ba55d7 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,5 @@ httpserverapp Sample http application on C++ For http server on C++ + See: https://github.com/awwit/httpserver diff --git a/httpserverapp.sln b/httpserverapp.sln deleted file mode 100644 index 467c721..0000000 --- a/httpserverapp.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{2857B73E-F847-4B02-9238-064979017E93}") = "httpserverapp", "httpserverapp\httpserverapp.cproj", "{4C15CBD7-D1C0-4869-AEE1-14CB41328514}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4C15CBD7-D1C0-4869-AEE1-14CB41328514}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C15CBD7-D1C0-4869-AEE1-14CB41328514}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C15CBD7-D1C0-4869-AEE1-14CB41328514}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C15CBD7-D1C0-4869-AEE1-14CB41328514}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - StartupItem = httpserverapp\httpserverapp.cproj - EndGlobalSection -EndGlobal diff --git a/httpserverapp.userprefs b/httpserverapp.userprefs deleted file mode 100644 index 2d6da20..0000000 --- a/httpserverapp.userprefs +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/httpserverapp/Test.cpp b/httpserverapp/Test.cpp deleted file mode 100644 index 21fa908..0000000 --- a/httpserverapp/Test.cpp +++ /dev/null @@ -1,81 +0,0 @@ - -#include "Test.h" - -bool test(HttpServer::ServerRequest &request, HttpServer::ServerResponse &response) -{ - const std::unordered_map &incoming_headers = request.headers; - const std::unordered_multimap &incoming_data = request.data; - - HttpServer::Socket &socket = response.socket; - std::map &headers_outgoing = response.headers; - - std::string s; - - for (auto h = incoming_headers.cbegin(); h != incoming_headers.cend(); ++h) - { - s += h->first + ": " + h->second + '\n'; - } - - s += '\n'; - - for (auto v = incoming_data.cbegin(); v != incoming_data.cend(); ++v) - { - s += v->first + ": " + v->second + '\n'; - } - - s += '\n'; - - for (auto &p : request.params) - { - s += p.first + ": " + p.second + '\n'; - } - - s = R"( - - - - - -
1 - 2 -
3 - 4 -
)"; - - headers_outgoing[""] = "HTTP/1.1 200 OK"; - headers_outgoing["Content-Type"] = "text/plain; charset=utf-8"; -// headers_outgoing["Access-Control-Allow-Origin"] = "*"; -// headers_outgoing["Content-Type"] = "text/html; charset=utf-8"; - headers_outgoing["Content-Length"] = std::to_string(s.length() ); - headers_outgoing["Connection"] = "keep-alive"; - headers_outgoing["Date"] = Utils::getDatetimeStringValue(); - - std::string headers; - - for (auto h = headers_outgoing.cbegin(); h != headers_outgoing.cend(); ++h) - { - if (h->first.length() ) - { - headers += h->first + ": "; - } - - headers += h->second + "\r\n"; - } - - headers += "\r\n"; - - headers_outgoing.clear(); - -// s = headers + s; - - std::chrono::milliseconds timeout(5000); - - socket.nonblock_send(headers, timeout); - - if ( (size_t)~0 == socket.nonblock_send(s, timeout) ) - { - socket.close(); - } - - return EXIT_SUCCESS; -} diff --git a/httpserverapp/Utils.h b/httpserverapp/Utils.h deleted file mode 100644 index ce42994..0000000 --- a/httpserverapp/Utils.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "RawData.h" -#include "FileIncoming.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Utils -{ - inline void tolower(std::string &str, const std::locale &loc) - { - for (auto &c : str) - { - c = std::tolower(c, loc); - } - } - - void trim(std::string &); - - inline std::string getUniqueName() - { - std::stringstream s; - s << std::hex << std::chrono::high_resolution_clock::now().time_since_epoch().count(); - return s.str(); - } - - char *stlStringToPChar(const std::string &); - - void stlMapToRawPairs(Utils::raw_pair *[], const std::map &); - void stlMultimapToRawPairs(Utils::raw_pair *[], const std::multimap &); - void stlUnorderedMapToRawPairs(Utils::raw_pair *[], const std::unordered_map &); - void stlUnorderedMultimapToRawPairs(Utils::raw_pair *[], const std::unordered_multimap &); - void filesIncomingToRawFilesInfo(Utils::raw_fileinfo *[], const std::unordered_multimap &); - void rawPairsToStlMap(std::map &, const Utils::raw_pair [], const size_t); - void rawPairsToStlMultimap(std::multimap &, const Utils::raw_pair [], const size_t); - void rawPairsToStlUnorderedMap(std::unordered_map &, const Utils::raw_pair [], const size_t); - void rawPairsToStlUnorderedMultimap(std::unordered_multimap &, const Utils::raw_pair [], const size_t); - void rawFilesInfoToFilesIncoming(std::unordered_multimap &, const Utils::raw_fileinfo [], const size_t); - void destroyRawPairs(Utils::raw_pair [], const size_t); - void destroyRawFilesInfo(Utils::raw_fileinfo [], const size_t); - - time_t stringTimeToTimestamp(const std::string &); - - std::string getDatetimeStringValue(const ::time_t tTime = ~0, const bool isGmtTime = false); - - size_t getNumberLength(const size_t number); - - bool parseCookies(const std::string &, std::unordered_multimap &); - - std::string urlEncode(const std::string &); - std::string urlDecode(const std::string &); -}; diff --git a/httpserverapp/httpserverapp.cproj b/httpserverapp/httpserverapp.cproj deleted file mode 100644 index a511002..0000000 --- a/httpserverapp/httpserverapp.cproj +++ /dev/null @@ -1,51 +0,0 @@ - - - - Debug - AnyCPU - {4C15CBD7-D1C0-4869-AEE1-14CB41328514} - - - - CPP - Bin - - - true - bin\Debug - httpserverapp - SharedLibrary - DEBUG MONODEVELOP POSIX - . - -std=c++11 - All - - - bin\Release - httpserverapp - SharedLibrary - 3 - MONODEVELOP POSIX - . - -std=c++11 - - - - - - - - - - - - - - - - - - - - - diff --git a/httpserverapp/httpserverapp.md.pc b/httpserverapp/httpserverapp.md.pc deleted file mode 100644 index d109504..0000000 --- a/httpserverapp/httpserverapp.md.pc +++ /dev/null @@ -1,5 +0,0 @@ -Name: httpserverapp -Description: -Version: 0.1 -Libs: -L"/media/projects/httpserverapp/httpserverapp/bin/Release" -lhttpserverapp -Cflags: -I"/media/projects/httpserverapp/httpserverapp" diff --git a/projects/qt-creator/httpserverapp.pro b/projects/qt-creator/httpserverapp.pro new file mode 100644 index 0000000..784e788 --- /dev/null +++ b/projects/qt-creator/httpserverapp.pro @@ -0,0 +1,43 @@ +TARGET = httpserverapp +TEMPLATE = lib + +CONFIG += c++11 +CONFIG -= app_bundle +CONFIG -= qt + +lessThan(QT_MAJOR_VERSION, 5) { + CONFIG += object_with_source + QMAKE_CXXFLAGS += -std=c++1y +} else { + CONFIG += object_parallel_to_source +} + +unix { + DEFINES += POSIX +} + +CONFIG(debug, debug|release):DEFINES += DEBUG + +SOURCES += \ + ../../src/FileIncoming.cpp \ + ../../src/Main.cpp \ + ../../src/Test.cpp \ + ../../src/Utils.cpp \ + ../../src/Socket.cpp \ + ../../src/System.cpp + +HEADERS += \ + ../../src/FileIncoming.h \ + ../../src/Main.h \ + ../../src/Test.h \ + ../../src/Utils.h \ + ../../src/RawData.h \ + ../../src/ServerRequest.h \ + ../../src/ServerResponse.h \ + ../../src/Socket.h \ + ../../src/System.h + +unix { + target.path = /usr/lib + INSTALLS += target +} diff --git a/projects/qt-creator/httpserverapp.pro.user b/projects/qt-creator/httpserverapp.pro.user new file mode 100644 index 0000000..186eb9c --- /dev/null +++ b/projects/qt-creator/httpserverapp.pro.user @@ -0,0 +1,270 @@ + + + + + + EnvironmentId + {1b4c0b3e-5aa0-412f-8f7e-3a13c2b330b9} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 1 + true + 0 + 8 + true + 1 + false + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {c77ee4a2-1c2a-4bac-9185-8378ec4ebf5d} + 1 + 0 + 0 + + ../../build/Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + false + false + + + true + Сборка + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Сборка + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Отладка + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + ../../build/Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + false + false + + + true + Сборка + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Сборка + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Выпуск + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 2 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Локальная установка + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + + false + %{buildDir} + Особая программа + + ProjectExplorer.CustomExecutableRunConfiguration + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/httpserverapp/FileIncoming.cpp b/src/FileIncoming.cpp similarity index 54% rename from httpserverapp/FileIncoming.cpp rename to src/FileIncoming.cpp index 4f20f95..1526735 100644 --- a/httpserverapp/FileIncoming.cpp +++ b/src/FileIncoming.cpp @@ -11,23 +11,23 @@ namespace HttpServer } - FileIncoming::FileIncoming(const FileIncoming &file) - : file_name(file.file_name), file_type(file.file_type), file_size(file.file_size) + FileIncoming::FileIncoming(const FileIncoming &obj) + : file_name(obj.file_name), file_type(obj.file_type), file_size(obj.file_size) { } - FileIncoming::FileIncoming(FileIncoming &&file) - : file_name(std::move(file.file_name) ), file_type(std::move(file.file_type) ), file_size(file.file_size) + FileIncoming::FileIncoming(FileIncoming &&obj) + : file_name(std::move(obj.file_name) ), file_type(std::move(obj.file_type) ), file_size(obj.file_size) { - file.file_size = 0; + obj.file_size = 0; } bool FileIncoming::isExists() const { std::ifstream file(file_name, std::ifstream::binary); - bool is_exists = file.good(); + const bool is_exists = file.good(); file.close(); diff --git a/httpserverapp/FileIncoming.h b/src/FileIncoming.h similarity index 72% rename from httpserverapp/FileIncoming.h rename to src/FileIncoming.h index 75df66c..6c6fa97 100644 --- a/httpserverapp/FileIncoming.h +++ b/src/FileIncoming.h @@ -15,9 +15,10 @@ namespace HttpServer FileIncoming() = delete; public: - FileIncoming(const std::string &, const std::string &, const size_t); - FileIncoming(const FileIncoming &); - FileIncoming(FileIncoming &&); + FileIncoming(const std::string &fileName, const std::string &fileType, const size_t fileSize); + FileIncoming(const FileIncoming &obj); + FileIncoming(FileIncoming &&obj); + ~FileIncoming() = default; inline std::string getName() const diff --git a/httpserverapp/Main.cpp b/src/Main.cpp similarity index 77% rename from httpserverapp/Main.cpp rename to src/Main.cpp index 819645a..91d19a3 100644 --- a/httpserverapp/Main.cpp +++ b/src/Main.cpp @@ -3,8 +3,6 @@ #include "Test.h" -#include - DLLEXPORT bool application_init() { return true; @@ -18,14 +16,14 @@ DLLEXPORT int application_call(HttpServer::server_request *request, HttpServer:: std::unordered_multimap files; std::unordered_multimap cookies; - Utils::rawPairsToStlUnorderedMultimap(params, request->params, request->params_count); - Utils::rawPairsToStlUnorderedMap(headers, request->headers, request->headers_count); - Utils::rawPairsToStlUnorderedMultimap(data, request->data, request->data_count); + Utils::rawPairsToStl(params, request->params, request->params_count); + Utils::rawPairsToStl(headers, request->headers, request->headers_count); + Utils::rawPairsToStl(data, request->data, request->data_count); Utils::rawFilesInfoToFilesIncoming(files, request->files, request->files_count); auto it_cookie = headers.find("Cookie"); - if (headers.end() != it_cookie) + if (headers.cend() != it_cookie) { Utils::parseCookies(it_cookie->second, cookies); } @@ -47,13 +45,11 @@ DLLEXPORT int application_call(HttpServer::server_request *request, HttpServer:: std::map() }; - std::string absolute_path = proc_request.document_root + proc_request.uri_reference; + const std::string absolute_path = proc_request.document_root + proc_request.uri_reference; int result = EXIT_SUCCESS; - std::ifstream file(absolute_path, std::ifstream::binary); - - if (file) + if (System::isFileExists(absolute_path) ) { auto it_connection = proc_request.headers.find("Connection"); @@ -69,12 +65,10 @@ DLLEXPORT int application_call(HttpServer::server_request *request, HttpServer:: result = test(proc_request, proc_response); } - file.close(); - if (proc_response.headers.size() ) { Utils::raw_pair *headers; - Utils::stlMapToRawPairs(&headers, proc_response.headers); + Utils::stlToRawPairs(&headers, proc_response.headers); response->headers_count = proc_response.headers.size(); response->headers = headers; diff --git a/httpserverapp/Main.h b/src/Main.h similarity index 100% rename from httpserverapp/Main.h rename to src/Main.h diff --git a/httpserverapp/RawData.h b/src/RawData.h similarity index 100% rename from httpserverapp/RawData.h rename to src/RawData.h diff --git a/httpserverapp/ServerRequest.h b/src/ServerRequest.h similarity index 100% rename from httpserverapp/ServerRequest.h rename to src/ServerRequest.h diff --git a/httpserverapp/ServerResponse.h b/src/ServerResponse.h similarity index 100% rename from httpserverapp/ServerResponse.h rename to src/ServerResponse.h diff --git a/httpserverapp/Socket.cpp b/src/Socket.cpp similarity index 57% rename from httpserverapp/Socket.cpp rename to src/Socket.cpp index f81d03e..8d4eff0 100644 --- a/httpserverapp/Socket.cpp +++ b/src/Socket.cpp @@ -3,25 +3,25 @@ namespace HttpServer { - int Socket::Startup() + bool Socket::Startup() { #ifdef WIN32 unsigned short version = MAKEWORD(2, 2); ::WSADATA wsaData = {0}; - return ::WSAStartup(version, &wsaData); + return 0 == ::WSAStartup(version, &wsaData); #elif POSIX - return 0; + return true; #else #error "Undefine platform" #endif } - int Socket::Cleanup() + bool Socket::Cleanup() { #ifdef WIN32 - return ::WSACleanup(); + return 0 == ::WSACleanup(); #elif POSIX - return 0; + return true; #else #error "Undefine platform" #endif @@ -32,7 +32,7 @@ namespace HttpServer } - Socket::Socket(const System::native_socket_type handle) : socket_handle(handle) + Socket::Socket(const System::native_socket_type fd) : socket_handle(fd) { } @@ -42,9 +42,9 @@ namespace HttpServer } - Socket::Socket(Socket &&that) : socket_handle(that.socket_handle) + Socket::Socket(Socket &&obj) : socket_handle(obj.socket_handle) { - that.socket_handle = ~0; + obj.socket_handle = ~0; } System::native_socket_type Socket::open() @@ -61,9 +61,9 @@ namespace HttpServer if (is_open() ) { #ifdef WIN32 - int result = ::closesocket(socket_handle); + const int result = ::closesocket(socket_handle); #elif POSIX - int result = ::close(socket_handle); + const int result = ::close(socket_handle); #else #error "Undefine platform" #endif @@ -81,12 +81,14 @@ namespace HttpServer int Socket::bind(const int port) const { - ::sockaddr_in sock_addr = {0}; - sock_addr.sin_family = AF_INET; - sock_addr.sin_port = htons(port); - sock_addr.sin_addr.s_addr = ::htonl(INADDR_ANY); - - return ::bind(socket_handle, reinterpret_cast(&sock_addr), sizeof(sockaddr_in) ); + const ::sockaddr_in sock_addr = { + AF_INET, + htons(port), + ::htonl(INADDR_ANY), + 0 + }; + + return ::bind(socket_handle, reinterpret_cast(&sock_addr), sizeof(sockaddr_in) ); } int Socket::listen() const @@ -110,22 +112,24 @@ namespace HttpServer { System::native_socket_type client_socket = ~0; #ifdef WIN32 - WSAPOLLFD event = {0}; - - event.fd = socket_handle; - event.events = POLLRDNORM; + WSAPOLLFD event = { + socket_handle, + POLLRDNORM, + 0 + }; - if (1 == ::WSAPoll(&event, 1, ~0) && event.revents | POLLRDNORM) + if (1 == ::WSAPoll(&event, 1, ~0) && event.revents & POLLRDNORM) { client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #elif POSIX - struct ::pollfd event = {0}; - - event.fd = socket_handle; - event.events = POLLIN; + struct ::pollfd event = { + socket_handle, + POLLIN, + 0 + }; - if (1 == ::poll(&event, 1, ~0) && event.revents | POLLIN) + if (1 == ::poll(&event, 1, ~0) && event.revents & POLLIN) { client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); } @@ -135,26 +139,28 @@ namespace HttpServer return Socket(client_socket); } - Socket Socket::nonblock_accept(const std::chrono::milliseconds &timeWait) const + Socket Socket::nonblock_accept(const std::chrono::milliseconds &timeout) const { System::native_socket_type client_socket = ~0; #ifdef WIN32 - WSAPOLLFD event = {0}; + WSAPOLLFD event = { + socket_handle, + POLLRDNORM, + 0 + }; - event.fd = socket_handle; - event.events = POLLRDNORM; - - if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents | POLLRDNORM) + if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLRDNORM) { client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #elif POSIX - struct ::pollfd event = {0}; - - event.fd = socket_handle; - event.events = POLLIN; + struct ::pollfd event = { + socket_handle, + POLLIN, + 0 + }; - if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents | POLLIN) + if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLIN) { client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); } @@ -204,6 +210,19 @@ namespace HttpServer #endif }*/ + bool Socket::tcp_nodelay(const bool nodelay) const + { + #ifdef WIN32 + int flags = nodelay ? 1 : 0; + return 0 == setsockopt(socket_handle, IPPROTO_TCP, TCP_NODELAY, (char *)&flags, sizeof(flags) ); + #elif POSIX + int flags = nodelay ? 1 : 0; + return 0 == setsockopt(socket_handle, IPPROTO_TCP, TCP_NODELAY, (char *)&flags, sizeof(flags) ); + #else + #error "Undefine platform" + #endif + } + size_t Socket::recv(std::vector &buf) const { #ifdef WIN32 @@ -215,26 +234,28 @@ namespace HttpServer #endif } - size_t Socket::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeWait) const + size_t Socket::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const { size_t recv_len = ~0; #ifdef WIN32 - WSAPOLLFD event = {0}; - - event.fd = socket_handle; - event.events = POLLRDNORM; - - if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents | POLLRDNORM) - { + WSAPOLLFD event = { + socket_handle, + POLLRDNORM, + 0 + }; + + if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLRDNORM) + { recv_len = ::recv(socket_handle, buf.data(), buf.size(), 0); } #elif POSIX - struct ::pollfd event = {0}; - - event.fd = socket_handle; - event.events = POLLIN; + struct ::pollfd event = { + socket_handle, + POLLIN, + 0 + }; - if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents | POLLIN) + if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLIN) { recv_len = ::recv(socket_handle, buf.data(), buf.size(), MSG_NOSIGNAL); } @@ -266,26 +287,28 @@ namespace HttpServer #endif } - size_t Socket::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeWait) const + size_t Socket::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const { size_t send_len = ~0; #ifdef WIN32 - WSAPOLLFD event = {0}; + WSAPOLLFD event = { + socket_handle, + POLLWRNORM, + 0 + }; - event.fd = socket_handle; - event.events = POLLWRNORM; - - if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents | POLLWRNORM) + if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLWRNORM) { send_len = ::send(socket_handle, buf.data(), buf.length(), 0); } #elif POSIX - struct ::pollfd event = {0}; - - event.fd = socket_handle; - event.events = POLLOUT; + struct ::pollfd event = { + socket_handle, + POLLOUT, + 0 + }; - if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents | POLLOUT) + if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLOUT) { send_len = ::send(socket_handle, buf.data(), buf.length(), MSG_NOSIGNAL); } @@ -295,28 +318,30 @@ namespace HttpServer return send_len; } - size_t Socket::nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeWait) const + size_t Socket::nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const { size_t send_len = ~0; #ifdef WIN32 - WSAPOLLFD event = {0}; + WSAPOLLFD event = { + socket_handle, + POLLWRNORM, + 0 + }; - event.fd = socket_handle; - event.events = POLLWRNORM; - - if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents | POLLWRNORM) + if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLWRNORM) { send_len = ::send(socket_handle, buf.data(), length, 0); } #elif POSIX - struct ::pollfd event = {0}; - - event.fd = socket_handle; - event.events = POLLOUT; + struct ::pollfd event = { + socket_handle, + POLLOUT, + 0 + }; - if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents | POLLOUT) + if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLOUT) { - send_len = ::send(socket_handle, buf.data(), length, MSG_WAITALL | MSG_NOSIGNAL); + send_len = ::send(socket_handle, buf.data(), length, MSG_NOSIGNAL); } #else #error "Undefine platform" @@ -324,9 +349,42 @@ namespace HttpServer return send_len; } - Socket &Socket::operator=(const Socket s) + void Socket::nonblock_send_sync() const + { + #ifdef WIN32 + WSAPOLLFD event = { + socket_handle, + POLLWRNORM, + 0 + }; + + ::WSAPoll(&event, 1, ~0); + #elif POSIX + struct ::pollfd event = { + socket_handle, + POLLOUT, + 0 + }; + + ::poll(&event, 1, ~0); + #else + #error "Undefine platform" + #endif + } + + Socket &Socket::operator=(const Socket &obj) { - socket_handle = s.socket_handle; + socket_handle = obj.socket_handle; return *this; } + + bool Socket::operator ==(const Socket &obj) const + { + return this->socket_handle == obj.socket_handle; + } + + bool Socket::operator !=(const Socket &obj) const + { + return this->socket_handle != obj.socket_handle; + } }; \ No newline at end of file diff --git a/httpserverapp/Socket.h b/src/Socket.h similarity index 51% rename from httpserverapp/Socket.h rename to src/Socket.h index 91b15ec..db2c9c3 100644 --- a/httpserverapp/Socket.h +++ b/src/Socket.h @@ -10,6 +10,7 @@ #include #include #include + #include #include #include #else @@ -33,14 +34,14 @@ namespace HttpServer System::native_socket_type socket_handle; public: - int static Startup(); - int static Cleanup(); + bool static Startup(); + bool static Cleanup(); public: Socket(); - Socket(const System::native_socket_type); - Socket(const Socket &); - Socket(Socket &&); + Socket(const System::native_socket_type fd); + Socket(const Socket &obj); + Socket(Socket &&obj); ~Socket() = default; @@ -58,32 +59,38 @@ namespace HttpServer #endif } - int bind(const int) const; + int bind(const int port) const; int listen() const; Socket accept() const; Socket nonblock_accept() const; - Socket nonblock_accept(const std::chrono::milliseconds &) const; + Socket nonblock_accept(const std::chrono::milliseconds &timeout) const; int shutdown() const; - bool nonblock(const bool = true) const; + bool nonblock(const bool isNonBlock = true) const; // bool is_nonblock() const; + bool tcp_nodelay(const bool nodelay = true) const; - size_t recv(std::vector &) const; - size_t nonblock_recv(std::vector &, const std::chrono::milliseconds &) const; + size_t recv(std::vector &buf) const; + size_t nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const; - size_t send(const std::string &) const; - size_t send(const std::vector &, const size_t) const; + size_t send(const std::string &buf) const; + size_t send(const std::vector &buf, const size_t length) const; - size_t nonblock_send(const std::string &, const std::chrono::milliseconds &) const; - size_t nonblock_send(const std::vector &, const size_t, const std::chrono::milliseconds &) const; + size_t nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const; + size_t nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const; + + void nonblock_send_sync() const; inline System::native_socket_type get_handle() const { return socket_handle; } - Socket &operator =(const Socket); + Socket &operator =(const Socket &obj); + + bool operator ==(const Socket &obj) const; + bool operator !=(const Socket &obj) const; }; }; \ No newline at end of file diff --git a/httpserverapp/System.cpp b/src/System.cpp similarity index 54% rename from httpserverapp/System.cpp rename to src/System.cpp index c5f6218..8faf1b5 100644 --- a/httpserverapp/System.cpp +++ b/src/System.cpp @@ -1,6 +1,12 @@  #include "System.h" +#include + +#ifdef WIN32 + char myWndClassName[] = "WndClassNameConstant"; +#endif + namespace System { #ifdef WIN32 @@ -10,7 +16,7 @@ namespace System ::HWND hWnd; }; - BOOL WINAPI EnumProc(::HWND hWnd, ::LPARAM lParam) + ::BOOL WINAPI EnumProc(::HWND hWnd, ::LPARAM lParam) { EnumData &ed = *reinterpret_cast(lParam); @@ -18,11 +24,18 @@ namespace System ::GetWindowThreadProcessId(hWnd, &process_id); - if (process_id == ed.process_id && GetConsoleWindow() != hWnd) + if (process_id == ed.process_id && ::GetConsoleWindow() != hWnd) { - ed.hWnd = hWnd; + std::array class_name; - return false; + ::GetClassName(hWnd, class_name.data(), class_name.size() - 1); + + if (0 == ::strcmp(class_name.data(), myWndClassName) ) + { + ed.hWnd = hWnd; + + return false; + } } return true; @@ -34,7 +47,7 @@ namespace System #ifdef WIN32 EnumData ed = {pid, 0}; - ::EnumWindows(EnumProc, reinterpret_cast(&ed) ); + ::EnumWindows(EnumProc, reinterpret_cast<::LPARAM>(&ed) ); if (0 == ed.hWnd) { @@ -49,6 +62,60 @@ namespace System #endif } + std::string getTempDir() + { + #ifdef WIN32 + std::array buf; + + const size_t len = ::GetTempPath(buf.size(), buf.data() ); + + return std::string(buf.cbegin(), buf.cbegin() + len); + #elif POSIX + const char *buf = ::getenv("TMPDIR"); + + if (nullptr == buf) + { + return std::string("/tmp/"); + } + + std::string str(buf); + + if ('/' != str.back() ) + { + str.push_back('/'); + } + + return str; + #else + #error "Undefine platform" + #endif + } + + bool isFileExists(const std::string &fileName) + { + #ifdef WIN32 + const ::DWORD attrib = ::GetFileAttributes(fileName.c_str() ); + + if (INVALID_FILE_ATTRIBUTES == attrib) + { + return false; + } + + return FILE_ATTRIBUTE_DIRECTORY != (attrib & FILE_ATTRIBUTE_DIRECTORY); + #elif POSIX + struct ::stat attrib; + + if (-1 == ::stat(fileName.c_str(), &attrib) ) + { + return false; + } + + return S_ISREG(attrib.st_mode); + #else + #error "Undefine platform" + #endif + } + bool getFileSizeAndTimeGmt(const std::string &filePath, size_t *fileSize, time_t *fileTime) { #ifdef WIN32 @@ -61,6 +128,7 @@ namespace System if (false == ::GetFileSizeEx(hFile, reinterpret_cast<::PLARGE_INTEGER>(fileSize) ) ) { + ::CloseHandle(hFile); return false; } @@ -88,7 +156,7 @@ namespace System stUtc.wYear - 1900, 0, 0, - 0 + -1 }; *fileTime = ::mktime(&tm_time); diff --git a/httpserverapp/System.h b/src/System.h similarity index 66% rename from httpserverapp/System.h rename to src/System.h index 29ee42b..ef6445e 100644 --- a/httpserverapp/System.h +++ b/src/System.h @@ -2,6 +2,25 @@ #ifdef WIN32 #include + char myWndClassName[]; + + #ifdef SIGTERM + #undef SIGTERM + #define SIGTERM (WM_USER + 15) + #endif + + #ifdef SIGINT + #undef SIGINT + #define SIGINT (WM_USER + 2) + #endif + + #ifndef SIGUSR1 + #define SIGUSR1 (WM_USER + 10) + #endif + + #ifndef SIGUSR2 + #define SIGUSR2 (WM_USER + 12) + #endif #elif POSIX #include #include @@ -11,10 +30,7 @@ #error "Undefine platform" #endif -#ifndef SIGUSR1 - #define SIGUSR1 10 -#endif - +#include #include #include #include @@ -37,19 +53,6 @@ namespace System #error "Undefine platform" #endif - inline size_t getProcessorsCount() - { - #ifdef WIN32 - ::SYSTEM_INFO si = {0}; - ::GetSystemInfo(&si); - return si.dwNumberOfProcessors; - #elif POSIX - return ::get_nprocs(); - #else - #error "Undefine platform" - #endif - } - inline native_processid_type getProcessId() { #ifdef WIN32 @@ -74,16 +77,9 @@ namespace System #endif } - inline std::string getTempDir() - { - #ifdef WIN32 - return std::string("C:/Temp/"); // FIXME: Windows temp dir - #elif POSIX - return std::string("/tmp/"); - #else - #error "Undefine platform" - #endif - } + std::string getTempDir(); + + bool isFileExists(const std::string &fileName); - bool getFileSizeAndTimeGmt(const std::string &, size_t *, time_t *); + bool getFileSizeAndTimeGmt(const std::string &filePath, size_t *fileSize, time_t *fileTime); }; \ No newline at end of file diff --git a/src/Test.cpp b/src/Test.cpp new file mode 100644 index 0000000..04127ed --- /dev/null +++ b/src/Test.cpp @@ -0,0 +1,125 @@ + +#include "Test.h" + +bool test(HttpServer::ServerRequest &request, HttpServer::ServerResponse &response) +{ + // Output incoming headers + + std::string s = R"( + + + + + + +)"; + + for (auto const &pair : request.headers) + { + s += R"( + + + +)"; + } + + // Output incoming data + + s += R"( + + + + + + +)"; + + for (auto const &pair : request.data) + { + s += R"( + + + +)"; + } + + // Output incoming url parameters + + s += R"( + + + + + + +)"; + + for (auto const &pair : request.params) + { + s += R"( + + + +)"; + } + + // Output info about incoming files + + s += R"( + + + + + + +)"; + + for (auto const &pair : request.files) + { + const HttpServer::FileIncoming &file = pair.second; + + s += R"( + + + +)"; + } + + s += R"( +
Incoming headers
)" + pair.first + R"()" + pair.second + R"(
Incoming data
)" + pair.first + R"()" + pair.second + R"(
Incoming url parameters
)" + pair.first + R"()" + pair.second + R"(
Incoming files
)" + file.getName() + R"()" + std::to_string(file.getSize() ) + R"(
)"; + + HttpServer::Socket &socket = response.socket; + std::map &headers_outgoing = response.headers; + + // Set outgoing headers + + headers_outgoing[""] = "HTTP/1.1 200 OK"; + headers_outgoing["Content-Type"] = "text/html; charset=utf-8"; + headers_outgoing["Accept-Ranges"] = "bytes"; + headers_outgoing["Content-Length"] = std::to_string(s.length() ); + headers_outgoing["Connection"] = "Keep-Alive"; + headers_outgoing["Date"] = Utils::getDatetimeAsString(); + + std::string headers; + + for (auto const &h : headers_outgoing) + { + if (h.first.length() ) + { + headers += h.first + ": "; + } + + headers += h.second + "\r\n"; + } + + headers += "\r\n"; + + // Send headers and page + + std::chrono::milliseconds timeout(5000); + + socket.nonblock_send(headers, timeout); + socket.nonblock_send(s, timeout); + + return EXIT_SUCCESS; +} diff --git a/httpserverapp/Test.h b/src/Test.h similarity index 100% rename from httpserverapp/Test.h rename to src/Test.h diff --git a/httpserverapp/Utils.cpp b/src/Utils.cpp similarity index 65% rename from httpserverapp/Utils.cpp rename to src/Utils.cpp index e75c023..406f810 100644 --- a/httpserverapp/Utils.cpp +++ b/src/Utils.cpp @@ -1,6 +1,7 @@  #include "Utils.h" +#include #include #include @@ -8,7 +9,7 @@ namespace Utils { void trim(std::string &str) { - size_t last = str.find_last_not_of(" \t\n\v\f\r"); + const size_t last = str.find_last_not_of(" \t\n\v\f\r"); if (std::string::npos == last) { @@ -18,9 +19,33 @@ namespace Utils str.assign(str.cbegin() + str.find_first_not_of(" \t\n\v\f\r"), str.cbegin() + last + 1); } + std::vector explode(const std::string &str, const char sep) + { + std::vector values; + + for (size_t pos = 0; std::string::npos != pos;) + { + size_t delimiter = str.find(sep, pos); + + std::string value = str.substr(pos, delimiter); + trim(value); + + values.emplace_back(std::move(value) ); + + pos = delimiter; + + if (std::string::npos != pos) + { + ++pos; + } + } + + return values; + } + char *stlStringToPChar(const std::string &str) { - size_t length = str.length(); + const size_t length = str.length(); char *s = nullptr; if (length) @@ -39,60 +64,6 @@ namespace Utils return s; } - void stlMapToRawPairs(Utils::raw_pair *raw[], const std::map &map) - { - if (raw && map.size() ) - { - raw_pair *arr = new raw_pair[map.size()]; - - *raw = arr; - - size_t i = 0; - - for (auto it = map.cbegin(); map.cend() != it; ++it, ++i) - { - arr[i].key = stlStringToPChar(it->first); - arr[i].value = stlStringToPChar(it->second); - } - } - } - - void stlUnorderedMapToRawPairs(Utils::raw_pair *raw[], const std::unordered_map &map) - { - if (raw && map.size() ) - { - raw_pair *arr = new raw_pair[map.size()]; - - *raw = arr; - - size_t i = 0; - - for (auto it = map.cbegin(); map.cend() != it; ++it, ++i) - { - arr[i].key = stlStringToPChar(it->first); - arr[i].value = stlStringToPChar(it->second); - } - } - } - - void stlUnorderedMultimapToRawPairs(Utils::raw_pair *raw[], const std::unordered_multimap &map) - { - if (raw && map.size() ) - { - raw_pair *arr = new raw_pair[map.size()]; - - *raw = arr; - - size_t i = 0; - - for (auto it = map.cbegin(); map.cend() != it; ++it, ++i) - { - arr[i].key = stlStringToPChar(it->first); - arr[i].value = stlStringToPChar(it->second); - } - } - } - void filesIncomingToRawFilesInfo(Utils::raw_fileinfo *raw[], const std::unordered_multimap &map) { if (raw && map.size() ) @@ -116,30 +87,6 @@ namespace Utils } } - void rawPairsToStlMap(std::map &map, const Utils::raw_pair raw[], const size_t count) - { - for (size_t i = 0; i < count; ++i) - { - map.emplace(raw[i].key ? raw[i].key : "", raw[i].value ? raw[i].value : ""); - } - } - - void rawPairsToStlUnorderedMap(std::unordered_map &map, const Utils::raw_pair raw[], const size_t count) - { - for (size_t i = 0; i < count; ++i) - { - map.emplace(raw[i].key ? raw[i].key : "", raw[i].value ? raw[i].value : ""); - } - } - - void rawPairsToStlUnorderedMultimap(std::unordered_multimap &map, const Utils::raw_pair raw[], const size_t count) - { - for (size_t i = 0; i < count; ++i) - { - map.emplace(raw[i].key ? raw[i].key : "", raw[i].value ? raw[i].value : ""); - } - } - void rawFilesInfoToFilesIncoming(std::unordered_multimap &map, const Utils::raw_fileinfo raw[], const size_t count) { for (size_t i = 0; i < count; ++i) @@ -191,37 +138,41 @@ namespace Utils {"Jan", 0}, {"Feb", 1}, {"Mar", 2}, {"Apr", 3}, {"May", 4}, {"Jun", 5}, {"Jul", 6}, {"Aug", 7}, {"Sep", 8}, {"Oct", 9}, {"Nov", 10}, {"Dec", 11} }; - const size_t str_mon_length = 32; - char *s_mon = new char[str_mon_length]; - ::memset(s_mon, 0, str_mon_length); + if (strTime.length() > 64) + { + return (time_t) ~0; + } + + const size_t str_mon_length = 64; + std::vector s_mon(str_mon_length); - struct ::tm tc = {0}; + struct ::tm tc = {0}; // Parse RFC 822 #ifdef WIN32 - if (std::numeric_limits::max() != ::sscanf_s(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon, str_mon_length, &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) ) + if (~0 != ::sscanf_s(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon.data(), s_mon.size(), &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) ) #else - if (std::numeric_limits::max() != ::sscanf(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon, &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) ) + if (~0 != ::sscanf(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon.data(), &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) ) #endif { tc.tm_year -= 1900; - auto it_mon = map_months.find(s_mon); + auto it_mon = map_months.find(s_mon.data() ); - if (map_months.end() != it_mon) + if (map_months.cend() != it_mon) { tc.tm_mon = it_mon->second; } } - delete[] s_mon; + tc.tm_isdst = -1; return ::mktime(&tc); } - std::string getDatetimeStringValue(const ::time_t tTime, const bool isGmtTime) + std::string getDatetimeAsString(const ::time_t tTime, const bool isGmtTime) { - char buf[64]; + std::array buf; ::time_t cur_time = tTime; @@ -243,15 +194,15 @@ namespace Utils } // RFC 822 - ::strftime(buf, 64, "%a, %d %b %Y %H:%M:%S GMT", &stm); + ::strftime(buf.data(), buf.size(), "%a, %d %b %Y %H:%M:%S GMT", &stm); #else struct ::tm *ptm = isGmtTime ? localtime(&cur_time) : gmtime(&cur_time); // RFC 822 - ::strftime(buf, 64, "%a, %d %b %G %H:%M:%S GMT", ptm); + ::strftime(buf.data(), buf.size(), "%a, %d %b %G %H:%M:%S GMT", ptm); #endif - return std::string(buf); + return std::string(buf.data() ); } size_t getNumberLength(const size_t number) diff --git a/src/Utils.h b/src/Utils.h new file mode 100644 index 0000000..a3fab0a --- /dev/null +++ b/src/Utils.h @@ -0,0 +1,83 @@ +#pragma once + +#include "RawData.h" +#include "FileIncoming.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Utils +{ + inline void tolower(std::string &str, const std::locale &loc) + { + for (auto &c : str) + { + c = std::tolower(c, loc); + } + } + + void trim(std::string &str); + + std::vector explode(const std::string &str, const char sep); + + inline std::string getUniqueName() + { + std::stringstream s; + s << std::hex << std::chrono::high_resolution_clock::now().time_since_epoch().count(); + return s.str(); + } + + char *stlStringToPChar(const std::string &str); + + template + void stlToRawPairs(Utils::raw_pair *raw[], const T &stl) + { + if (raw && stl.size() ) + { + raw_pair *arr = new raw_pair[stl.size()]; + + *raw = arr; + + size_t i = 0; + + for (auto it = stl.cbegin(); stl.cend() != it; ++it, ++i) + { + arr[i].key = stlStringToPChar(it->first); + arr[i].value = stlStringToPChar(it->second); + } + } + } + + template + void rawPairsToStl(T &stl, const Utils::raw_pair raw[], const size_t count) + { + for (size_t i = 0; i < count; ++i) + { + stl.emplace(raw[i].key ? raw[i].key : "", raw[i].value ? raw[i].value : ""); + } + } + + void filesIncomingToRawFilesInfo(Utils::raw_fileinfo *raw[], const std::unordered_multimap &map); + void rawFilesInfoToFilesIncoming(std::unordered_multimap &map, const Utils::raw_fileinfo raw[], const size_t count); + + void destroyRawPairs(Utils::raw_pair raw[], const size_t count); + void destroyRawFilesInfo(Utils::raw_fileinfo raw[], const size_t count); + + time_t stringTimeToTimestamp(const std::string &strTime); + + std::string getDatetimeAsString(const ::time_t tTime = ~0, const bool isGmtTime = false); + + size_t getNumberLength(const size_t number); + + bool parseCookies(const std::string &cookieHeader, std::unordered_multimap &cookies); + + std::string urlEncode(const std::string &str); + std::string urlDecode(const std::string &str); +}; \ No newline at end of file From d1570fae5d4b6fae1024fc4b6e26735e628699a9 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Mon, 16 Nov 2015 15:01:51 +0300 Subject: [PATCH 03/31] Added Visual Studio project Successful build project in Visual Studio --- projects/msvs/httpserverapp.sln | 28 ++++ projects/msvs/httpserverapp.v12.suo | Bin 0 -> 147456 bytes projects/msvs/httpserverapp.vcxproj | 175 ++++++++++++++++++++ projects/msvs/httpserverapp.vcxproj.filters | 66 ++++++++ projects/msvs/httpserverapp.vcxproj.user | 4 + 5 files changed, 273 insertions(+) create mode 100644 projects/msvs/httpserverapp.sln create mode 100644 projects/msvs/httpserverapp.v12.suo create mode 100644 projects/msvs/httpserverapp.vcxproj create mode 100644 projects/msvs/httpserverapp.vcxproj.filters create mode 100644 projects/msvs/httpserverapp.vcxproj.user diff --git a/projects/msvs/httpserverapp.sln b/projects/msvs/httpserverapp.sln new file mode 100644 index 0000000..07921f1 --- /dev/null +++ b/projects/msvs/httpserverapp.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.40629.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "httpserverapp", "httpserverapp.vcxproj", "{D1565609-DDDE-4521-8AD9-0D1AD7D18525}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D1565609-DDDE-4521-8AD9-0D1AD7D18525}.Debug|Win32.ActiveCfg = Debug|x64 + {D1565609-DDDE-4521-8AD9-0D1AD7D18525}.Debug|Win32.Build.0 = Debug|x64 + {D1565609-DDDE-4521-8AD9-0D1AD7D18525}.Debug|x64.ActiveCfg = Debug|x64 + {D1565609-DDDE-4521-8AD9-0D1AD7D18525}.Debug|x64.Build.0 = Debug|x64 + {D1565609-DDDE-4521-8AD9-0D1AD7D18525}.Release|Win32.ActiveCfg = Release|Win32 + {D1565609-DDDE-4521-8AD9-0D1AD7D18525}.Release|Win32.Build.0 = Release|Win32 + {D1565609-DDDE-4521-8AD9-0D1AD7D18525}.Release|x64.ActiveCfg = Release|x64 + {D1565609-DDDE-4521-8AD9-0D1AD7D18525}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/msvs/httpserverapp.v12.suo b/projects/msvs/httpserverapp.v12.suo new file mode 100644 index 0000000000000000000000000000000000000000..3949d5dd312ef3d13671c915e2756c606c809631 GIT binary patch literal 147456 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 + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + {D1565609-DDDE-4521-8AD9-0D1AD7D18525} + Win32Proj + httpserverapp + + + + DynamicLibrary + true + v120 + MultiByte + + + DynamicLibrary + true + v120 + MultiByte + + + DynamicLibrary + false + v120 + true + MultiByte + + + DynamicLibrary + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + + + + true + ..\..\build\$(Platform)\$(Configuration)\ + ..\..\build\$(Platform)\$(Configuration)\ + + + true + ..\..\build\$(Platform)\$(Configuration)\ + ..\..\build\$(Platform)\$(Configuration)\ + + + false + ..\..\build\$(Platform)\$(Configuration)\ + ..\..\build\$(Platform)\$(Configuration)\ + + + false + ..\..\build\$(Platform)\$(Configuration)\ + ..\..\build\$(Platform)\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPSERVERAPP_EXPORTS;%(PreprocessorDefinitions) + $(IntDir)asm\ + $(IntDir)obj\ + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPSERVERAPP_EXPORTS;%(PreprocessorDefinitions) + $(IntDir)asm\ + $(IntDir)obj\ + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + $(IntDir)asm\ + $(IntDir)obj\ + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + $(IntDir)asm\ + $(IntDir)obj\ + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/projects/msvs/httpserverapp.vcxproj.filters b/projects/msvs/httpserverapp.vcxproj.filters new file mode 100644 index 0000000..e85b8eb --- /dev/null +++ b/projects/msvs/httpserverapp.vcxproj.filters @@ -0,0 +1,66 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/projects/msvs/httpserverapp.vcxproj.user b/projects/msvs/httpserverapp.vcxproj.user new file mode 100644 index 0000000..ef5ff2a --- /dev/null +++ b/projects/msvs/httpserverapp.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From af8f0881ed81dfef95a117b122a8495674122565 Mon Sep 17 00:00:00 2001 From: awwit Date: Thu, 17 Dec 2015 19:44:55 +0300 Subject: [PATCH 04/31] Added function for convert bin-data to hex-string (and inversely) into Utils Changed realization of function Utils::getUniqueName() --- projects/qt-creator/httpserverapp.pro.user | 2 +- src/Utils.cpp | 122 ++++++++++++++++++++- src/Utils.h | 15 ++- 3 files changed, 131 insertions(+), 8 deletions(-) diff --git a/projects/qt-creator/httpserverapp.pro.user b/projects/qt-creator/httpserverapp.pro.user index 186eb9c..4af6cd7 100644 --- a/projects/qt-creator/httpserverapp.pro.user +++ b/projects/qt-creator/httpserverapp.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/src/Utils.cpp b/src/Utils.cpp index 406f810..ac34929 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -43,6 +43,126 @@ namespace Utils return values; } + std::string encodeHtmlSymbols(const std::string &str) + { + std::string buf; + buf.reserve(str.length() ); + + for (size_t pos = 0; pos < str.length(); ++pos) + { + switch (str[pos]) + { + case '&': buf.append("&"); break; + case '\"': buf.append("""); break; + case '\'': buf.append("'"); break; + case '<': buf.append("<"); break; + case '>': buf.append(">"); break; + default: buf.push_back(str[pos]); break; + } + } + + return buf; + } + + std::string binToHexString(const char *binData, const size_t dataSize) + { + std::string str(dataSize * 2, 0); + + const uint8_t *bin = reinterpret_cast(binData); + + const char hexDigits[] = { "0123456789abcdef" }; + + for (size_t i = dataSize - 1; std::numeric_limits::max() != i; --i) + { + str[(i << 1) + 0] = hexDigits[bin[i] >> 4]; + str[(i << 1) + 1] = hexDigits[bin[i] & 0x0F]; + } + + return str; + } + + static unsigned char hexStringToBinEncodeSymbol(const char c) + { + if (c >= '0' && c <= '9') + { + return c - 0x30; + } + else if (c >= 'a' && c <= 'f') + { + return c - 0x57; + } + else if (c >= 'A' && c <= 'F') + { + return c - 0x37; + } + + return 0; + } + + std::string hexStringToBin(const std::string &hexStr) + { + std::string bin(hexStr.length() / 2, 0); + + for (size_t i = 0; i < bin.length(); ++i) + { + char a = hexStr[(i << 1) + 0]; + char b = hexStr[(i << 1) + 1]; + + bin[i] = ( + (hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b) + ); + } + + return bin; + } + + unsigned long long htonll(const unsigned long long src) + { + enum Endianness { + INIT = 0, + LITE = 1, + BIGE = 2 + }; + + static int endian = Endianness::INIT; + + union { + unsigned long long ull; + unsigned char c[8]; + } x; + + if (endian == Endianness::INIT) + { + x.ull = 0x01; + endian = (x.c[7] == 0x01ULL) ? Endianness::BIGE : Endianness::LITE; + } + + if (endian == Endianness::BIGE) + { + return src; + } + + x.ull = src; + + unsigned char c; + + c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c; + c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c; + c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c; + c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c; + + return x.ull; + } + + std::string getUniqueName() + { + size_t time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + + time = htonll(time); + + return binToHexString(reinterpret_cast(&time), sizeof(time) ); + } + char *stlStringToPChar(const std::string &str) { const size_t length = str.length(); @@ -146,7 +266,7 @@ namespace Utils const size_t str_mon_length = 64; std::vector s_mon(str_mon_length); - struct ::tm tc = {0}; + struct ::tm tc = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Parse RFC 822 #ifdef WIN32 diff --git a/src/Utils.h b/src/Utils.h index a3fab0a..7896262 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -27,12 +27,15 @@ namespace Utils std::vector explode(const std::string &str, const char sep); - inline std::string getUniqueName() - { - std::stringstream s; - s << std::hex << std::chrono::high_resolution_clock::now().time_since_epoch().count(); - return s.str(); - } + std::string encodeHtmlSymbols(const std::string &str); + + std::string binToHexString(const char *bin, const size_t size); + + std::string hexStringToBin(const std::string &hexStr); + + unsigned long long htonll(const unsigned long long src); + + std::string getUniqueName(); char *stlStringToPChar(const std::string &str); From 48df69373208368ddf4bba0300304de8f41fb5dd Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Tue, 22 Dec 2015 01:31:59 +0300 Subject: [PATCH 05/31] Fixed: correct cleaning of the structure before using --- projects/msvs/httpserverapp.v12.suo | Bin 147456 -> 146944 bytes projects/msvs/httpserverapp.vcxproj | 4 ++++ src/Utils.cpp | 7 ++++++- src/Utils.h | 8 +------- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/projects/msvs/httpserverapp.v12.suo b/projects/msvs/httpserverapp.v12.suo index 3949d5dd312ef3d13671c915e2756c606c809631..6c4c06edb760f3ec98f1151af6bf7d7e08f8df9d 100644 GIT binary patch delta 314 zcmZo@;B5HAF~LBUi2(`(7#LW9OhzF7_y7NYkSH?{vjZ{r=0c->#)$a=C97;5KI5>@2mHahnRG2P2CzP|4(dq8h9QKt}!KpAwpk zMw1J*#U~puu}yYRG+{Rai8C-vzi7y)Ke0e>dxRF_3dTuV4U@FI<%1b28HyQ77*ZK> z8T1%37MA>z?B|dJ=T6UW4$mIEYqLb^jBqvK~zgQ%~!pa16>i_AiEKK>6EjR== ZHyG70PU3NHc9v>)mSWuQEXA}}82~BbWeorT delta 903 zcmXxiNmCO+6u|MB$v_fGtSL=QDu7`bH6lu)sJLLnL|j0P`@W!}BB)V=;>v)ED;m=- zN2@$|2RwQ30#%kL_2LKc8(8JZ65_v;p{st=uiw1snXY-(KbK{>v(fp=^e_}<2C<5% zd_FJJGJYjzRkSq3N7CKusMfBlrJ`C3yR%;czdEaasO6$p`=;xZiBJA|k#VG4Jf5E^ z6QBJN@yF?l1XxUxlpB}Xu`DRT9LNV|F^isHuwNEASp;~!jQzy3Avc&FLGD$On~N~2 zP>mYY!o)nt<1Ii03sHwfsK;U~K?9{TY&f*-pa30<0!3A8zC8Ti~SL8{rB737+B^hVdLP zkVOu%D+KdvJAP}=QzISk)R$>J*JudCY|5;B< diff --git a/projects/msvs/httpserverapp.vcxproj b/projects/msvs/httpserverapp.vcxproj index 645ff1a..63c072c 100644 --- a/projects/msvs/httpserverapp.vcxproj +++ b/projects/msvs/httpserverapp.vcxproj @@ -113,6 +113,7 @@ WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPSERVERAPP_EXPORTS;%(PreprocessorDefinitions) $(IntDir)asm\ $(IntDir)obj\ + true Windows @@ -127,6 +128,7 @@ WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPSERVERAPP_EXPORTS;%(PreprocessorDefinitions) $(IntDir)asm\ $(IntDir)obj\ + true Windows @@ -143,6 +145,7 @@ WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) $(IntDir)asm\ $(IntDir)obj\ + true Windows @@ -161,6 +164,7 @@ WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) $(IntDir)asm\ $(IntDir)obj\ + true Windows diff --git a/src/Utils.cpp b/src/Utils.cpp index ac34929..752d32e 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -2,8 +2,12 @@ #include "Utils.h" #include +#include #include +#include #include +#include +#include namespace Utils { @@ -266,7 +270,8 @@ namespace Utils const size_t str_mon_length = 64; std::vector s_mon(str_mon_length); - struct ::tm tc = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + struct ::tm tc; + memset(&tc, 0, sizeof(tc) ); // Parse RFC 822 #ifdef WIN32 diff --git a/src/Utils.h b/src/Utils.h index 7896262..86e71c7 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -4,14 +4,8 @@ #include "FileIncoming.h" #include -#include -#include -#include -#include -#include -#include +#include #include -#include namespace Utils { From 3a25e12f4df59496f4c100e05b0def79457e07a5 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Tue, 22 Dec 2015 18:44:36 +0300 Subject: [PATCH 06/31] The code for unicode version of project was added --- projects/msvs/httpserverapp.v12.suo | Bin 146944 -> 150016 bytes src/System.cpp | 38 +++++++++++++++++++++++----- src/System.h | 2 +- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/projects/msvs/httpserverapp.v12.suo b/projects/msvs/httpserverapp.v12.suo index 6c4c06edb760f3ec98f1151af6bf7d7e08f8df9d..135eab33b3fb1ef181163b529078838f53547f41 100644 GIT binary patch delta 8959 zcmds7ZFo~vw$47JB@H2j5JHHdO=~QrrX?)}p%$7#L4*#arGRLGmM=>zB|uvX6q+&} z96rR71#G=AP&$HKMJIfWA}R*Nix=lI40;_MN2cT8jMt9=9CVaXxbHeiTAZ1y&JX|G zJkQ&l?6c3=d$0AbcddO+17GR_TM}A5w`gJ?lSZS*u>h`JzkZ#Y`Pc#UKeQzKA+g!- z2r5M)o|2U$W7~n7XL$2|B@%Hu(4ST)E5v;IRGC6Y`?|#ps_Ry)!%eOmahi_xP3w6V z4h#T)`jOD~YwC$3?!v9{01wLD`vAJ=Z$8iMu}=@Q$Bu8t>=N)B^VWP7Ys7c#*pBl~ zoJ$5$fSUmqz$;GGXqq$wagYWK0@8t70XL8VWCDW$50C|914DouU??yQxD6N%i~w?h z+kre_Brpod2fRQ5Fd7&G6ar&`aTs572M)#qcLEcDi9iwX17H$R3`_<}fKp%zPzFo| zrUBCdw(AVwZr~oE9GD5r0%ijhKqW8-m+eUC(f z0l%F|-y@OOf#1p`^!dJsWcmjt={=U1zu8|L{OnsQ)O(r|qd%PZ{y(DrJNb%(oP(Zk z%t6oJ-xTzG9vGmqEI)d|jZx15Or{<=JvoY_y{}KDCHg)C_*X1$`IxQE-xc_-q~q4& z&3;eN@Dh!2j12a?5}$??Hj=1JOaIAm!Rc~s|`l%VP+hX%LBaU8r%U$|b?*>Kc9 z+N@q~i>DR6(nU68{3h}mwYsPvMlNI>X{P19ZlyWH9Te`B6US<@id)1G^%8EIjkXOW zEEDPEz`UR%GQ9yWB?tv4IQG;@a6o3!7Xw!cFV&@;Nl+!2J*G~36x9tX*71Tk18|dJ zBn~)Y`4jwq=IKG-=xHpN&#MX@@w)42mk0<7^cs^OQgE76mue(VMNI&I{s}XNPSSE< zaMz$!OAUz=>7|}oGLWih>GQ-!VWhgGVx1OUZtChLG^&FmoCx>&MoxH*|HuiiQKuak zy@-h* z5i!V3_;vt^0PJ%;3Exg&@ZP>{e;fDk-HENIx4x@)B_F8t3muZ*x7|4T+ipCIn$367 z*|PZF4gdAQDO16a-xcJJIX-mKf6wBHO*Z}gz?&;W!NfvcZ!GLzH#TYy(oa*XBUnEZyYB9x0i~UNqHE*)@KKaLBdBXVJ)Rt+X6MaW1n!EUl#2c@u(qxUgTA-`hegEtwgFfy3 z_ARe-Z-g~9r5D7r3v7Z42Ip_~-<1AswoHbjQUI&wP)&BdIG8zJq47?)m`-)hCNYgZ z^%T>|WREDLx~!%+u5NVS^E#OJ3$W(=udgKIyRSr}v7s1VCfbK7LE|ghn3~BeF0rxG zfm}zkqkK2UYBL(w02~G_z>k2nzyrXKfpx%oU<0rbco5hGJOs1?n}Hxez!qRDAOZG? zP@SR5SwSE2s`w?%_S{5zHS7Llhom1=$zFIwc~fue~j zo=EMUsn(6NXi4#+;2tw=sx&1;xTet@le4dgm2~ND9VHg(#XGW~4=(E1Z6imXk<7Q( zQ<={v!$R2U%UmmIb8G2j!8RJ@Gt!X)1I>BUPN7l5g9R2U^!h0KD<3(%F4B(i$xxPX zQ1yK}I+(wL4EZ*yJ>sLb*(O z@0C)8KZW++VG~bN$;jOlddx^2r*z_^gcBY-^c#1oAaCI)x-!vD+KD@<2JXH$gINHsq((r?_xPTNjA z^s}OVVrwf@{NbXOh!KlQEYZn4HMxZX>-1#$%n`>csHUt_50U?g6!Jb2PZecaI|E^IFk6YfOaq45N^SR~Qp;=g)Rw2G&+oQkQ3X@(kWVQvu^&`8Jfn(E-cib)**C)= zUmqZR^A>=a6)-TOFR=Nxe zhax0sXX~-WE#OQ@_WqL~npUjNEbewRO_L=(#7N4_(9xC!Rvt&5?JqJ_>&=$Qabi)h zP)n0`7|3*9D{iCX^X{Wh=AL8H)9JZs5iUfQYey_4tyxVJfD#4H(AG(M91!Zt-+v z@tKR#L<^j>kTUC>R9G9JmSy3{y}-|!Wma6UP1g1mjcipLyO=7LYC8igw8W+^dh2TV z-?PL(2kYml%HaIiO~HC6$OCqfqufE>dV@@Hhz9Z>)6(fWGaX*bGdGb}nkhV4D+W@5 zH;Y20uHbo#u*gcixRYMlZlFMePF0uIx9w4ykD=qWp!xkytgw;JE_P99Rf^ow1A%Bf z6%&}&hzPb8*eUQ1xZS9y954)e774l{S~7Ey8ky27gkJS=IWJ~b)G%>i=qWULx-nD?u%>@$2*BO4pg~6 z0U|Kz$B8OSSfIie4HS9+db+kT=4KP^SZj-lhNma`dmm)URP~+S*l3ky7epg@pK~GH z4f4uB{0MCDQ1IhSb}hMEb69Jsq9~1i@em~CGtn5Vg?1F^qi%|ayu?(@^qG+Yo9rS) zm90;zV*dc5v|L`kBF4~5W*Z{vQFLySXD}WXWZLl44&PW$rRSMs_DE8z}LVkvw}0s{c!9H*_#3#uBFf(H?BM=TQWqWnpZ#Ar$>RZo+j@zF|VNmZ=oRBuM<_WWROUvGfx!J zg~wk(cK1=}@tm!SvYtGTTUi7kb~fpC3!NB6&6lP^g&Y)k%Fe`);Q@+CWg3@pVd}l= z*-qCSCoyIbBGsvy^s&ffuN`niHQ7mx2aGCB)aAVyvLpW$ly4{FW*vD$T2xR)RQt0u z=!uVOv8#ujbn?(qR8OU}|B#KZ+(_Q(R+@CkKx<0vR52$#PTeQbl7>EF4_)5(2u+xd z3h9VRtmQ>6roGQNut-FZ2NI~GlxHk-^5>5Ojj>>kq}}k(QB$Crn*4%8w9DjfN)!3E zBP%}-mOU4^!FM*=`J9zb9^I!(Zrf28wLZHyMhZ1IWO)RI6!VcnMl9jnCY{Z;)r-@y3>_uJ7 zIxLL37p=%noA=gH+b8id@2b#?$#Qc~aX(mUlUsUv^jsxlxmZEkW0OO9M-wn1xLE7oSx&d6u(zeqMmbr+Qbu3Pi z9R^f>-qTu9&H6xr|8yb{P`r$#Gp|%&rjf$05CM$c1=hOj}Wg7B)RSlJ(1;4aKDzNYw zj~eo7Qlar@j4ZiwvP(%+my{|i6GW4|)K}P~#|B;xikOM@v*J(j%AJBL-gKyI+<(ZR z(mRAfLp5~&x?7*Jw4)hdTekJdk%sqrJ^l>LSt zlJ&Mn9gyoy$J@13@f)nVj~d#koh3&kJ6lj?Ea*)C9j_)T_eQJ+$=Pz=OzrQ~b8guf zO)M#LUIKJuwZiEOSz@7987Ju2+Z%Bkb<)TtRy3e79MwCNWXn z=*jX9Y%Z|tlKy_tie_PF-VE(=s^xiHpfg>{mh&PJX?QIR+3AdNDECY0(no66-XAlu z8s>7`1!3gM&&NdceweDdyCZB=>$ga%)!_*N?>o=WbjiR60;*M2MHAla+G3_dUN=C2 zYss|BF5h@xm?EB!)E2F*lfkBV;YLF3jSV1b-MVY6~ah3R06RQ_eI4Y#+FCvXo)?v;> zJ6Y(Z`?3fkvFD&v3-a7hP#BnC)NxJA%sc|$ZIZ4y@e%Kgp&aSb87H(Tbt0aZ;VZ)#8>G#qBuaBXWfO0& zHpzoG2|ss0(UYcbSq{m|{gvHnc_IBtA_Zz(AwB&Ss~XW^RouMh5rYKxq)2y?Vid;wA$1wbF!{7wDV6?Pag^>>Hp;!XDlKx0Lj6X{FzvSwFYIzjU#$u`pMT&sCE2%a+b9pR#;e z?fgaZj@uP?{3D&0<;8V%OWpV)c1`KV zd;k3u61r&$zgthEJ~H#nxqkoP=z@B8E$GJP{I54hX4Li9rcvL1bv0=CX)}Kc|G7bu zyOxT<8yi;^dd6lI3>`BpWAu=rBQkQv=Cqqda#qHO(Zf6$Lxv0+IwCuJOm;zb_NoNc zj6Ao@=#))gyH~9B>mx)a)Ag4pOo@H0-3z~?D|&Q~j9cZ7j%w^0wX<#54Q*XxMUMW_ zM7n4f1BqMvk;zg{;dGrW?IDJ@-zubcuo7tRD}rt>og=dxK3H+~nu}LQ{67fM4>h~< uyGIR8$A6Ga@4Ia>kgHVF39ki@#gmmjbZ(3r^|*!>RVP#9ojUp`!}7nJbZ%^=v~!sR7uT@PErF~v@)wEm?H~L@V^(7p zl9q(OOiXAGt`kKE!-9gk2U10x$PmX+VEDopOnl*6bW=AT^ZUE)WQHa3hwdbw-g8b* z@A=(x&iysK$q>G%ZgiK4v{bRAr75TqT%MYm;@)(~0HfUM%Iyy<+eDFo5)~^cLzajl zbGY?%(*wmL)PW&ht85qTR4vEF?MfaxVgpU0f|kf&x?eS-ZJzGSa-n7dF4>Zlyhy;* zI3Eq3mJ1@$25>ze^#~LIx2Fq_waw_uK|PDZ>QZfvUJut4ed;&(x!mP4XwQ-9w(>N*c04`T`9Y;G z(=AsSEoG&tP6w`Ka08S>1@K^2C2uq489b?;8|8Xqle8FXBKPf&ng$J2gfDoXwf*WI zGm)tit);)>1EtU2Ov*x3w6A4bd8<4m+-fy?LLj?b)<~c^l#4aMR8x> z3Z8~8*b3XA8@9tU5QiPG6P|_VU>EF$=ivo-5qh8(`k){7z)P@~LrI|WGQ0x&;8oZU zufYJk4hP^3I0%Dq2;PLl@D>cg5g3M}@HV^y$KW`efDt$e@4|cVK77DS@gXXw;3N1L zK7mi+GdK-rU=%)wv+xCc317k2@C}@UZ{a)m9)5ry;V1YReu4AAd-EHN!8rV0g^xer zPndv7xBwU75?qEU;FmkTT#!6aWsh|>igQG<5uaEq-NF*B_eyW2H{K*D`kx&;^5D4n zQ^)NNf$8~_q~of94)l-#Di|OWj9`K+Fhe$2AP43FpK2?vHkc3BgMr_DWG7OSN#J3c z{dDV-r&~_u95IjqOQMJ5;U1fJTn-A4NrxVOUAROYKD7i_JEUHL+70xeoTwd^gIOLE zhr;8yMBQz)SO(o8a>{Xc3*U<>Wzgf7K95_s2qV<~iSiYss;K5e>V}I}Dg1J4Eqya; zd(z}&R*M`GPAZZ?bBlp;(JQ9M=s4u{a>9I6;m~6HnuOC-h#F@lE`9a};@Nd>G(xY^I~6zqO@@`drOIS%7;b zXS}jfewF_({$2uY%|fcSUg%Gzn3Xo(t9)#90W5&)z?$6abriKW7>JJ+|0N{v&yU$6 z8?x)Auq{{lX?b~OJ}r-*{b{$=inxmebtkBr>UYbw@ilVv&dgZP7AlT;%|b~mJ41&Z z()*|??^@?bIQ62|-e(U}?37RVQfs~Ao #ifdef WIN32 - char myWndClassName[] = "WndClassNameConstant"; + #include + ::TCHAR myWndClassName[] = TEXT("WndClassNameConstant"); + + #ifdef UNICODE + #include + #endif #endif namespace System @@ -26,11 +31,11 @@ namespace System if (process_id == ed.process_id && ::GetConsoleWindow() != hWnd) { - std::array class_name; + std::array<::TCHAR, 257> class_name; ::GetClassName(hWnd, class_name.data(), class_name.size() - 1); - if (0 == ::strcmp(class_name.data(), myWndClassName) ) + if (0 == ::_tcscmp(class_name.data(), myWndClassName) ) { ed.hWnd = hWnd; @@ -65,11 +70,16 @@ namespace System std::string getTempDir() { #ifdef WIN32 - std::array buf; + std::array buf; const size_t len = ::GetTempPath(buf.size(), buf.data() ); - return std::string(buf.cbegin(), buf.cbegin() + len); + #ifdef UNICODE + std::wstring_convert> converter; + return converter.to_bytes(buf.data() ); + #else + return std::string(buf.cbegin(), buf.cbegin() + len); + #endif #elif POSIX const char *buf = ::getenv("TMPDIR"); @@ -94,7 +104,14 @@ namespace System bool isFileExists(const std::string &fileName) { #ifdef WIN32 - const ::DWORD attrib = ::GetFileAttributes(fileName.c_str() ); + #ifdef UNICODE + std::wstring_convert> converter; + const std::wstring file_name = converter.from_bytes(fileName); + #else + const std::string &file_name = fileName; + #endif + + const ::DWORD attrib = ::GetFileAttributes(file_name.c_str() ); if (INVALID_FILE_ATTRIBUTES == attrib) { @@ -119,7 +136,14 @@ namespace System bool getFileSizeAndTimeGmt(const std::string &filePath, size_t *fileSize, time_t *fileTime) { #ifdef WIN32 - ::HANDLE hFile = ::CreateFile(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + #ifdef UNICODE + std::wstring_convert> converter; + const std::wstring file_path = converter.from_bytes(filePath); + #else + const std::string &file_path = filePath; + #endif + + ::HANDLE hFile = ::CreateFile(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); if (INVALID_HANDLE_VALUE == hFile) { diff --git a/src/System.h b/src/System.h index ef6445e..d16896b 100644 --- a/src/System.h +++ b/src/System.h @@ -2,7 +2,7 @@ #ifdef WIN32 #include - char myWndClassName[]; + ::TCHAR myWndClassName[]; #ifdef SIGTERM #undef SIGTERM From 47f66383dfd88d1e66de48a1f676c9f83df80563 Mon Sep 17 00:00:00 2001 From: awwit Date: Sat, 9 Jan 2016 02:30:15 +0300 Subject: [PATCH 07/31] Minor fixes --- projects/qt-creator/httpserverapp.pro.user | 4 +- src/Utils.cpp | 61 ++++++++++++---------- src/Utils.h | 10 +--- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/projects/qt-creator/httpserverapp.pro.user b/projects/qt-creator/httpserverapp.pro.user index 4af6cd7..84d9027 100644 --- a/projects/qt-creator/httpserverapp.pro.user +++ b/projects/qt-creator/httpserverapp.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -61,7 +61,7 @@ Desktop Desktop {c77ee4a2-1c2a-4bac-9185-8378ec4ebf5d} - 1 + 0 0 0 diff --git a/src/Utils.cpp b/src/Utils.cpp index 752d32e..cd22af2 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -11,16 +11,26 @@ namespace Utils { + void toLower(std::string &str, const std::locale &loc) + { + for (auto &c : str) + { + c = std::tolower(c, loc); + } + } + void trim(std::string &str) { - const size_t last = str.find_last_not_of(" \t\n\v\f\r"); + static const char whitespace[] = {" \t\n\v\f\r"}; + + const size_t last = str.find_last_not_of(whitespace); if (std::string::npos == last) { return str.clear(); } - str.assign(str.cbegin() + str.find_first_not_of(" \t\n\v\f\r"), str.cbegin() + last + 1); + str.assign(str.cbegin() + str.find_first_not_of(whitespace), str.cbegin() + last + 1); } std::vector explode(const std::string &str, const char sep) @@ -68,7 +78,7 @@ namespace Utils return buf; } - std::string binToHexString(const char *binData, const size_t dataSize) + std::string binToHexString(const void *binData, const size_t dataSize) { std::string str(dataSize * 2, 0); @@ -109,8 +119,8 @@ namespace Utils for (size_t i = 0; i < bin.length(); ++i) { - char a = hexStr[(i << 1) + 0]; - char b = hexStr[(i << 1) + 1]; + const char a = hexStr[(i << 1) + 0]; + const char b = hexStr[(i << 1) + 1]; bin[i] = ( (hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b) @@ -164,7 +174,7 @@ namespace Utils time = htonll(time); - return binToHexString(reinterpret_cast(&time), sizeof(time) ); + return binToHexString(&time, sizeof(time) ); } char *stlStringToPChar(const std::string &str) @@ -254,24 +264,19 @@ namespace Utils time_t stringTimeToTimestamp(const std::string &strTime) { - /* static const std::unordered_map map_days { - {"Sun", 0}, {"Mon", 1}, {"Tue", 2}, {"Wed", 3}, {"Thu", 4}, {"Fri", 5}, {"Sat", 6} - };*/ - static const std::unordered_map map_months { {"Jan", 0}, {"Feb", 1}, {"Mar", 2}, {"Apr", 3}, {"May", 4}, {"Jun", 5}, {"Jul", 6}, {"Aug", 7}, {"Sep", 8}, {"Oct", 9}, {"Nov", 10}, {"Dec", 11} }; if (strTime.length() > 64) { - return (time_t) ~0; + return ~0; } const size_t str_mon_length = 64; std::vector s_mon(str_mon_length); - struct ::tm tc; - memset(&tc, 0, sizeof(tc) ); + struct ::tm tc = {}; // Parse RFC 822 #ifdef WIN32 @@ -301,27 +306,24 @@ namespace Utils ::time_t cur_time = tTime; - if ( (time_t)~0 == tTime) + if (tTime == ~0) { ::time(&cur_time); } #ifdef WIN32 - struct ::tm stm = {0}; + struct ::tm stm = {}; - if (isGmtTime) - { - ::localtime_s(&stm, &cur_time); - } - else - { + isGmtTime ? + ::localtime_s(&stm, &cur_time) : ::gmtime_s(&stm, &cur_time); - } // RFC 822 ::strftime(buf.data(), buf.size(), "%a, %d %b %Y %H:%M:%S GMT", &stm); #else - struct ::tm *ptm = isGmtTime ? localtime(&cur_time) : gmtime(&cur_time); + struct ::tm *ptm = isGmtTime ? + ::localtime(&cur_time) : + ::gmtime(&cur_time); // RFC 822 ::strftime(buf.data(), buf.size(), "%a, %d %b %G %H:%M:%S GMT", ptm); @@ -350,7 +352,7 @@ namespace Utils { if (cookieHeader.empty() ) { - return false; + return true; } for (size_t cur_pos = 0, next_value; std::string::npos != cur_pos; cur_pos = next_value) @@ -385,7 +387,7 @@ namespace Utils return true; } - inline bool isUrlAllowed(const std::string::value_type c) + inline bool isUrlAllowed(const char c) { static const std::string special("-_.~"); @@ -400,7 +402,7 @@ namespace Utils for (auto it = str.cbegin(); str.cend() != it; ++it) { - const std::string::value_type &c = *it; + const char &c = *it; if (' ' == c) { @@ -423,11 +425,12 @@ namespace Utils { std::string decoded; - std::string::value_type ch[3] = {0}; + // ch length must be >= 3 + std::array ch; for (auto it = str.cbegin(); str.cend() != it; ++it) { - const std::string::value_type &c = *it; + const char &c = *it; if ('%' == c) { @@ -449,7 +452,7 @@ namespace Utils ch[1] = *it; - decoded.push_back(strtoul(ch, nullptr, 16) ); + decoded.push_back(strtoul(ch.data(), nullptr, 16) ); } else if ('+' == c) { diff --git a/src/Utils.h b/src/Utils.h index 86e71c7..b2e15c1 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -9,13 +9,7 @@ namespace Utils { - inline void tolower(std::string &str, const std::locale &loc) - { - for (auto &c : str) - { - c = std::tolower(c, loc); - } - } + void toLower(std::string &str, const std::locale &loc); void trim(std::string &str); @@ -23,7 +17,7 @@ namespace Utils std::string encodeHtmlSymbols(const std::string &str); - std::string binToHexString(const char *bin, const size_t size); + std::string binToHexString(const void *bin, const size_t size); std::string hexStringToBin(const std::string &hexStr); From 0fc589e6152630486931f52c2e361418dc965c75 Mon Sep 17 00:00:00 2001 From: awwit Date: Sun, 10 Jan 2016 19:32:23 +0300 Subject: [PATCH 08/31] Minor fixes #2 --- projects/qt-creator/httpserverapp.pro.user | 4 +- src/Socket.cpp | 55 +++++++++++++--------- src/Socket.h | 11 +++-- src/System.cpp | 9 ++-- 4 files changed, 46 insertions(+), 33 deletions(-) diff --git a/projects/qt-creator/httpserverapp.pro.user b/projects/qt-creator/httpserverapp.pro.user index 84d9027..16cf2b3 100644 --- a/projects/qt-creator/httpserverapp.pro.user +++ b/projects/qt-creator/httpserverapp.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -61,7 +61,7 @@ Desktop Desktop {c77ee4a2-1c2a-4bac-9185-8378ec4ebf5d} - 0 + 1 0 0 diff --git a/src/Socket.cpp b/src/Socket.cpp index 8d4eff0..a034757 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -27,6 +27,17 @@ namespace HttpServer #endif } + int Socket::getLastError() + { + #ifdef WIN32 + return ::WSAGetLastError(); + #elif POSIX + return errno; + #else + #error "Undefine platform" + #endif + } + Socket::Socket(): socket_handle(~0) { @@ -47,16 +58,16 @@ namespace HttpServer obj.socket_handle = ~0; } - System::native_socket_type Socket::open() + bool Socket::open() { close(); socket_handle = ::socket(AF_INET, SOCK_STREAM, 0); - return socket_handle; + return is_open(); } - int Socket::close() + bool Socket::close() { if (is_open() ) { @@ -71,15 +82,15 @@ namespace HttpServer if (0 == result) { socket_handle = ~0; - } - return result; + return true; + } } - return ~0; + return false; } - int Socket::bind(const int port) const + bool Socket::bind(const int port) const { const ::sockaddr_in sock_addr = { AF_INET, @@ -88,12 +99,12 @@ namespace HttpServer 0 }; - return ::bind(socket_handle, reinterpret_cast(&sock_addr), sizeof(sockaddr_in) ); + return 0 == ::bind(socket_handle, reinterpret_cast(&sock_addr), sizeof(sockaddr_in) ); } - int Socket::listen() const + bool Socket::listen() const { - return ::listen(socket_handle, SOMAXCONN); + return 0 == ::listen(socket_handle, SOMAXCONN); } Socket Socket::accept() const @@ -170,20 +181,20 @@ namespace HttpServer return Socket(client_socket); } - int Socket::shutdown() const + bool Socket::shutdown() const { if (is_open() ) { #ifdef WIN32 - return ::shutdown(socket_handle, SD_BOTH); + return 0 == ::shutdown(socket_handle, SD_BOTH); #elif POSIX - return ::shutdown(socket_handle, SHUT_RDWR); + return 0 == ::shutdown(socket_handle, SHUT_RDWR); #else #error "Undefine platform" #endif } - return -1; + return false; } bool Socket::nonblock(const bool isNonBlock) const @@ -192,32 +203,34 @@ namespace HttpServer unsigned long value = isNonBlock; return 0 == ::ioctlsocket(socket_handle, FIONBIO, &value); #elif POSIX - return -1 != ::fcntl(socket_handle, F_SETFL, isNonBlock ? O_NONBLOCK : O_SYNC); + return ~0 != ::fcntl(socket_handle, F_SETFL, isNonBlock ? O_NONBLOCK : O_SYNC); #else #error "Undefine platform" #endif } -/* bool Socket::is_nonblock() const +/* + bool Socket::is_nonblock() const { #ifdef WIN32 #elif POSIX - int flags = ::fcntl(socket_handle, F_GETFL, 0); - return (flags != -1) && (flags & O_NONBLOCK); + const int flags = ::fcntl(socket_handle, F_GETFL, 0); + return (flags != ~0) && (flags & O_NONBLOCK); #else #error "Undefine platform" #endif - }*/ + } +*/ bool Socket::tcp_nodelay(const bool nodelay) const { #ifdef WIN32 int flags = nodelay ? 1 : 0; - return 0 == setsockopt(socket_handle, IPPROTO_TCP, TCP_NODELAY, (char *)&flags, sizeof(flags) ); + return 0 == setsockopt(socket_handle, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&flags), sizeof(flags) ); #elif POSIX int flags = nodelay ? 1 : 0; - return 0 == setsockopt(socket_handle, IPPROTO_TCP, TCP_NODELAY, (char *)&flags, sizeof(flags) ); + return 0 == setsockopt(socket_handle, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags) ); #else #error "Undefine platform" #endif diff --git a/src/Socket.h b/src/Socket.h index db2c9c3..4b4871b 100644 --- a/src/Socket.h +++ b/src/Socket.h @@ -36,6 +36,7 @@ namespace HttpServer public: bool static Startup(); bool static Cleanup(); + int static getLastError(); public: Socket(); @@ -45,8 +46,8 @@ namespace HttpServer ~Socket() = default; - System::native_socket_type open(); - int close(); + bool open(); + bool close(); inline bool is_open() const { @@ -59,14 +60,14 @@ namespace HttpServer #endif } - int bind(const int port) const; - int listen() const; + bool bind(const int port) const; + bool listen() const; Socket accept() const; Socket nonblock_accept() const; Socket nonblock_accept(const std::chrono::milliseconds &timeout) const; - int shutdown() const; + bool shutdown() const; bool nonblock(const bool isNonBlock = true) const; // bool is_nonblock() const; diff --git a/src/System.cpp b/src/System.cpp index 67bd452..7e397aa 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -21,9 +21,9 @@ namespace System ::HWND hWnd; }; - ::BOOL WINAPI EnumProc(::HWND hWnd, ::LPARAM lParam) + static ::BOOL WINAPI EnumProc(const ::HWND hWnd, const ::LPARAM lParam) { - EnumData &ed = *reinterpret_cast(lParam); + EnumData &ed = *reinterpret_cast(lParam); native_processid_type process_id = 0; @@ -143,7 +143,7 @@ namespace System const std::string &file_path = filePath; #endif - ::HANDLE hFile = ::CreateFile(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + const ::HANDLE hFile = ::CreateFile(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); if (INVALID_HANDLE_VALUE == hFile) { @@ -187,7 +187,6 @@ namespace System return true; #elif POSIX - struct ::tm *clock; struct ::stat attrib; if (-1 == ::stat(filePath.c_str(), &attrib) ) @@ -197,7 +196,7 @@ namespace System *fileSize = attrib.st_size; - clock = ::gmtime(&(attrib.st_mtime) ); + struct ::tm *clock = ::gmtime(&(attrib.st_mtime) ); *fileTime = ::mktime(clock); From 4af1db0a5b44522966f3cf1dff4007ec72bafc91 Mon Sep 17 00:00:00 2001 From: awwit Date: Sun, 31 Jan 2016 01:01:19 +0300 Subject: [PATCH 09/31] Fixed url encode/decode functions --- src/Utils.cpp | 86 +++++++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index cd22af2..a833299 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -21,16 +21,16 @@ namespace Utils void trim(std::string &str) { - static const char whitespace[] = {" \t\n\v\f\r"}; + static const std::array whitespace { " \t\n\v\f\r" }; - const size_t last = str.find_last_not_of(whitespace); + const size_t last = str.find_last_not_of(whitespace.data() ); if (std::string::npos == last) { return str.clear(); } - str.assign(str.cbegin() + str.find_first_not_of(whitespace), str.cbegin() + last + 1); + str.assign(str.cbegin() + str.find_first_not_of(whitespace.data() ), str.cbegin() + last + 1); } std::vector explode(const std::string &str, const char sep) @@ -84,12 +84,12 @@ namespace Utils const uint8_t *bin = reinterpret_cast(binData); - const char hexDigits[] = { "0123456789abcdef" }; + static const std::array hexDigits { "0123456789abcdef" }; for (size_t i = dataSize - 1; std::numeric_limits::max() != i; --i) { - str[(i << 1) + 0] = hexDigits[bin[i] >> 4]; - str[(i << 1) + 1] = hexDigits[bin[i] & 0x0F]; + str[i * 2 + 0] = hexDigits[bin[i] >> 4]; + str[i * 2 + 1] = hexDigits[bin[i] & 0x0F]; } return str; @@ -119,8 +119,8 @@ namespace Utils for (size_t i = 0; i < bin.length(); ++i) { - const char a = hexStr[(i << 1) + 0]; - const char b = hexStr[(i << 1) + 1]; + const char a = hexStr[i * 2 + 0]; + const char b = hexStr[i * 2 + 1]; bin[i] = ( (hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b) @@ -387,81 +387,71 @@ namespace Utils return true; } - inline bool isUrlAllowed(const char c) + static inline bool isCharUrlAllowed(const char c) { - static const std::string special("-_.~"); - - return std::string::npos != special.find(c); + return c == '-' || c == '_' || c == '.' || c == '~'; } std::string urlEncode(const std::string &str) { - std::ostringstream encoded; - encoded.fill('0'); - encoded << std::hex; + std::string encoded; + + static const std::array hexDigits { "0123456789abcdef" }; - for (auto it = str.cbegin(); str.cend() != it; ++it) + for (size_t i = 0; i < str.length(); ++i) { - const char &c = *it; + const unsigned char c = str[i]; - if (' ' == c) + if (std::isalnum(c) || isCharUrlAllowed(c) ) { - encoded << '+'; + encoded.push_back(c); } - else if (std::isalnum(c) || isUrlAllowed(c) ) + else if (' ' == c) { - encoded << c; + encoded.push_back('+'); } else { - encoded << '%' << std::setw(2) << (int) ( (unsigned char) c); + const uint8_t a = c >> 4; + const uint8_t b = c & 0x0F; + + encoded.push_back('%'); + encoded.push_back(hexDigits[a]); + encoded.push_back(hexDigits[b]); } } - return encoded.str(); + return encoded; } std::string urlDecode(const std::string &str) { std::string decoded; - // ch length must be >= 3 - std::array ch; - - for (auto it = str.cbegin(); str.cend() != it; ++it) + for (size_t i = 0; i < str.length(); ++i) { - const char &c = *it; + unsigned char c = str[i]; if ('%' == c) { - ++it; - - if (str.cend() == it) + if (i + 2 < str.length() ) { - break; - } - - ch[0] = *it; + const char a = str[i + 1]; + const char b = str[i + 2]; - ++it; + c = ( + (hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b) + ); - if (str.cend() == it) - { - break; + i += 2; } - - ch[1] = *it; - - decoded.push_back(strtoul(ch.data(), nullptr, 16) ); } else if ('+' == c) { - decoded.push_back(' '); - } - else - { - decoded.push_back(c); + c = ' '; } + + decoded.push_back(c); } return decoded; From d41d55d89e2bb26ce5f97b4866ca2d06bbd58ac7 Mon Sep 17 00:00:00 2001 From: awwit Date: Tue, 26 Apr 2016 00:17:00 +0300 Subject: [PATCH 10/31] Added support of HTTPS (via gnutls) Changed the build system on QBS (for Linux) --- README.md | 34 ++- projects/qt-creator/httpserverapp.pro | 43 ---- projects/qt-creator/httpserverapp.pro.user | 270 --------------------- projects/qt-creator/httpserverapp.qbs | 49 ++++ src/Main.cpp | 22 +- src/ServerRequest.h | 10 +- src/ServerResponse.h | 5 +- src/Socket.cpp | 211 ++++++++-------- src/Socket.h | 30 ++- src/SocketAdapter.cpp | 15 ++ src/SocketAdapter.h | 32 +++ src/SocketAdapterDefault.cpp | 49 ++++ src/SocketAdapterDefault.h | 28 +++ src/SocketAdapterTls.cpp | 122 ++++++++++ src/SocketAdapterTls.h | 32 +++ src/Test.cpp | 6 +- src/Utils.cpp | 8 +- 17 files changed, 527 insertions(+), 439 deletions(-) delete mode 100644 projects/qt-creator/httpserverapp.pro delete mode 100644 projects/qt-creator/httpserverapp.pro.user create mode 100644 projects/qt-creator/httpserverapp.qbs create mode 100644 src/SocketAdapter.cpp create mode 100644 src/SocketAdapter.h create mode 100644 src/SocketAdapterDefault.cpp create mode 100644 src/SocketAdapterDefault.h create mode 100644 src/SocketAdapterTls.cpp create mode 100644 src/SocketAdapterTls.h diff --git a/README.md b/README.md index 4ba55d7..51fda94 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,36 @@ httpserverapp ============= -Sample http application on C++ +Sample application for [C++ http server](https://github.com/awwit/httpserver). -For http server on C++ +Dependencies +------------ -See: https://github.com/awwit/httpserver +Common: + +* [gnutls](https://www.gnutls.org/) + +Linux: + +* dl +* pthread + +Build +----- + +Linux: + +```sh +git clone https://github.com/awwit/httpserverapp.git +cd httpserverapp +mkdir build +cd build +qbs build -f ./../projects/qt-creator/httpserverapp.qbs release +``` + +License +======= + +The source codes are licensed under the +[MIT](https://opensource.org/licenses/MIT), +the full text of the license is located in the [LICENSE](LICENSE) file. diff --git a/projects/qt-creator/httpserverapp.pro b/projects/qt-creator/httpserverapp.pro deleted file mode 100644 index 784e788..0000000 --- a/projects/qt-creator/httpserverapp.pro +++ /dev/null @@ -1,43 +0,0 @@ -TARGET = httpserverapp -TEMPLATE = lib - -CONFIG += c++11 -CONFIG -= app_bundle -CONFIG -= qt - -lessThan(QT_MAJOR_VERSION, 5) { - CONFIG += object_with_source - QMAKE_CXXFLAGS += -std=c++1y -} else { - CONFIG += object_parallel_to_source -} - -unix { - DEFINES += POSIX -} - -CONFIG(debug, debug|release):DEFINES += DEBUG - -SOURCES += \ - ../../src/FileIncoming.cpp \ - ../../src/Main.cpp \ - ../../src/Test.cpp \ - ../../src/Utils.cpp \ - ../../src/Socket.cpp \ - ../../src/System.cpp - -HEADERS += \ - ../../src/FileIncoming.h \ - ../../src/Main.h \ - ../../src/Test.h \ - ../../src/Utils.h \ - ../../src/RawData.h \ - ../../src/ServerRequest.h \ - ../../src/ServerResponse.h \ - ../../src/Socket.h \ - ../../src/System.h - -unix { - target.path = /usr/lib - INSTALLS += target -} diff --git a/projects/qt-creator/httpserverapp.pro.user b/projects/qt-creator/httpserverapp.pro.user deleted file mode 100644 index 16cf2b3..0000000 --- a/projects/qt-creator/httpserverapp.pro.user +++ /dev/null @@ -1,270 +0,0 @@ - - - - - - EnvironmentId - {1b4c0b3e-5aa0-412f-8f7e-3a13c2b330b9} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - true - false - 1 - true - 0 - 8 - true - 1 - false - true - true - false - - - - ProjectExplorer.Project.PluginSettings - - - - ProjectExplorer.Project.Target.0 - - Desktop - Desktop - {c77ee4a2-1c2a-4bac-9185-8378ec4ebf5d} - 1 - 0 - 0 - - ../../build/Debug - - - true - qmake - - QtProjectManager.QMakeBuildStep - false - true - - false - false - false - - - true - Сборка - - Qt4ProjectManager.MakeStep - - -w - -r - - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Сборка - - Qt4ProjectManager.MakeStep - - -w - -r - - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Отладка - - Qt4ProjectManager.Qt4BuildConfiguration - 2 - true - - - ../../build/Release - - - true - qmake - - QtProjectManager.QMakeBuildStep - false - true - - false - false - false - - - true - Сборка - - Qt4ProjectManager.MakeStep - - -w - -r - - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Сборка - - Qt4ProjectManager.MakeStep - - -w - -r - - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Выпуск - - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - 2 - - - 0 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Локальная установка - - ProjectExplorer.DefaultDeployConfiguration - - 1 - - - - false - false - false - false - true - 0.01 - 10 - true - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - 2 - - - - false - %{buildDir} - Особая программа - - ProjectExplorer.CustomExecutableRunConfiguration - 3768 - false - true - false - false - true - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 18 - - - Version - 18 - - diff --git a/projects/qt-creator/httpserverapp.qbs b/projects/qt-creator/httpserverapp.qbs new file mode 100644 index 0000000..106d708 --- /dev/null +++ b/projects/qt-creator/httpserverapp.qbs @@ -0,0 +1,49 @@ +import qbs + +Project { + DynamicLibrary { + name: "httpserverapp" + + Depends { name: "cpp" } + cpp.cxxLanguageVersion: "c++11" + + cpp.defines: qbs.buildVariant == "debug" ? base : base.concat(["DEBUG"]) + + cpp.dynamicLibraries: base.concat(["gnutls"]) + + Properties { + condition: qbs.targetOS.contains("linux") + cpp.defines: outer.concat(["POSIX"]) + cpp.dynamicLibraries: outer.concat(["dl", "pthread"]) + } + + Properties { + condition: qbs.targetOS.contains("windows") + cpp.defines: outer.concat(["WIN32"]) + } + + files: [ + "../../src/FileIncoming.cpp", + "../../src/FileIncoming.h", + "../../src/Main.cpp", + "../../src/Main.h", + "../../src/RawData.h", + "../../src/ServerRequest.h", + "../../src/ServerResponse.h", + "../../src/Socket.cpp", + "../../src/Socket.h", + "../../src/SocketAdapter.cpp", + "../../src/SocketAdapter.h", + "../../src/SocketAdapterDefault.cpp", + "../../src/SocketAdapterDefault.h", + "../../src/SocketAdapterTls.cpp", + "../../src/SocketAdapterTls.h", + "../../src/System.cpp", + "../../src/System.h", + "../../src/Test.cpp", + "../../src/Test.h", + "../../src/Utils.cpp", + "../../src/Utils.h", + ] + } +} diff --git a/src/Main.cpp b/src/Main.cpp index 91d19a3..12e8951 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -28,8 +28,22 @@ DLLEXPORT int application_call(HttpServer::server_request *request, HttpServer:: Utils::parseCookies(it_cookie->second, cookies); } + // Create socket adapter + uint8_t addr[sizeof(HttpServer::SocketAdapterTls)]; + + HttpServer::SocketAdapter *socket_adapter; + + if (request->tls_session) + { + socket_adapter = new (addr) HttpServer::SocketAdapterTls(request->tls_session); + } + else + { + socket_adapter = new (addr) HttpServer::SocketAdapterDefault(request->socket); + } + HttpServer::ServerRequest proc_request { - HttpServer::Socket(request->socket), + *socket_adapter, std::string(request->method), std::string(request->uri_reference), std::string(request->document_root), @@ -41,7 +55,7 @@ DLLEXPORT int application_call(HttpServer::server_request *request, HttpServer:: }; HttpServer::ServerResponse proc_response { - HttpServer::Socket(request->socket), + *socket_adapter, std::map() }; @@ -49,7 +63,7 @@ DLLEXPORT int application_call(HttpServer::server_request *request, HttpServer:: int result = EXIT_SUCCESS; - if (System::isFileExists(absolute_path) ) + if (std::string::npos == absolute_path.find("/../") && System::isFileExists(absolute_path) ) { auto it_connection = proc_request.headers.find("Connection"); @@ -65,6 +79,8 @@ DLLEXPORT int application_call(HttpServer::server_request *request, HttpServer:: result = test(proc_request, proc_response); } + socket_adapter->~SocketAdapter(); + if (proc_response.headers.size() ) { Utils::raw_pair *headers; diff --git a/src/ServerRequest.h b/src/ServerRequest.h index 0982cc8..234fdef 100644 --- a/src/ServerRequest.h +++ b/src/ServerRequest.h @@ -1,7 +1,8 @@ #pragma once #include "RawData.h" -#include "Socket.h" +#include "SocketAdapterDefault.h" +#include "SocketAdapterTls.h" #include "FileIncoming.h" #include @@ -11,6 +12,7 @@ namespace HttpServer struct server_request { const System::native_socket_type socket; + const ::gnutls_session_t tls_session; const char *method; const char *uri_reference; const char *document_root; @@ -27,7 +29,7 @@ namespace HttpServer /** * Структура запроса (входные данные) * - * @member const Socket socket - сокет клиента + * @member const SocketAdapter &socket - сокет клиента * @member const std::string method - метод применяемый к ресурсу * @member const std::string uri_reference - ссылка на ресурс * @member const std::string document_root - корневая директория приложения @@ -39,7 +41,7 @@ namespace HttpServer */ struct ServerRequest { - const Socket socket; + const SocketAdapter &socket; const std::string method; const std::string uri_reference; const std::string document_root; @@ -49,4 +51,4 @@ namespace HttpServer const std::unordered_multimap files; const std::unordered_multimap cookies; }; -}; +}; \ No newline at end of file diff --git a/src/ServerResponse.h b/src/ServerResponse.h index f59400c..302dda0 100644 --- a/src/ServerResponse.h +++ b/src/ServerResponse.h @@ -1,6 +1,7 @@ #pragma once #include "RawData.h" +#include "SocketAdapter.h" #include #include @@ -16,7 +17,7 @@ namespace HttpServer struct ServerResponse { - Socket socket; + SocketAdapter &socket; std::map headers; }; -}; +}; \ No newline at end of file diff --git a/src/Socket.cpp b/src/Socket.cpp index a034757..a9f40b9 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -60,28 +60,28 @@ namespace HttpServer bool Socket::open() { - close(); + this->close(); - socket_handle = ::socket(AF_INET, SOCK_STREAM, 0); + this->socket_handle = ::socket(AF_INET, SOCK_STREAM, 0); - return is_open(); + return this->is_open(); } bool Socket::close() { - if (is_open() ) + if (this->is_open() ) { #ifdef WIN32 - const int result = ::closesocket(socket_handle); + const int result = ::closesocket(this->socket_handle); #elif POSIX - const int result = ::close(socket_handle); + const int result = ::close(this->socket_handle); #else #error "Undefine platform" #endif if (0 == result) { - socket_handle = ~0; + this->socket_handle = ~0; return true; } @@ -99,20 +99,20 @@ namespace HttpServer 0 }; - return 0 == ::bind(socket_handle, reinterpret_cast(&sock_addr), sizeof(sockaddr_in) ); + return 0 == ::bind(this->socket_handle, reinterpret_cast(&sock_addr), sizeof(sockaddr_in) ); } bool Socket::listen() const { - return 0 == ::listen(socket_handle, SOMAXCONN); + return 0 == ::listen(this->socket_handle, SOMAXCONN); } Socket Socket::accept() const { #ifdef WIN32 - System::native_socket_type client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); + System::native_socket_type client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); #elif POSIX - System::native_socket_type client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); + System::native_socket_type client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); #else #error "Undefine platform" #endif @@ -124,25 +124,25 @@ namespace HttpServer System::native_socket_type client_socket = ~0; #ifdef WIN32 WSAPOLLFD event = { - socket_handle, + this->socket_handle, POLLRDNORM, 0 }; if (1 == ::WSAPoll(&event, 1, ~0) && event.revents & POLLRDNORM) { - client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); + client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #elif POSIX struct ::pollfd event = { - socket_handle, + this->socket_handle, POLLIN, 0 }; if (1 == ::poll(&event, 1, ~0) && event.revents & POLLIN) { - client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); + client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #else #error "Undefine platform" @@ -155,25 +155,25 @@ namespace HttpServer System::native_socket_type client_socket = ~0; #ifdef WIN32 WSAPOLLFD event = { - socket_handle, + this->socket_handle, POLLRDNORM, 0 }; if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLRDNORM) { - client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); + client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #elif POSIX struct ::pollfd event = { - socket_handle, + this->socket_handle, POLLIN, 0 }; if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLIN) { - client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); + client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #else #error "Undefine platform" @@ -186,9 +186,9 @@ namespace HttpServer if (is_open() ) { #ifdef WIN32 - return 0 == ::shutdown(socket_handle, SD_BOTH); + return 0 == ::shutdown(this->socket_handle, SD_BOTH); #elif POSIX - return 0 == ::shutdown(socket_handle, SHUT_RDWR); + return 0 == ::shutdown(this->socket_handle, SHUT_RDWR); #else #error "Undefine platform" #endif @@ -201,9 +201,9 @@ namespace HttpServer { #ifdef WIN32 unsigned long value = isNonBlock; - return 0 == ::ioctlsocket(socket_handle, FIONBIO, &value); + return 0 == ::ioctlsocket(this->socket_handle, FIONBIO, &value); #elif POSIX - return ~0 != ::fcntl(socket_handle, F_SETFL, isNonBlock ? O_NONBLOCK : O_SYNC); + return ~0 != ::fcntl(this->socket_handle, F_SETFL, isNonBlock ? O_NONBLOCK : O_SYNC); #else #error "Undefine platform" #endif @@ -227,50 +227,50 @@ namespace HttpServer { #ifdef WIN32 int flags = nodelay ? 1 : 0; - return 0 == setsockopt(socket_handle, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&flags), sizeof(flags) ); + return 0 == setsockopt(this->socket_handle, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&flags), sizeof(flags) ); #elif POSIX int flags = nodelay ? 1 : 0; - return 0 == setsockopt(socket_handle, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags) ); + return 0 == setsockopt(this->socket_handle, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags) ); #else #error "Undefine platform" #endif } - size_t Socket::recv(std::vector &buf) const + long Socket::recv(std::vector &buf) const { #ifdef WIN32 - return ::recv(socket_handle, buf.data(), buf.size(), 0); + return ::recv(this->socket_handle, buf.data(), buf.size(), 0); #elif POSIX - return ::recv(socket_handle, buf.data(), buf.size(), MSG_NOSIGNAL); + return ::recv(this->socket_handle, buf.data(), buf.size(), 0); #else #error "Undefine platform" #endif } - size_t Socket::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const + long Socket::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const { - size_t recv_len = ~0; + long recv_len = ~0; #ifdef WIN32 WSAPOLLFD event = { - socket_handle, + this->socket_handle, POLLRDNORM, 0 }; if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLRDNORM) { - recv_len = ::recv(socket_handle, buf.data(), buf.size(), 0); + recv_len = ::recv(this->socket_handle, buf.data(), buf.size(), 0); } #elif POSIX struct ::pollfd event = { - socket_handle, + this->socket_handle, POLLIN, 0 }; if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLIN) { - recv_len = ::recv(socket_handle, buf.data(), buf.size(), MSG_NOSIGNAL); + recv_len = ::recv(this->socket_handle, buf.data(), buf.size(), 0); } #else #error "Undefine platform" @@ -278,95 +278,112 @@ namespace HttpServer return recv_len; } - size_t Socket::send(const std::string &buf) const + static long send_all(const System::native_socket_type socket_handle, const void *data, const size_t length) { - #ifdef WIN32 - return ::send(socket_handle, buf.data(), buf.length(), 0); - #elif POSIX - return ::send(socket_handle, buf.data(), buf.length(), MSG_WAITALL | MSG_NOSIGNAL); - #else - #error "Undefine platform" - #endif + size_t total = 0; + + while (total < length) + { + const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, length - total, 0); + + if (send_size < 0) + { + return send_size; + } + + total += send_size; + } + + return total; } - size_t Socket::send(const std::vector &buf, const size_t length) const + long Socket::send(const std::string &buf) const { - #ifdef WIN32 - return ::send(socket_handle, buf.data(), length, 0); - #elif POSIX - return ::send(socket_handle, buf.data(), length, MSG_WAITALL | MSG_NOSIGNAL); - #else - #error "Undefine platform" - #endif + return send_all(this->socket_handle, buf.data(), buf.length() ); } - size_t Socket::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const + long Socket::send(const std::vector &buf, const size_t length) const { - size_t send_len = ~0; + return send_all(this->socket_handle, buf.data(), length); + } + + static long nonblock_send_all(const System::native_socket_type socket_handle, const void *data, const size_t length, const std::chrono::milliseconds &timeout) + { + size_t total = 0; + #ifdef WIN32 - WSAPOLLFD event = { - socket_handle, - POLLWRNORM, - 0 - }; + WSAPOLLFD event = { + socket_handle, + POLLWRNORM, + 0 + }; - if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLWRNORM) + while (total < length) { - send_len = ::send(socket_handle, buf.data(), buf.length(), 0); + if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLWRNORM) + { + const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, length - total, 0); + + if (send_size < 0) + { + return send_size; + } + + total += send_size; + } + else + { + return -1; + } } + #elif POSIX - struct ::pollfd event = { - socket_handle, - POLLOUT, - 0 - }; + struct ::pollfd event = { + socket_handle, + POLLOUT, + 0 + }; - if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLOUT) + while (total < length) { - send_len = ::send(socket_handle, buf.data(), buf.length(), MSG_NOSIGNAL); + if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLOUT) + { + const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, length - total, 0); + + if (send_size < 0) + { + return send_size; + } + + total += send_size; + } + else + { + return -1; + } } #else #error "Undefine platform" #endif - return send_len; + + return total; } - size_t Socket::nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const + long Socket::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const { - size_t send_len = ~0; - #ifdef WIN32 - WSAPOLLFD event = { - socket_handle, - POLLWRNORM, - 0 - }; - - if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLWRNORM) - { - send_len = ::send(socket_handle, buf.data(), length, 0); - } - #elif POSIX - struct ::pollfd event = { - socket_handle, - POLLOUT, - 0 - }; + return nonblock_send_all(this->socket_handle, buf.data(), buf.length(), timeout); + } - if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLOUT) - { - send_len = ::send(socket_handle, buf.data(), length, MSG_NOSIGNAL); - } - #else - #error "Undefine platform" - #endif - return send_len; + long Socket::nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const + { + return nonblock_send_all(this->socket_handle, buf.data(), length, timeout); } void Socket::nonblock_send_sync() const { #ifdef WIN32 WSAPOLLFD event = { - socket_handle, + this->socket_handle, POLLWRNORM, 0 }; @@ -374,7 +391,7 @@ namespace HttpServer ::WSAPoll(&event, 1, ~0); #elif POSIX struct ::pollfd event = { - socket_handle, + this->socket_handle, POLLOUT, 0 }; @@ -387,7 +404,7 @@ namespace HttpServer Socket &Socket::operator=(const Socket &obj) { - socket_handle = obj.socket_handle; + this->socket_handle = obj.socket_handle; return *this; } diff --git a/src/Socket.h b/src/Socket.h index 4b4871b..4097cdd 100644 --- a/src/Socket.h +++ b/src/Socket.h @@ -52,9 +52,9 @@ namespace HttpServer inline bool is_open() const { #ifdef WIN32 - return INVALID_SOCKET != socket_handle; + return INVALID_SOCKET != this->socket_handle; #elif POSIX - return ~0 != socket_handle; + return ~0 != this->socket_handle; #else #error "Undefine platform" #endif @@ -73,20 +73,20 @@ namespace HttpServer // bool is_nonblock() const; bool tcp_nodelay(const bool nodelay = true) const; - size_t recv(std::vector &buf) const; - size_t nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const; + long recv(std::vector &buf) const; + long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const; - size_t send(const std::string &buf) const; - size_t send(const std::vector &buf, const size_t length) const; + long send(const std::string &buf) const; + long send(const std::vector &buf, const size_t length) const; - size_t nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const; - size_t nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const; + long nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const; + long nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const; void nonblock_send_sync() const; inline System::native_socket_type get_handle() const { - return socket_handle; + return this->socket_handle; } Socket &operator =(const Socket &obj); @@ -94,4 +94,16 @@ namespace HttpServer bool operator ==(const Socket &obj) const; bool operator !=(const Socket &obj) const; }; +}; + +namespace std +{ + // Hash for Socket + template<> struct hash + { + std::size_t operator()(const HttpServer::Socket &obj) const + { + return std::hash{}(obj.get_handle() ); + } + }; }; \ No newline at end of file diff --git a/src/SocketAdapter.cpp b/src/SocketAdapter.cpp new file mode 100644 index 0000000..5354cb0 --- /dev/null +++ b/src/SocketAdapter.cpp @@ -0,0 +1,15 @@ + +#include "SocketAdapter.h" + +namespace HttpServer +{ + bool SocketAdapter::operator ==(const SocketAdapter &obj) const + { + return this->get_handle() == obj.get_handle(); + } + + bool SocketAdapter::operator !=(const SocketAdapter &obj) const + { + return this->get_handle() != obj.get_handle(); + } +}; \ No newline at end of file diff --git a/src/SocketAdapter.h b/src/SocketAdapter.h new file mode 100644 index 0000000..690e668 --- /dev/null +++ b/src/SocketAdapter.h @@ -0,0 +1,32 @@ +#pragma once + +#include "System.h" + +#include +#include +#include + +#include + +namespace HttpServer +{ + class SocketAdapter + { + public: + virtual ~SocketAdapter() = default; + + virtual System::native_socket_type get_handle() const = 0; + virtual ::gnutls_session_t get_tls_session() const = 0; + virtual SocketAdapter *copy() const = 0; + + virtual long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const = 0; + + virtual long nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const = 0; + virtual long nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const = 0; + + virtual void close() = 0; + + bool operator ==(const SocketAdapter &obj) const; + bool operator !=(const SocketAdapter &obj) const; + }; +}; \ No newline at end of file diff --git a/src/SocketAdapterDefault.cpp b/src/SocketAdapterDefault.cpp new file mode 100644 index 0000000..12fffd4 --- /dev/null +++ b/src/SocketAdapterDefault.cpp @@ -0,0 +1,49 @@ + +#include "SocketAdapterDefault.h" + +namespace HttpServer +{ + SocketAdapterDefault::SocketAdapterDefault(const Socket &_sock) : sock(_sock) + { + + } + + System::native_socket_type SocketAdapterDefault::get_handle() const + { + return sock.get_handle(); + } + + ::gnutls_session_t SocketAdapterDefault::get_tls_session() const + { + return 0; + } + + SocketAdapter *SocketAdapterDefault::copy() const + { + return new SocketAdapterDefault(this->sock); + } + + long SocketAdapterDefault::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const + { + return sock.nonblock_recv(buf, timeout); + } + + long SocketAdapterDefault::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const + { + return sock.nonblock_send(buf, timeout); + } + + long SocketAdapterDefault::nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const + { + return sock.nonblock_send(buf, length, timeout); + } + + void SocketAdapterDefault::close() + { + // Wait for send all data to client + sock.nonblock_send_sync(); + + sock.shutdown(); + sock.close(); + } +}; \ No newline at end of file diff --git a/src/SocketAdapterDefault.h b/src/SocketAdapterDefault.h new file mode 100644 index 0000000..e3272be --- /dev/null +++ b/src/SocketAdapterDefault.h @@ -0,0 +1,28 @@ +#pragma once + +#include "SocketAdapter.h" +#include "Socket.h" + +namespace HttpServer +{ + class SocketAdapterDefault : public SocketAdapter + { + private: + Socket sock; + + public: + SocketAdapterDefault() = delete; + SocketAdapterDefault(const Socket &_sock); + + virtual System::native_socket_type get_handle() const override; + virtual ::gnutls_session_t get_tls_session() const override; + virtual SocketAdapter *copy() const override; + + virtual long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const override; + + virtual long nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const override; + virtual long nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const override; + + virtual void close() override; + }; +}; \ No newline at end of file diff --git a/src/SocketAdapterTls.cpp b/src/SocketAdapterTls.cpp new file mode 100644 index 0000000..fd576dd --- /dev/null +++ b/src/SocketAdapterTls.cpp @@ -0,0 +1,122 @@ + +#include "SocketAdapterTls.h" + +namespace HttpServer +{ + SocketAdapterTls::SocketAdapterTls(const Socket &sock, ::gnutls_priority_t priority_cache, ::gnutls_certificate_credentials_t x509_cred) + { + ::gnutls_init(&this->session, GNUTLS_SERVER); + ::gnutls_priority_set(this->session, priority_cache); + ::gnutls_credentials_set(this->session, GNUTLS_CRD_CERTIFICATE, x509_cred); + + ::gnutls_certificate_server_set_request(this->session, GNUTLS_CERT_IGNORE); + + ::gnutls_transport_set_int2(this->session, sock.get_handle(), sock.get_handle() ); + } + + SocketAdapterTls::SocketAdapterTls(const ::gnutls_session_t _session) : session(_session) + { + + } + + bool SocketAdapterTls::handshake() + { + int ret; + + do + { + ret = ::gnutls_handshake(this->session); + } + while (ret < 0 && ::gnutls_error_is_fatal(ret) == 0); + + if (ret < 0) + { + Socket sock(this->get_handle() ); + + sock.close(); + ::gnutls_deinit(this->session); + + return false; + } + + return true; + } + + long SocketAdapterTls::nonblock_send_all(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const + { + size_t record_size = ::gnutls_record_get_max_size(this->session); + + if (0 == record_size) + { + return -1; + } + + size_t total = 0; + + while (total < length) + { + ::gnutls_record_set_timeout(this->session, timeout.count() ); + + if (record_size > length - total) + { + record_size = length - total; + } + + const long send_size = ::gnutls_record_send(this->session, reinterpret_cast(buf) + total, record_size); + + if (send_size < 0) + { + return send_size; + } + + total += send_size; + } + + return total; + } + + System::native_socket_type SocketAdapterTls::get_handle() const + { + return reinterpret_cast(::gnutls_transport_get_int(this->session) ); + } + + ::gnutls_session_t SocketAdapterTls::get_tls_session() const + { + return this->session; + } + + SocketAdapter *SocketAdapterTls::copy() const + { + return new SocketAdapterTls(this->session); + } + + long SocketAdapterTls::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const + { + ::gnutls_record_set_timeout(this->session, timeout.count() ); + return ::gnutls_record_recv(this->session, buf.data(), buf.size() ); + } + + long SocketAdapterTls::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const + { + return this->nonblock_send_all(buf.data(), buf.length(), timeout); + } + + long SocketAdapterTls::nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const + { + return this->nonblock_send_all(buf.data(), length, timeout); + } + + void SocketAdapterTls::close() + { + Socket sock(this->get_handle() ); + + // Wait for send all data to client + sock.nonblock_send_sync(); + + ::gnutls_bye(this->session, GNUTLS_SHUT_RDWR); + + sock.close(); + + ::gnutls_deinit(this->session); + } +}; \ No newline at end of file diff --git a/src/SocketAdapterTls.h b/src/SocketAdapterTls.h new file mode 100644 index 0000000..de57147 --- /dev/null +++ b/src/SocketAdapterTls.h @@ -0,0 +1,32 @@ +#pragma once + +#include "SocketAdapter.h" +#include "Socket.h" + +namespace HttpServer +{ + class SocketAdapterTls : public SocketAdapter + { + private: + ::gnutls_session_t session; + + public: + SocketAdapterTls() = delete; + SocketAdapterTls(const Socket &sock, ::gnutls_priority_t priority_cache, ::gnutls_certificate_credentials_t x509_cred); + SocketAdapterTls(const ::gnutls_session_t _session); + + bool handshake(); + long nonblock_send_all(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const; + + virtual System::native_socket_type get_handle() const override; + virtual ::gnutls_session_t get_tls_session() const override; + virtual SocketAdapter *copy() const override; + + virtual long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const override; + + virtual long nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const override; + virtual long nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const override; + + virtual void close() override; + }; +}; \ No newline at end of file diff --git a/src/Test.cpp b/src/Test.cpp index 04127ed..e9f8dd1 100644 --- a/src/Test.cpp +++ b/src/Test.cpp @@ -88,7 +88,7 @@ bool test(HttpServer::ServerRequest &request, HttpServer::ServerResponse &respon s += R"( )"; - HttpServer::Socket &socket = response.socket; + HttpServer::SocketAdapter &socket = response.socket; std::map &headers_outgoing = response.headers; // Set outgoing headers @@ -116,10 +116,10 @@ bool test(HttpServer::ServerRequest &request, HttpServer::ServerResponse &respon // Send headers and page - std::chrono::milliseconds timeout(5000); + const std::chrono::milliseconds timeout(5000); socket.nonblock_send(headers, timeout); socket.nonblock_send(s, timeout); return EXIT_SUCCESS; -} +} \ No newline at end of file diff --git a/src/Utils.cpp b/src/Utils.cpp index a833299..6806969 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -396,7 +396,7 @@ namespace Utils { std::string encoded; - static const std::array hexDigits { "0123456789abcdef" }; + static const std::array hexDigits { "0123456789ABCDEF" }; for (size_t i = 0; i < str.length(); ++i) { @@ -436,14 +436,12 @@ namespace Utils { if (i + 2 < str.length() ) { - const char a = str[i + 1]; - const char b = str[i + 2]; + const char a = str[++i]; + const char b = str[++i]; c = ( (hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b) ); - - i += 2; } } else if ('+' == c) From 3f5a075b47f62208efc5dccbfa674c5eaed4d58e Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Tue, 26 Apr 2016 22:02:32 +0300 Subject: [PATCH 11/31] Added support of HTTPS for Windows --- README.md | 15 ++++++-- projects/msvs/httpserverapp.v12.suo | Bin 150016 -> 0 bytes projects/msvs/httpserverapp.vcxproj | 40 +++++++++++++++----- projects/msvs/httpserverapp.vcxproj.filters | 18 +++++++++ projects/msvs/httpserverapp.vcxproj.user | 13 ++++++- src/Socket.cpp | 4 +- src/Socket.h | 8 +--- src/SocketAdapterTls.cpp | 2 +- src/System.cpp | 8 ++-- src/System.h | 1 + src/Utils.cpp | 12 +++--- 11 files changed, 90 insertions(+), 31 deletions(-) delete mode 100644 projects/msvs/httpserverapp.v12.suo diff --git a/README.md b/README.md index 51fda94..2aa6944 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,9 @@ Common: * [gnutls](https://www.gnutls.org/) -Linux: +Linux: `dl`, `pthread`, `gnutls` -* dl -* pthread +Windows: `ws2_32.lib`, `libgnutls.dll.a` Build ----- @@ -28,6 +27,16 @@ cd build qbs build -f ./../projects/qt-creator/httpserverapp.qbs release ``` +Windows: + +```sh +git clone https://github.com/awwit/httpserverapp.git +cd httpserver +mkdir build +cd build +devenv ./../projects/msvs/httpserverapp.sln /build +``` + License ======= diff --git a/projects/msvs/httpserverapp.v12.suo b/projects/msvs/httpserverapp.v12.suo deleted file mode 100644 index 135eab33b3fb1ef181163b529078838f53547f41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 150016 zcmeHw37lP3eg6$nHUU8qBPfJb5fWyyhfQWO31NwWBqWGW!mL@CjhV?xSVTZXL8J(Z zK>-mdbwQ=56j5olu0^bStJZF|w*70Z+SXS2f4}#_e=IRUY}|_PYzC!{qg%0jNd-{?6Z7} z&tHo15)8bw=kYs0ffdOJ{!Jv)lf}s}evT#EuzK}B4ojZ9YpqRQ@qNR+A363lXPy4c zlq2!xwPX@JF2IZ<$;RXy%szl;i<7PDjXM87EZJ+<{3Lfhf7Xu=fqm1*s-!y^PcBc+ zPd4D^L~;@S?*}G%eZ2a)(2wJiy{5bjZ^}}KK4-rE8vL?v^@TNb3!<5-O2FpkGK z0psNuufRAFs3o zXJWhx<1CC0j82S27+n~PF_vJQjj$l3XGK)t1vFY zSdFm;gLLLvUxM*kj0(o=jZmR{-pf#cT@KHyHEa~kI#zC z^E2{%kNmfW{BsRCredAsIe&7kxz5z#^z*p3v<1Q!Tvy5vKl=jwB+nd*@gj`FFvw37 z@t0s6j&TGAeM8zx+JFAtbo`u*{-?gD{^xhiuKvu^|NNW`>VG~r^*?pFssH)D=zl&J z{mUp|MIqCZx`k_^IXOu*8Nz_Kh#|EC|w z*O$Y_$UC$!?qg;X{?~KxHRLTmMF0200!~01j{yt)F!2Y+VDY+lVNic#{@>Qb{G_*h z$7)>h^b87lub!XqKc`H=2g%!9yn6m-FMNnLoR8%x?FUm&kKW!ocoGxo75Bp**^t_H z^-2H#^gm6e@qfyG^(g#0>lf;^E_fV0z_70Bbt-?9D=>n&`{5sr;@`5AD>hVLHNOr1 zXL{Y#AN5}U>G&*pfDc)J`u(HeI5q2-K?U`>(EqspRQFKd)H^@z+2^=ucyQhcT;~{Q z-;Mc~faZhveS8-(#hD@({rKF3;e($#N&f4?759Sv^z8Y~W;}2K-Wvy=JP8Efc)P*UAT+Fv29oZP1B5=~~p7e+qpG`knR4zsY~u`Iq5(hcGMiV5Tk(Ny5qCzhf~sec^iN zKNFw58iSAQ{GFJ&AM1WOtl>zy7PK}d67_fT{~WA8^*Md>dgng_pB4X0e9t}pzslv5 z<^T6$O_=|Y^-$V;_y1qp{488hyKiSh91!W z>AI8le1tw{zTSgh-XJejzt5>mU)qK8Y{f}CRG^TV_*xGm(1Z8aWXZtT!Le(?-HUS0B zs$?kdCdgR-F?F@PUhAjiziRtm?P*U@==&u8m)?ia=gil;@XJ%x7wVax{Y;^U%zrdK zKstmzXTH7^zdTxffq6r&N3)NgEnA-im`5Gnz3>@N^a11m zz%dS9@~Po-_dWTF+i#e<^NL3=-?YL9uQt(*PfYAy{C&`egQ;<6Sx=&(fuG*@@q4!a zbo~$CyJ0m}X;tb245rn#t?&RCTy2IbtyTNu#WVl)0{oOq;%l`YYw!W)toX>*zt(`* zwEgRWqL%IF-%rQ<>@TDKAO^lx>#-UipswK~JHNmFratTYpZ1qMaYtg*JO3(tcCh+o z+4))TCf#fGT~+@aeHSYKNh@6M{44QU@qhN%f1zY^Kg+iN1C!Jr+WsTQS~>aT~_lFmA_S zKgS&yZ^yU`gBpyD(eX6do|&4ZK&#mQGOrJA*uqm~1s- z^EULD&P@N$`*tjOntx0sijk{{Vtvfe=ReW2MH4UNlde1&ZVOzN?HK=Yew7QpUu zNW*C12-O}V&d7}DIB3$H>PDG$VaYPMC|#?GYA>A0*RKXL?g^xJkZu58LkIXzwFmJz z8!bdyD(UV8N2-j45|gU_{LuRgQA>UExZV5TM^N0{^B!q*_Akp#C$ zd7j+UqEPPHVxnd2Wx#t`;dsqr7PVnJM&E9oMY!?!s5-;cWz-s3E1=?zSoX<8(*@6_ zg0mjjlWFSIKPinq%b~TX_s0zG>jC%OS~y?SD=lmlq&DTbCCpkYYsmce=7^X&4SFzM zy*t|6F2DHv8IyZH1$?(f!{^#Szh!Zac-Axd zznYUf>!`OxUroo_-dOm&Aswo@zXOQqgZ8Fgh0>kOqdgW4OYL>@M?Lo1iH!Uiu*cKA zu5MF%m$`R@UK)4NuESs#nWF8v;IEz_ZEH6i>sDj6Q$+1jxd5`qs7u*p`fB$?waF%y z3Xs?lHgzg7J%}+7y!K|}e7`)+#$4|xe6HH^B)*zj5hYpFFI*q3$^RPYu8W4w_7G@W zMC<%LaFk);*lol8M(Uh7O_x`JYafb67gu_Ho|Ati$uYFV=IN$f?xg8fbM5EALE1<`>;G0zZrns8Bk}oOb z+s!CKYaBL_T-(t1i$>1#xI)@mYeJD?b(I%_&+aS%g{|*stLay4fzQo6mBO~Q#biLm zp(<}hkA0#V6G|K^dU_Rb$IH{`l_j4^wFi-JOen@7R#Z}kWiFwPcbjs-hJnxD7nzR=AGLV(&x3K4#8C;(JMc&Is zPUO6Q!6-AfC-qn{BF=4|N)-#}4@A>}VrA;78m&S6O-&jJVJC>^1i-1)g{- zt2LdC$F&}!i3fo1{%9-fdd%9d^Gk=|+zy;PL!_u$>1=ep%tptHu9f;WxTEt9^M-5I z^<=et`nys+ha{Bax*M~`vyXO;E4xPHI89yY_=ljS;>lJPM+JIGSLmoUuLPCiX?87J zJULcs7#fpMQT64B-M=0fCxY_TJpZf&hIP=^#4(Pu^p%BS)G6`NU6?tZ=Bcf-vzq#! zv4Zhxt9GW)*VRLgVqb1KmAX)$7Q2GuQOT7#?Y(H5_V2*-NRX#}`ff6DS#8epS5dP3 zb|~Z_9%`48e8txvm2dY>1L|;0Qjh+S18Ce>VP}hJh*j`CM-2_O7JRlN8lQ1}u1LEO z*>j;R-h3b^K5BEL!(%YdSE601D^bhRzDw4S^E$K`J=4N4!czRLqG$crT1R{yR}@c^ zn)##bI*JE52izXdTTt{ddvUd=;FoyXpKE||GTx@>*->~(p*`c-P1i|sA7+ggyK6sc zDfo!TPF3KGkEMvm@O&)%`RoL*FxzEp1)RR|7|t{VpmAWT{|$Yj;3X@ z5}>HW-C?cQITO-s3iB1fd>gc$?&9Zpmb_n>+4Mghr|xXU?umK0s}}2?>^z|qvLk;0 ze9nCv?2g`)`s~xu#XW)Ntg?;Zz4kN~ZNp#ko*5OqI*h;Py+hcOSiv{*9tK1BEPLd6 zHp3>2GP=*rZg{Ql{}yQCRf#0lVhrT(%24#<38dWXP;`fDmbY2;=W%-6Ibh$_MN^39 zY7~zol$q69R{AzHlD{emiJ5&@lJ#C7d9?7=3DLy$d$O-6zT!Orb>AfARPAQyg;f%7 z;&LE=qD17{=W;zZ`zqL}#ae{^3q|{WT*1B3t{^Khk^v)aRmR@7S3>8n0A;*Pn2XY{ z?Y<3E@#^_5D!$^2B^Sd&u-|47`$iN8Z?5t#dotC!pAJ7Io*wecqC#>8sJOjw4$M-^ z?P?I-ItlYXUikd}D|V%nJ_2{U`J*mdhSknJ{dq;d4Zt67CACGdWrCii+OJ-;l?_qS zw*FZiu66Vmfh=C-KFfC%)JCQ9XX`dn>=zhibVaMaU3y2FPTWyjW@K#Fs&t%eR&h51 z#WC)le$jd8dWzW_5lsTRv-`CLG{#o75t8CuzP|UQdkeRYO z759m{npxedGwo_M7XeK?3uM-Cw3bjvdcjv^`r}zj`RuoN;(qSz0WITsx+X2vUd#?y zE4^Pvv=vXGY0V6r*=449fTy9x({x##!-z)p_b4>y15Ld345P92Zw090RfVw)V74f%WZc(tMUH;c>7E%>|--tU;`w-Q0SA;> zeKBh<>Lk8+Hq^E3%dv`mh={~O^ro6mOUWldv3Qn2P{{dHV&gTQEm7^JtxZ(d3%Oo& z$eVzs*iKTOoi+zE$f-O2PSUqx-tfMkMml-SD^&S~ambCi3-{faYchQV;kZ}tYdAlx zX0lU8DEoHIx<05=>bXK+jBiKVdbT?-TN(SH^Sc&=7PkOhE9qCCMNpQ2_X{ku4rFGN z!<{ia6*XQoW$U!CANNYEa`D-$klok1jK1wG%-u>^Ti)q2yC3&#U|b#42!3hzziR7L zUO$h2jA!MtK9{n}=I*h@z!NW1;(7&k{>Cp!qMg1J6>FAuuD`1DiuQRsT<3$pLyheM z4O=f-$<3*)^vjr=nG=e=1W4kYYmr@DZS`IS93O2+qKb_)bPY0Z72Vw2{#eC$c^$34 z?b?!?cOr+a1GYz^(NtqI_mOmt&EtMF<%EN zs(TUs9gxPWiktLPHi}hB;jn)ImNN61TK+Yr9pL(S{c=TUDxv0$Kt2}KRz9Ck^i$q@ zOH%&qPiSv?p+D8Bx#r1&Jd=EP?BFnOhD;lBTvX0o1X{AQn7VreGSr7>noB+mEDse< z>yA{~>p68?W#XCt9s#~>fqn1789xEqi6GkAb}Z!WiPdC}us=)kF7RZyAE5b}Rh(va z*xZSkTCeNf^wN~|HRG9;z+8?k3som5XZrxv&LFqs>59DfLcCo&ayb_~zQO9I`X``_ zS3AjiP2mXUG~g=7wz_@a?*o>`V!C>)L1-08BeO$CG|vK{DCTq|vr9+5ecw{~KxIvJ z7rV9&Uk9$oT1bL)>>t)gLem2w{qgul`#*XQ1$EH7FydvNGzvSzqgV91z*DBDYRA|r ztK5Z^ioMq?d-5>v>>aMS`0PQ*m#FP$9)!8#<%cv+m{9_G^E%MIb*dtB5DU&VJkvJ= zUA$U@9pCZH2U~*79E<5c?+27cWvz9_QOO1GqF5W=+cv~_-bEnXWUF6jo1HDKT>}cgtR?1swT?D5!&Z5 z`9NKl8H1e%q-A&-jGgs)aN5(D3aYhU9BbB$TpAt%%<;N)e3seIh2qn`KC0|wIWez_ z!wwH-)Y#*}7?=BBDLd1FxJ-Xjt+DPiBBo(rx+9vV*Q>k~)N#+S5Wk1WZU(Y=9+|5f z&FI_J-1hmfbt=2N()BN%0_sl=o9dWuH*D$vE#crM4;@t}K>{H2hHc>6T`Ss`uH&IGlJkKD3U zF;9r_^VG?}QKnY4V!w2-{2oW6ZNLwHw}$iruG74hN{v+m$pS4G$N15p`% zoq5g@Z4|p!sn71gh?ldrDU_8IGZOy-aFtofBDUHQknq_l&};WclNRlRn0+KVA0$-P zT_b|?2H-66zN4MU@hnOG0e=THIqX)<8L$7x&HUu`N8AW}@v7>zy%L|6^V^IHkcTUn zz6@tQb(F>e$I^S@^cK&l#H}?kH6@d z?*M5To{{X`HhT>z=@&z8;@R}9FO;p~`d67a-+-|_sPTN3AXMujSLJs}kK=3$%DCAr zcL3&ZyoSJU;faX)E~V_EER)`L6cncS?Z6o?hIRQuG5|^w-3>JH>S|#$etL;){{>K9 z*AS129rp3Byw?%vOVj>wcBlGpfFoX{?fRm+ze#&6$3V}NgUOe{R9y9L(COT!>Vm_F zFU&I()%RVD@4LQ)^AaWwaa&Q zU*?8X_bPh)6v*ObNVH_yh_+#ML{~fq^6+ppUTMU`HoKHG-seU26B@y5*OU(i&NAb0 zt^0JQLiQ;f3v6ZR2l4&%YF+>&@p>h-JZPF|EN>_Y3nL-3223w=FJLKNPw?yqb=OhG zmS;mR(R#4j)QeqEdSB@h=u&nxj^I7&3L<(g5S6(fE-Q)ZJkM}NTJ+lsS`xQ;s=e~^ z#5Wh*M*(-d{%hBU+5UO9gNq!oFA%m;HcxRxsJ^%&&8{e39s~N#L7P{9)@l^;5xVV8mdeQ@qP|2ywJ@{q6ddLgbf-rn`BjQVms_9@@wqtzILg;T`Vbt+%h zUe#suu?F{6_vvXn$*#q|YA%h>x#v!F%=-+i#b5TP zeShoVpHj!JO>=k?cuv0HUs3z=|Fx(N%}wu1u(q1prr z=QaBHN={v}`Af7ZyD!VE)N6mkw6ogxxEk~f?*S@CBh}I$jNDi~=WbEOf%gJcyd0rx zgS2cay}fs7cxY9+A;rDW-Fnsj2we4K;hHOyXAxZ#zFTXaT(D<%G`$y!zQ+P3c^o5N ze$8CtHK1t^Fmv+IiU%x;010ai6xp%d(is0pLn3@Ow1GwVJsEdns zk@`t`(@%hmmZ@nq9>1nN5%|i8IBjdHxcwYpxvX&gVOEtX;g6&vbbdviRmgj9_h>22 z*PDSl9v{`#t-21b*6ww{_e9}qS3gyCjnwUZ(pah2#& z{YB}!2=BY&Z12ZxjnzE6Vb>WSHO?utFlHpn`A@`PEau-g<(tDlvzCznFiXMv{yi1aulgP!i1F!met+(3Kv;%9XUl-%uFc^4us>H@ zD~Gg}-fu~5_zuicrst8Bx4fv+pN(0EtB4nKx?E+`a~aSyW?kyBZsc6)?jeG#O*;y+ zwo*MsYfZE6s%R&*33A^7;Jz|#kL?xNI)V6>0AIY?rtLo}z7oIjrb%i8;WF{j>~jOf z7kCJ>w9?M&`l>L3{?k~oGP}@p$5MVr)xQE~Uqc?Kte($1mG^vl;Z)3Y2l9;C*NuN} z!2mi1htmqMx<3H3PDyeEM!Y!4)!Njk<~ci*_Ny=+FMM4((&$C)=TO;Fp1mOF?wj|T zCraA&arjX@o09i+;%95!A5{4N3`lR8Sw&l$Y7c%fa24-WsSL!0sHO2#3r2{&DYZyj zdFHP1QmpZ{(bhPdm6nzII8b~(8j7rs#SXc~?qRCxmG<3;F;{%)RTrERxpn-vqjN zF_@X%%Gw;#Y6I*|yj};L0nv4NzyC*U*8&^4S$kyWsZF(`dXXXVQN~VW2wCjAFwK3SAh^!wZ!j1G;!Tq|uoYr}VbmHBgY91n!PU zw=6%axZJN3XunSex_C7oTlVN9+7)G?SzA;sm8F@#;(0o#wL7w0-PqTzZ9Lbc4WrBm z)b>H?``LF%CdPiO&!Rn6+M-c&q_K@WH?cw*dZ}%Qxj2Gi; z-m^0!5?{U^RC}aw?G%b%vKrLQM=6bK@1M5o)m-OpjN!sj=l5Hkf;r>$z?spNx@)

-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 L2l2T9&sF|^TVvuS diff --git a/projects/msvs/httpserverapp.vcxproj b/projects/msvs/httpserverapp.vcxproj index 63c072c..f50dbce 100644 --- a/projects/msvs/httpserverapp.vcxproj +++ b/projects/msvs/httpserverapp.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -22,6 +22,9 @@ + + + @@ -33,6 +36,9 @@ + + + @@ -46,26 +52,26 @@ DynamicLibrary true - v120 + v140 MultiByte DynamicLibrary true - v120 + v140 MultiByte DynamicLibrary false - v120 + v140 true MultiByte DynamicLibrary false - v120 + v140 true MultiByte @@ -89,35 +95,45 @@ true ..\..\build\$(Platform)\$(Configuration)\ ..\..\build\$(Platform)\$(Configuration)\ + D:\usr\include;$(IncludePath) + D:\usr\lib;$(LibraryPath) true ..\..\build\$(Platform)\$(Configuration)\ ..\..\build\$(Platform)\$(Configuration)\ + D:\usr\include;$(IncludePath) + D:\usr\lib64;$(LibraryPath) false ..\..\build\$(Platform)\$(Configuration)\ ..\..\build\$(Platform)\$(Configuration)\ + D:\usr\include;$(IncludePath) + D:\usr\lib;$(LibraryPath) false ..\..\build\$(Platform)\$(Configuration)\ ..\..\build\$(Platform)\$(Configuration)\ + D:\usr\include;$(IncludePath) + D:\usr\lib64;$(LibraryPath) NotUsing Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPSERVERAPP_EXPORTS;%(PreprocessorDefinitions) + WIN32;DEBUG;%(PreprocessorDefinitions) $(IntDir)asm\ $(IntDir)obj\ true + -Dssize_t=long %(AdditionalOptions) Windows true + ws2_32.lib;libgnutls.dll.a;%(AdditionalDependencies) @@ -125,14 +141,16 @@ NotUsing Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPSERVERAPP_EXPORTS;%(PreprocessorDefinitions) + WIN32;DEBUG;%(PreprocessorDefinitions) $(IntDir)asm\ $(IntDir)obj\ true + -Dssize_t=long %(AdditionalOptions) Windows true + ws2_32.lib;libgnutls.dll.a;%(AdditionalDependencies) @@ -142,16 +160,18 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;NDEBUG;%(PreprocessorDefinitions) $(IntDir)asm\ $(IntDir)obj\ true + -Dssize_t=long %(AdditionalOptions) Windows true true true + ws2_32.lib;libgnutls.dll.a;%(AdditionalDependencies) @@ -161,16 +181,18 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;NDEBUG;%(PreprocessorDefinitions) $(IntDir)asm\ $(IntDir)obj\ true + -Dssize_t=long %(AdditionalOptions) Windows true true true + ws2_32.lib;libgnutls.dll.a;%(AdditionalDependencies) diff --git a/projects/msvs/httpserverapp.vcxproj.filters b/projects/msvs/httpserverapp.vcxproj.filters index e85b8eb..ba8f20d 100644 --- a/projects/msvs/httpserverapp.vcxproj.filters +++ b/projects/msvs/httpserverapp.vcxproj.filters @@ -33,6 +33,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + @@ -62,5 +71,14 @@ Header Files + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/projects/msvs/httpserverapp.vcxproj.user b/projects/msvs/httpserverapp.vcxproj.user index ef5ff2a..deabe1c 100644 --- a/projects/msvs/httpserverapp.vcxproj.user +++ b/projects/msvs/httpserverapp.vcxproj.user @@ -1,4 +1,15 @@  - + + + + $(ProjectDir) + WindowsLocalDebugger + + + + + $(ProjectDir) + WindowsLocalDebugger + \ No newline at end of file diff --git a/src/Socket.cpp b/src/Socket.cpp index a9f40b9..ead8bb4 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -284,7 +284,7 @@ namespace HttpServer while (total < length) { - const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, length - total, 0); + const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, length - total, 0); if (send_size < 0) { @@ -322,7 +322,7 @@ namespace HttpServer { if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLWRNORM) { - const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, length - total, 0); + const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, length - total, 0); if (send_size < 0) { diff --git a/src/Socket.h b/src/Socket.h index 4097cdd..fb7eecc 100644 --- a/src/Socket.h +++ b/src/Socket.h @@ -1,10 +1,6 @@ #pragma once -#ifdef WIN32 - #include - #pragma comment(lib, "ws2_32.lib") - #undef max -#elif POSIX +#ifdef POSIX #include #include #include @@ -13,8 +9,6 @@ #include #include #include -#else - #error "Undefine platform" #endif #include "System.h" diff --git a/src/SocketAdapterTls.cpp b/src/SocketAdapterTls.cpp index fd576dd..4d2f819 100644 --- a/src/SocketAdapterTls.cpp +++ b/src/SocketAdapterTls.cpp @@ -77,7 +77,7 @@ namespace HttpServer System::native_socket_type SocketAdapterTls::get_handle() const { - return reinterpret_cast(::gnutls_transport_get_int(this->session) ); + return static_cast(::gnutls_transport_get_int(this->session) ); } ::gnutls_session_t SocketAdapterTls::get_tls_session() const diff --git a/src/System.cpp b/src/System.cpp index 7e397aa..636f4cd 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -72,7 +72,7 @@ namespace System #ifdef WIN32 std::array buf; - const size_t len = ::GetTempPath(buf.size(), buf.data() ); + auto const len = ::GetTempPath(buf.size(), buf.data() ); #ifdef UNICODE std::wstring_convert> converter; @@ -196,9 +196,11 @@ namespace System *fileSize = attrib.st_size; - struct ::tm *clock = ::gmtime(&(attrib.st_mtime) ); + struct ::tm clock = {}; + + ::gmtime_r(&(attrib.st_mtime), &clock); - *fileTime = ::mktime(clock); + *fileTime = ::mktime(&clock); return true; #else diff --git a/src/System.h b/src/System.h index d16896b..c1c2865 100644 --- a/src/System.h +++ b/src/System.h @@ -1,6 +1,7 @@ #pragma once #ifdef WIN32 + #include #include ::TCHAR myWndClassName[]; diff --git a/src/Utils.cpp b/src/Utils.cpp index 6806969..86003bb 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -287,7 +287,7 @@ namespace Utils { tc.tm_year -= 1900; - auto it_mon = map_months.find(s_mon.data() ); + auto const it_mon = map_months.find(s_mon.data() ); if (map_months.cend() != it_mon) { @@ -321,12 +321,14 @@ namespace Utils // RFC 822 ::strftime(buf.data(), buf.size(), "%a, %d %b %Y %H:%M:%S GMT", &stm); #else - struct ::tm *ptm = isGmtTime ? - ::localtime(&cur_time) : - ::gmtime(&cur_time); + struct ::tm stm = {}; + + isGmtTime ? + ::localtime_r(&cur_time, &stm) : + ::gmtime_r(&cur_time, &stm); // RFC 822 - ::strftime(buf.data(), buf.size(), "%a, %d %b %G %H:%M:%S GMT", ptm); + ::strftime(buf.data(), buf.size(), "%a, %d %b %G %H:%M:%S GMT", &stm); #endif return std::string(buf.data() ); From 1a179e871e9d0c96d84dbe52181c7815cf5cf25a Mon Sep 17 00:00:00 2001 From: awwit Date: Tue, 31 May 2016 14:48:17 +0300 Subject: [PATCH 12/31] Fixed some warnings from code --- src/SocketAdapterTls.cpp | 4 ++-- src/System.h | 3 +++ src/Utils.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/SocketAdapterTls.cpp b/src/SocketAdapterTls.cpp index 4d2f819..b26903d 100644 --- a/src/SocketAdapterTls.cpp +++ b/src/SocketAdapterTls.cpp @@ -55,7 +55,7 @@ namespace HttpServer while (total < length) { - ::gnutls_record_set_timeout(this->session, timeout.count() ); + ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); if (record_size > length - total) { @@ -92,7 +92,7 @@ namespace HttpServer long SocketAdapterTls::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const { - ::gnutls_record_set_timeout(this->session, timeout.count() ); + ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); return ::gnutls_record_recv(this->session, buf.data(), buf.size() ); } diff --git a/src/System.h b/src/System.h index c1c2865..87d0fac 100644 --- a/src/System.h +++ b/src/System.h @@ -3,6 +3,9 @@ #ifdef WIN32 #include #include + #undef min + #undef max + ::TCHAR myWndClassName[]; #ifdef SIGTERM diff --git a/src/Utils.cpp b/src/Utils.cpp index 86003bb..525a216 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -280,7 +280,7 @@ namespace Utils // Parse RFC 822 #ifdef WIN32 - if (~0 != ::sscanf_s(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon.data(), s_mon.size(), &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) ) + if (~0 != ::sscanf_s(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon.data(), static_cast(s_mon.size() ), &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) ) #else if (~0 != ::sscanf(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon.data(), &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) ) #endif From 69a17c36b02eabe7b1c4521fcd3e2f2e84a6f81b Mon Sep 17 00:00:00 2001 From: awwit Date: Thu, 30 Mar 2017 23:05:59 +0300 Subject: [PATCH 13/31] Categorize source code files. Add HTTP/2 protocol support --- README.md | 12 +- projects/qt-creator/httpserverapp.qbs | 98 +- src/FileIncoming.cpp | 36 - src/FileIncoming.h | 41 - src/Init.cpp | 258 + src/Init.h | 14 + src/Main.cpp | 93 +- src/Main.h | 11 +- src/RawData.h | 20 - src/ServerRequest.h | 54 - src/ServerResponse.h | 23 - src/Socket.h | 103 - src/SocketAdapter.cpp | 15 - src/SocketAdapter.h | 32 - src/SocketAdapterDefault.cpp | 49 - src/SocketAdapterDefault.h | 28 - src/SocketAdapterTls.cpp | 122 - src/SocketAdapterTls.h | 32 - src/Test.cpp | 125 - src/Test.h | 10 - src/Utils.cpp | 459 -- src/Utils.h | 74 - src/application/Test.cpp | 147 + src/application/Test.h | 9 + src/client/Request.cpp | 54 + src/client/Request.h | 50 + src/client/Response.cpp | 29 + src/client/Response.h | 25 + src/client/protocol/ClientHttp1.cpp | 29 + src/client/protocol/ClientHttp1.h | 15 + src/client/protocol/ClientHttp2.cpp | 186 + src/client/protocol/ClientHttp2.h | 23 + src/client/protocol/ClientProtocol.cpp | 20 + src/client/protocol/ClientProtocol.h | 24 + src/socket/Adapter.cpp | 25 + src/socket/Adapter.h | 33 + src/socket/AdapterDefault.cpp | 44 + src/socket/AdapterDefault.h | 26 + src/socket/AdapterTls.cpp | 136 + src/socket/AdapterTls.h | 30 + src/socket/List.cpp | 383 ++ src/socket/List.h | 43 + src/{ => socket}/Socket.cpp | 146 +- src/socket/Socket.h | 79 + src/{ => system}/System.cpp | 122 +- src/{ => system}/System.h | 47 +- src/transfer/AppRequest.h | 23 + src/transfer/AppResponse.h | 13 + src/transfer/FileIncoming.cpp | 108 + src/transfer/FileIncoming.h | 40 + src/transfer/HttpStatusCode.h | 52 + src/transfer/ProtocolVariant.h | 11 + src/transfer/http2/HPack.cpp | 6038 ++++++++++++++++++++++++ src/transfer/http2/HPack.h | 15 + src/transfer/http2/Http2.cpp | 182 + src/transfer/http2/Http2.h | 191 + src/utils/Event.cpp | 102 + src/utils/Event.h | 33 + src/utils/Utils.cpp | 841 ++++ src/utils/Utils.h | 137 + 60 files changed, 9786 insertions(+), 1434 deletions(-) delete mode 100644 src/FileIncoming.cpp delete mode 100644 src/FileIncoming.h create mode 100644 src/Init.cpp create mode 100644 src/Init.h delete mode 100644 src/RawData.h delete mode 100644 src/ServerRequest.h delete mode 100644 src/ServerResponse.h delete mode 100644 src/Socket.h delete mode 100644 src/SocketAdapter.cpp delete mode 100644 src/SocketAdapter.h delete mode 100644 src/SocketAdapterDefault.cpp delete mode 100644 src/SocketAdapterDefault.h delete mode 100644 src/SocketAdapterTls.cpp delete mode 100644 src/SocketAdapterTls.h delete mode 100644 src/Test.cpp delete mode 100644 src/Test.h delete mode 100644 src/Utils.cpp delete mode 100644 src/Utils.h create mode 100644 src/application/Test.cpp create mode 100644 src/application/Test.h create mode 100644 src/client/Request.cpp create mode 100644 src/client/Request.h create mode 100644 src/client/Response.cpp create mode 100644 src/client/Response.h create mode 100644 src/client/protocol/ClientHttp1.cpp create mode 100644 src/client/protocol/ClientHttp1.h create mode 100644 src/client/protocol/ClientHttp2.cpp create mode 100644 src/client/protocol/ClientHttp2.h create mode 100644 src/client/protocol/ClientProtocol.cpp create mode 100644 src/client/protocol/ClientProtocol.h create mode 100644 src/socket/Adapter.cpp create mode 100644 src/socket/Adapter.h create mode 100644 src/socket/AdapterDefault.cpp create mode 100644 src/socket/AdapterDefault.h create mode 100644 src/socket/AdapterTls.cpp create mode 100644 src/socket/AdapterTls.h create mode 100644 src/socket/List.cpp create mode 100644 src/socket/List.h rename src/{ => socket}/Socket.cpp (65%) create mode 100644 src/socket/Socket.h rename src/{ => system}/System.cpp (58%) rename src/{ => system}/System.h (64%) create mode 100644 src/transfer/AppRequest.h create mode 100644 src/transfer/AppResponse.h create mode 100644 src/transfer/FileIncoming.cpp create mode 100644 src/transfer/FileIncoming.h create mode 100644 src/transfer/HttpStatusCode.h create mode 100644 src/transfer/ProtocolVariant.h create mode 100644 src/transfer/http2/HPack.cpp create mode 100644 src/transfer/http2/HPack.h create mode 100644 src/transfer/http2/Http2.cpp create mode 100644 src/transfer/http2/Http2.h create mode 100644 src/utils/Event.cpp create mode 100644 src/utils/Event.h create mode 100644 src/utils/Utils.cpp create mode 100644 src/utils/Utils.h diff --git a/README.md b/README.md index 2aa6944..074e3e8 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ -httpserverapp -============= +# httpserverapp Sample application for [C++ http server](https://github.com/awwit/httpserver). -Dependencies ------------- +## Dependencies Common: @@ -14,8 +12,7 @@ Linux: `dl`, `pthread`, `gnutls` Windows: `ws2_32.lib`, `libgnutls.dll.a` -Build ------ +## Build Linux: @@ -37,8 +34,7 @@ cd build devenv ./../projects/msvs/httpserverapp.sln /build ``` -License -======= +# License The source codes are licensed under the [MIT](https://opensource.org/licenses/MIT), diff --git a/projects/qt-creator/httpserverapp.qbs b/projects/qt-creator/httpserverapp.qbs index 106d708..f919cab 100644 --- a/projects/qt-creator/httpserverapp.qbs +++ b/projects/qt-creator/httpserverapp.qbs @@ -1,49 +1,67 @@ import qbs Project { - DynamicLibrary { - name: "httpserverapp" + DynamicLibrary { + name: "httpserverapp" - Depends { name: "cpp" } - cpp.cxxLanguageVersion: "c++11" + Depends { name: "cpp" } + cpp.cxxLanguageVersion: "c++14" - cpp.defines: qbs.buildVariant == "debug" ? base : base.concat(["DEBUG"]) + cpp.defines: qbs.buildVariant == "debug" ? ["DEBUG"] : base - cpp.dynamicLibraries: base.concat(["gnutls"]) + cpp.dynamicLibraries: ["gnutls"] - Properties { - condition: qbs.targetOS.contains("linux") - cpp.defines: outer.concat(["POSIX"]) - cpp.dynamicLibraries: outer.concat(["dl", "pthread"]) - } + Properties { + condition: qbs.targetOS.contains("linux") + cpp.defines: outer.concat(["POSIX"]) + cpp.dynamicLibraries: outer.concat(["dl", "pthread"]) + } + Properties { + condition: qbs.targetOS.contains("windows") + cpp.defines: outer.concat(["WIN32", "NOMINMAX"]) + } - Properties { - condition: qbs.targetOS.contains("windows") - cpp.defines: outer.concat(["WIN32"]) - } - - files: [ - "../../src/FileIncoming.cpp", - "../../src/FileIncoming.h", - "../../src/Main.cpp", - "../../src/Main.h", - "../../src/RawData.h", - "../../src/ServerRequest.h", - "../../src/ServerResponse.h", - "../../src/Socket.cpp", - "../../src/Socket.h", - "../../src/SocketAdapter.cpp", - "../../src/SocketAdapter.h", - "../../src/SocketAdapterDefault.cpp", - "../../src/SocketAdapterDefault.h", - "../../src/SocketAdapterTls.cpp", - "../../src/SocketAdapterTls.h", - "../../src/System.cpp", - "../../src/System.h", - "../../src/Test.cpp", - "../../src/Test.h", - "../../src/Utils.cpp", - "../../src/Utils.h", - ] - } + files: [ + "../../src/Init.cpp", + "../../src/Init.h", + "../../src/application/Test.cpp", + "../../src/application/Test.h", + "../../src/client/protocol/ClientHttp1.cpp", + "../../src/client/protocol/ClientHttp1.h", + "../../src/client/protocol/ClientHttp2.cpp", + "../../src/client/protocol/ClientHttp2.h", + "../../src/client/protocol/ClientProtocol.cpp", + "../../src/client/protocol/ClientProtocol.h", + "../../src/utils/Event.cpp", + "../../src/utils/Event.h", + "../../src/transfer/FileIncoming.cpp", + "../../src/transfer/FileIncoming.h", + "../../src/transfer/http2/HPack.cpp", + "../../src/transfer/http2/HPack.h", + "../../src/transfer/http2/Http2.cpp", + "../../src/transfer/http2/Http2.h", + "../../src/transfer/HttpStatusCode.h", + "../../src/Main.cpp", + "../../src/Main.h", + "../../src/client/Request.cpp", + "../../src/client/Request.h", + "../../src/client/Response.cpp", + "../../src/client/Response.h", + "../../src/transfer/ProtocolVariant.h", + "../../src/transfer/AppRequest.h", + "../../src/transfer/AppResponse.h", + "../../src/socket/Socket.cpp", + "../../src/socket/Socket.h", + "../../src/socket/Adapter.cpp", + "../../src/socket/Adapter.h", + "../../src/socket/AdapterDefault.cpp", + "../../src/socket/AdapterDefault.h", + "../../src/socket/AdapterTls.cpp", + "../../src/socket/AdapterTls.h", + "../../src/system/System.cpp", + "../../src/system/System.h", + "../../src/utils/Utils.cpp", + "../../src/utils/Utils.h", + ] + } } diff --git a/src/FileIncoming.cpp b/src/FileIncoming.cpp deleted file mode 100644 index 1526735..0000000 --- a/src/FileIncoming.cpp +++ /dev/null @@ -1,36 +0,0 @@ - -#include "FileIncoming.h" - -#include - -namespace HttpServer -{ - FileIncoming::FileIncoming(const std::string &fileName, const std::string &fileType, const size_t fileSize) - : file_name(fileName), file_type(fileType), file_size(fileSize) - { - - } - - FileIncoming::FileIncoming(const FileIncoming &obj) - : file_name(obj.file_name), file_type(obj.file_type), file_size(obj.file_size) - { - - } - - FileIncoming::FileIncoming(FileIncoming &&obj) - : file_name(std::move(obj.file_name) ), file_type(std::move(obj.file_type) ), file_size(obj.file_size) - { - obj.file_size = 0; - } - - bool FileIncoming::isExists() const - { - std::ifstream file(file_name, std::ifstream::binary); - - const bool is_exists = file.good(); - - file.close(); - - return is_exists; - } -}; \ No newline at end of file diff --git a/src/FileIncoming.h b/src/FileIncoming.h deleted file mode 100644 index 6c6fa97..0000000 --- a/src/FileIncoming.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -namespace HttpServer -{ - class FileIncoming - { - protected: - std::string file_name; - std::string file_type; - size_t file_size; - - private: - FileIncoming() = delete; - - public: - FileIncoming(const std::string &fileName, const std::string &fileType, const size_t fileSize); - FileIncoming(const FileIncoming &obj); - FileIncoming(FileIncoming &&obj); - - ~FileIncoming() = default; - - inline std::string getName() const - { - return file_name; - } - - inline std::string getType() const - { - return file_type; - } - - inline size_t getSize() const - { - return file_size; - } - - bool isExists() const; - }; -}; \ No newline at end of file diff --git a/src/Init.cpp b/src/Init.cpp new file mode 100644 index 0000000..fb95657 --- /dev/null +++ b/src/Init.cpp @@ -0,0 +1,258 @@ + +#include "Init.h" + +#include "socket/AdapterDefault.h" + +#include "transfer/FileIncoming.h" +#include "transfer/http2/Http2.h" +#include "utils/Utils.h" + +#include "client/protocol/ClientHttp1.h" +#include "client/protocol/ClientHttp2.h" + +Socket::Adapter *createSocketAdapter(Transfer::app_request *request, void *addr) +{ + if (request->tls_session) + { + return new (addr) Socket::AdapterTls(request->tls_session); + } + + return new (addr) Socket::AdapterDefault(request->socket); +} + +void destroySocketAdapter(Socket::Adapter *adapter) +{ + if (adapter) + { + adapter->~Adapter(); + } +} + +static void getIncomingVars(std::unordered_multimap ¶ms, const std::string &uri) +{ + const size_t start = uri.find('?'); + + if (std::string::npos == start) + { + return; + } + + for (size_t var_pos = start + 1, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) + { + var_end = uri.find('&', var_pos); + + size_t delimiter = uri.find('=', var_pos); + + if (delimiter >= var_end) + { + std::string var_name = Utils::urlDecode(uri.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos) ); + + params.emplace(std::move(var_name), std::string() ); + } + else + { + std::string var_name = Utils::urlDecode(uri.substr(var_pos, delimiter - var_pos) ); + + ++delimiter; + + std::string var_value = Utils::urlDecode(uri.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos) ); + + params.emplace(std::move(var_name), std::move(var_value) ); + } + } +} + +bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *procResponse, const Transfer::app_request *request, Socket::Adapter *socket_adapter) +{ + const uint8_t *src = reinterpret_cast(request->request_data); + + size_t protocol_number; + src = Utils::unpackNumber(&protocol_number, src); + Transfer::ProtocolVariant protocol_variant = static_cast(protocol_number); + HttpClient::ClientProtocol *prot = nullptr; + + std::string document_root; + std::string host; + std::string path; + std::string method; + std::unordered_multimap params; + std::unordered_multimap headers; + std::unordered_multimap data; + std::unordered_multimap files; + std::unordered_multimap cookies; + + bool success = true; + + switch (protocol_variant) + { + case Transfer::ProtocolVariant::HTTP_1: + { + src = Utils::unpackString(document_root, src); + src = Utils::unpackString(host, src); + src = Utils::unpackString(path, src); + src = Utils::unpackString(method, src); + src = Utils::unpackContainer(headers, src); + src = Utils::unpackContainer(data, src); + src = Utils::unpackFilesIncoming(files, src); + + auto const it_cookie = headers.find("cookie"); + + if (headers.cend() != it_cookie) + { + Utils::parseCookies(it_cookie->second, cookies); + } + + getIncomingVars(params, path); + + prot = new HttpClient::ClientHttp1(socket_adapter); + + break; + } + + case Transfer::ProtocolVariant::HTTP_2: + { + src = Utils::unpackString(document_root, src); + src = Utils::unpackString(host, src); + src = Utils::unpackString(path, src); + src = Utils::unpackString(method, src); + + size_t stream_id; + + src = Utils::unpackNumber(&stream_id, src); + + Http2::ConnectionSettings settings; + + size_t number; + + src = Utils::unpackNumber(&number, src); + settings.header_table_size = number; + src = Utils::unpackNumber(&number, src); + settings.enable_push = number; + src = Utils::unpackNumber(&number, src); + settings.max_concurrent_streams = number; + src = Utils::unpackNumber(&number, src); + settings.initial_window_size = number; + src = Utils::unpackNumber(&number, src); + settings.max_frame_size = number; + src = Utils::unpackNumber(&number, src); + settings.max_header_list_size = number; + + std::deque > dynamic_table; + src = Utils::unpackVector(dynamic_table, src); + + src = Utils::unpackContainer(headers, src); + src = Utils::unpackContainer(data, src); + src = Utils::unpackFilesIncoming(files, src); + + getIncomingVars(params, path); + + Http2::OutStream *stream = new Http2::OutStream(stream_id, settings, Http2::DynamicTable(settings.header_table_size, settings.max_header_list_size, std::move(dynamic_table) ) ); + + prot = new HttpClient::ClientHttp2(socket_adapter, stream); + + break; + } + + default: + { + success = false; + break; + } + } + + *procRequest = HttpClient::Request { + prot, + std::move(document_root), + std::move(host), + std::move(path), + std::move(method), + std::move(params), + std::move(headers), + std::move(data), + std::move(files), + std::move(cookies), + protocol_variant + }; + + *procResponse = HttpClient::Response { + prot, + protocol_variant, + std::unordered_map(), + Http::StatusCode::EMPTY + }; + + return success; +} + +void cleanProtocolData(HttpClient::Response *response) +{ + if (response) + { + delete response->prot; + } +} + +bool isSwitchingProtocols(const HttpClient::Request &request, HttpClient::Response &response) +{ + if (request.prot->getSocket()->get_tls_session() != 0) + { + return false; + } + + auto const it_upgrade = request.headers.find("upgrade"); + + if (request.headers.cend() == it_upgrade) + { + return false; + } + + auto const it_connection = request.headers.find("connection"); + + if (request.headers.cend() == it_connection) + { + return false; + } + + std::vector list = Utils::explode(it_connection->second, ','); + + bool is_upgrade = false; + + for (auto &item : list) + { + Utils::toLower(item); + + if ("upgrade" == item) + { + is_upgrade = true; + break; + } + } + + if (false == is_upgrade) + { + return false; + } + + const std::string &upgrade = it_upgrade->second; + + if ("h2c" != upgrade) + { + return false; + } + + auto const it_settings = request.headers.find("http2-settings"); + + if (request.headers.cend() == it_settings) + { + return false; + } + + response.headers["connection"] = "upgrade"; + response.headers["upgrade"] = "h2c"; + + const std::string headers = "HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nUpgrade: h2c\r\n\r\n"; + + response.prot->getSocket()->nonblock_send(headers, std::chrono::milliseconds(5000) ); + + return true; +} diff --git a/src/Init.h b/src/Init.h new file mode 100644 index 0000000..3d068e3 --- /dev/null +++ b/src/Init.h @@ -0,0 +1,14 @@ +#pragma once + +#include "client/Request.h" +#include "client/Response.h" +#include "transfer/AppRequest.h" +#include "transfer/AppResponse.h" + +Socket::Adapter *createSocketAdapter(Transfer::app_request *request, void *addr); +void destroySocketAdapter(Socket::Adapter *adapter); + +bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *procResponse, const Transfer::app_request *request, Socket::Adapter *socket_adapter); +void cleanProtocolData(HttpClient::Response *response); + +bool isSwitchingProtocols(const HttpClient::Request &request, HttpClient::Response &response); diff --git a/src/Main.cpp b/src/Main.cpp index 12e8951..232dd44 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,107 +1,80 @@  #include "Main.h" +#include "Init.h" -#include "Test.h" +#include "application/Test.h" + +#include "utils/Utils.h" DLLEXPORT bool application_init() { return true; } -DLLEXPORT int application_call(HttpServer::server_request *request, HttpServer::server_response *response) +DLLEXPORT int application_call(Transfer::app_request *request, Transfer::app_response *response) { - std::unordered_multimap params; - std::unordered_map headers; - std::unordered_multimap data; - std::unordered_multimap files; - std::unordered_multimap cookies; + // Allocate memory on the stack + uint8_t addr[sizeof(Socket::AdapterTls)]; - Utils::rawPairsToStl(params, request->params, request->params_count); - Utils::rawPairsToStl(headers, request->headers, request->headers_count); - Utils::rawPairsToStl(data, request->data, request->data_count); - Utils::rawFilesInfoToFilesIncoming(files, request->files, request->files_count); + // Create the socket adapter + Socket::Adapter *socket_adapter = createSocketAdapter(request, addr); - auto it_cookie = headers.find("Cookie"); + HttpClient::Request proc_request; + HttpClient::Response proc_response; - if (headers.cend() != it_cookie) + if (false == initServerObjects(&proc_request, &proc_response, request, socket_adapter) ) { - Utils::parseCookies(it_cookie->second, cookies); + return EXIT_FAILURE; } - // Create socket adapter - uint8_t addr[sizeof(HttpServer::SocketAdapterTls)]; + const std::string absolute_path = proc_request.document_root + proc_request.path; - HttpServer::SocketAdapter *socket_adapter; + int result = EXIT_SUCCESS; - if (request->tls_session) + if (isSwitchingProtocols(proc_request, proc_response) ) { - socket_adapter = new (addr) HttpServer::SocketAdapterTls(request->tls_session); - } - else - { - socket_adapter = new (addr) HttpServer::SocketAdapterDefault(request->socket); - } - - HttpServer::ServerRequest proc_request { - *socket_adapter, - std::string(request->method), - std::string(request->uri_reference), - std::string(request->document_root), - std::move(params), - std::move(headers), - std::move(data), - std::move(files), - std::move(cookies) - }; - - HttpServer::ServerResponse proc_response { - *socket_adapter, - std::map() - }; - - const std::string absolute_path = proc_request.document_root + proc_request.uri_reference; - int result = EXIT_SUCCESS; - - if (std::string::npos == absolute_path.find("/../") && System::isFileExists(absolute_path) ) + } + else if (std::string::npos == absolute_path.find("/../") && System::isFileExists(absolute_path) ) { - auto it_connection = proc_request.headers.find("Connection"); + auto it_connection = proc_request.headers.find("connection"); if (proc_request.headers.cend() != it_connection) { - proc_response.headers["Connection"] = it_connection->second; + proc_response.headers["connection"] = it_connection->second; } - proc_response.headers["X-Sendfile"] = absolute_path; + proc_response.headers["x-sendfile"] = absolute_path; } else { - result = test(proc_request, proc_response); + // Call application + result = Application::test(proc_request, proc_response); } - socket_adapter->~SocketAdapter(); + destroySocketAdapter(socket_adapter); if (proc_response.headers.size() ) { - Utils::raw_pair *headers; - Utils::stlToRawPairs(&headers, proc_response.headers); - - response->headers_count = proc_response.headers.size(); - response->headers = headers; + response->data_size = Utils::getPackContainerSize(proc_response.headers); + response->response_data = new uint8_t[response->data_size]; + Utils::packContainer(reinterpret_cast(response->response_data), proc_response.headers); } + cleanProtocolData(&proc_response); + return result; } -DLLEXPORT void application_clear(Utils::raw_pair headers[], const size_t headers_count) +DLLEXPORT void application_clear(void *response_data, size_t response_size) { - if (headers && headers_count) + if (response_data && response_size) { - destroyRawPairs(headers, headers_count); + delete[] reinterpret_cast(response_data); } } DLLEXPORT void application_final() { -} \ No newline at end of file +} diff --git a/src/Main.h b/src/Main.h index ddc8a58..e8eb26d 100644 --- a/src/Main.h +++ b/src/Main.h @@ -1,16 +1,7 @@ #pragma once -#include "ServerRequest.h" -#include "ServerResponse.h" -#include "FileIncoming.h" -#include "Utils.h" - -#include -#include -#include - #ifdef WIN32 #define DLLEXPORT extern "C" __declspec(dllexport) #else #define DLLEXPORT extern "C" -#endif \ No newline at end of file +#endif diff --git a/src/RawData.h b/src/RawData.h deleted file mode 100644 index a493382..0000000 --- a/src/RawData.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -namespace Utils -{ - struct raw_pair - { - char *key; - char *value; - }; - - struct raw_fileinfo - { - char *key; - char *file_name; - char *file_type; - size_t file_size; - }; -}; \ No newline at end of file diff --git a/src/ServerRequest.h b/src/ServerRequest.h deleted file mode 100644 index 234fdef..0000000 --- a/src/ServerRequest.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include "RawData.h" -#include "SocketAdapterDefault.h" -#include "SocketAdapterTls.h" -#include "FileIncoming.h" - -#include - -namespace HttpServer -{ - struct server_request - { - const System::native_socket_type socket; - const ::gnutls_session_t tls_session; - const char *method; - const char *uri_reference; - const char *document_root; - const size_t params_count; - const Utils::raw_pair *params; - const size_t headers_count; - const Utils::raw_pair *headers; - const size_t data_count; - const Utils::raw_pair *data; - const size_t files_count; - const Utils::raw_fileinfo *files; - }; - - /** - * Структура запроса (входные данные) - * - * @member const SocketAdapter &socket - сокет клиента - * @member const std::string method - метод применяемый к ресурсу - * @member const std::string uri_reference - ссылка на ресурс - * @member const std::string document_root - корневая директория приложения - * @member const std::unordered_multimap params - параметры ресурса - * @member const std::unordered_map headers - заголовки запроса - * @member const std::unordered_multimap data - входящие данные запроса - * @member const std::unordered_multimap files - входящие файлы запроса - * @member const std::unordered_multimap cookies - входящие куки запроса - */ - struct ServerRequest - { - const SocketAdapter &socket; - const std::string method; - const std::string uri_reference; - const std::string document_root; - const std::unordered_multimap params; - const std::unordered_map headers; - const std::unordered_multimap data; - const std::unordered_multimap files; - const std::unordered_multimap cookies; - }; -}; \ No newline at end of file diff --git a/src/ServerResponse.h b/src/ServerResponse.h deleted file mode 100644 index 302dda0..0000000 --- a/src/ServerResponse.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "RawData.h" -#include "SocketAdapter.h" - -#include -#include - -namespace HttpServer -{ - struct server_response - { - System::native_socket_type socket; - size_t headers_count; - Utils::raw_pair *headers; - }; - - struct ServerResponse - { - SocketAdapter &socket; - std::map headers; - }; -}; \ No newline at end of file diff --git a/src/Socket.h b/src/Socket.h deleted file mode 100644 index fb7eecc..0000000 --- a/src/Socket.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#ifdef POSIX - #include - #include - #include - #include - #include - #include - #include - #include -#endif - -#include "System.h" - -#include -#include - -#include -#include -#include - -namespace HttpServer -{ - class Socket - { - protected: - System::native_socket_type socket_handle; - - public: - bool static Startup(); - bool static Cleanup(); - int static getLastError(); - - public: - Socket(); - Socket(const System::native_socket_type fd); - Socket(const Socket &obj); - Socket(Socket &&obj); - - ~Socket() = default; - - bool open(); - bool close(); - - inline bool is_open() const - { - #ifdef WIN32 - return INVALID_SOCKET != this->socket_handle; - #elif POSIX - return ~0 != this->socket_handle; - #else - #error "Undefine platform" - #endif - } - - bool bind(const int port) const; - bool listen() const; - - Socket accept() const; - Socket nonblock_accept() const; - Socket nonblock_accept(const std::chrono::milliseconds &timeout) const; - - bool shutdown() const; - - bool nonblock(const bool isNonBlock = true) const; - // bool is_nonblock() const; - bool tcp_nodelay(const bool nodelay = true) const; - - long recv(std::vector &buf) const; - long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const; - - long send(const std::string &buf) const; - long send(const std::vector &buf, const size_t length) const; - - long nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const; - long nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const; - - void nonblock_send_sync() const; - - inline System::native_socket_type get_handle() const - { - return this->socket_handle; - } - - Socket &operator =(const Socket &obj); - - bool operator ==(const Socket &obj) const; - bool operator !=(const Socket &obj) const; - }; -}; - -namespace std -{ - // Hash for Socket - template<> struct hash - { - std::size_t operator()(const HttpServer::Socket &obj) const - { - return std::hash{}(obj.get_handle() ); - } - }; -}; \ No newline at end of file diff --git a/src/SocketAdapter.cpp b/src/SocketAdapter.cpp deleted file mode 100644 index 5354cb0..0000000 --- a/src/SocketAdapter.cpp +++ /dev/null @@ -1,15 +0,0 @@ - -#include "SocketAdapter.h" - -namespace HttpServer -{ - bool SocketAdapter::operator ==(const SocketAdapter &obj) const - { - return this->get_handle() == obj.get_handle(); - } - - bool SocketAdapter::operator !=(const SocketAdapter &obj) const - { - return this->get_handle() != obj.get_handle(); - } -}; \ No newline at end of file diff --git a/src/SocketAdapter.h b/src/SocketAdapter.h deleted file mode 100644 index 690e668..0000000 --- a/src/SocketAdapter.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "System.h" - -#include -#include -#include - -#include - -namespace HttpServer -{ - class SocketAdapter - { - public: - virtual ~SocketAdapter() = default; - - virtual System::native_socket_type get_handle() const = 0; - virtual ::gnutls_session_t get_tls_session() const = 0; - virtual SocketAdapter *copy() const = 0; - - virtual long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const = 0; - - virtual long nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const = 0; - virtual long nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const = 0; - - virtual void close() = 0; - - bool operator ==(const SocketAdapter &obj) const; - bool operator !=(const SocketAdapter &obj) const; - }; -}; \ No newline at end of file diff --git a/src/SocketAdapterDefault.cpp b/src/SocketAdapterDefault.cpp deleted file mode 100644 index 12fffd4..0000000 --- a/src/SocketAdapterDefault.cpp +++ /dev/null @@ -1,49 +0,0 @@ - -#include "SocketAdapterDefault.h" - -namespace HttpServer -{ - SocketAdapterDefault::SocketAdapterDefault(const Socket &_sock) : sock(_sock) - { - - } - - System::native_socket_type SocketAdapterDefault::get_handle() const - { - return sock.get_handle(); - } - - ::gnutls_session_t SocketAdapterDefault::get_tls_session() const - { - return 0; - } - - SocketAdapter *SocketAdapterDefault::copy() const - { - return new SocketAdapterDefault(this->sock); - } - - long SocketAdapterDefault::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const - { - return sock.nonblock_recv(buf, timeout); - } - - long SocketAdapterDefault::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const - { - return sock.nonblock_send(buf, timeout); - } - - long SocketAdapterDefault::nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const - { - return sock.nonblock_send(buf, length, timeout); - } - - void SocketAdapterDefault::close() - { - // Wait for send all data to client - sock.nonblock_send_sync(); - - sock.shutdown(); - sock.close(); - } -}; \ No newline at end of file diff --git a/src/SocketAdapterDefault.h b/src/SocketAdapterDefault.h deleted file mode 100644 index e3272be..0000000 --- a/src/SocketAdapterDefault.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "SocketAdapter.h" -#include "Socket.h" - -namespace HttpServer -{ - class SocketAdapterDefault : public SocketAdapter - { - private: - Socket sock; - - public: - SocketAdapterDefault() = delete; - SocketAdapterDefault(const Socket &_sock); - - virtual System::native_socket_type get_handle() const override; - virtual ::gnutls_session_t get_tls_session() const override; - virtual SocketAdapter *copy() const override; - - virtual long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const override; - - virtual long nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const override; - virtual long nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const override; - - virtual void close() override; - }; -}; \ No newline at end of file diff --git a/src/SocketAdapterTls.cpp b/src/SocketAdapterTls.cpp deleted file mode 100644 index b26903d..0000000 --- a/src/SocketAdapterTls.cpp +++ /dev/null @@ -1,122 +0,0 @@ - -#include "SocketAdapterTls.h" - -namespace HttpServer -{ - SocketAdapterTls::SocketAdapterTls(const Socket &sock, ::gnutls_priority_t priority_cache, ::gnutls_certificate_credentials_t x509_cred) - { - ::gnutls_init(&this->session, GNUTLS_SERVER); - ::gnutls_priority_set(this->session, priority_cache); - ::gnutls_credentials_set(this->session, GNUTLS_CRD_CERTIFICATE, x509_cred); - - ::gnutls_certificate_server_set_request(this->session, GNUTLS_CERT_IGNORE); - - ::gnutls_transport_set_int2(this->session, sock.get_handle(), sock.get_handle() ); - } - - SocketAdapterTls::SocketAdapterTls(const ::gnutls_session_t _session) : session(_session) - { - - } - - bool SocketAdapterTls::handshake() - { - int ret; - - do - { - ret = ::gnutls_handshake(this->session); - } - while (ret < 0 && ::gnutls_error_is_fatal(ret) == 0); - - if (ret < 0) - { - Socket sock(this->get_handle() ); - - sock.close(); - ::gnutls_deinit(this->session); - - return false; - } - - return true; - } - - long SocketAdapterTls::nonblock_send_all(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const - { - size_t record_size = ::gnutls_record_get_max_size(this->session); - - if (0 == record_size) - { - return -1; - } - - size_t total = 0; - - while (total < length) - { - ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); - - if (record_size > length - total) - { - record_size = length - total; - } - - const long send_size = ::gnutls_record_send(this->session, reinterpret_cast(buf) + total, record_size); - - if (send_size < 0) - { - return send_size; - } - - total += send_size; - } - - return total; - } - - System::native_socket_type SocketAdapterTls::get_handle() const - { - return static_cast(::gnutls_transport_get_int(this->session) ); - } - - ::gnutls_session_t SocketAdapterTls::get_tls_session() const - { - return this->session; - } - - SocketAdapter *SocketAdapterTls::copy() const - { - return new SocketAdapterTls(this->session); - } - - long SocketAdapterTls::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const - { - ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); - return ::gnutls_record_recv(this->session, buf.data(), buf.size() ); - } - - long SocketAdapterTls::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const - { - return this->nonblock_send_all(buf.data(), buf.length(), timeout); - } - - long SocketAdapterTls::nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const - { - return this->nonblock_send_all(buf.data(), length, timeout); - } - - void SocketAdapterTls::close() - { - Socket sock(this->get_handle() ); - - // Wait for send all data to client - sock.nonblock_send_sync(); - - ::gnutls_bye(this->session, GNUTLS_SHUT_RDWR); - - sock.close(); - - ::gnutls_deinit(this->session); - } -}; \ No newline at end of file diff --git a/src/SocketAdapterTls.h b/src/SocketAdapterTls.h deleted file mode 100644 index de57147..0000000 --- a/src/SocketAdapterTls.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "SocketAdapter.h" -#include "Socket.h" - -namespace HttpServer -{ - class SocketAdapterTls : public SocketAdapter - { - private: - ::gnutls_session_t session; - - public: - SocketAdapterTls() = delete; - SocketAdapterTls(const Socket &sock, ::gnutls_priority_t priority_cache, ::gnutls_certificate_credentials_t x509_cred); - SocketAdapterTls(const ::gnutls_session_t _session); - - bool handshake(); - long nonblock_send_all(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const; - - virtual System::native_socket_type get_handle() const override; - virtual ::gnutls_session_t get_tls_session() const override; - virtual SocketAdapter *copy() const override; - - virtual long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const override; - - virtual long nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const override; - virtual long nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const override; - - virtual void close() override; - }; -}; \ No newline at end of file diff --git a/src/Test.cpp b/src/Test.cpp deleted file mode 100644 index e9f8dd1..0000000 --- a/src/Test.cpp +++ /dev/null @@ -1,125 +0,0 @@ - -#include "Test.h" - -bool test(HttpServer::ServerRequest &request, HttpServer::ServerResponse &response) -{ - // Output incoming headers - - std::string s = R"( - - - - - - -)"; - - for (auto const &pair : request.headers) - { - s += R"( - - - -)"; - } - - // Output incoming data - - s += R"( - - - - - - -)"; - - for (auto const &pair : request.data) - { - s += R"( - - - -)"; - } - - // Output incoming url parameters - - s += R"( - - - - - - -)"; - - for (auto const &pair : request.params) - { - s += R"( - - - -)"; - } - - // Output info about incoming files - - s += R"( - - - - - - -)"; - - for (auto const &pair : request.files) - { - const HttpServer::FileIncoming &file = pair.second; - - s += R"( - - - -)"; - } - - s += R"( -
Incoming headers
)" + pair.first + R"()" + pair.second + R"(
Incoming data
)" + pair.first + R"()" + pair.second + R"(
Incoming url parameters
)" + pair.first + R"()" + pair.second + R"(
Incoming files
)" + file.getName() + R"()" + std::to_string(file.getSize() ) + R"(
)"; - - HttpServer::SocketAdapter &socket = response.socket; - std::map &headers_outgoing = response.headers; - - // Set outgoing headers - - headers_outgoing[""] = "HTTP/1.1 200 OK"; - headers_outgoing["Content-Type"] = "text/html; charset=utf-8"; - headers_outgoing["Accept-Ranges"] = "bytes"; - headers_outgoing["Content-Length"] = std::to_string(s.length() ); - headers_outgoing["Connection"] = "Keep-Alive"; - headers_outgoing["Date"] = Utils::getDatetimeAsString(); - - std::string headers; - - for (auto const &h : headers_outgoing) - { - if (h.first.length() ) - { - headers += h.first + ": "; - } - - headers += h.second + "\r\n"; - } - - headers += "\r\n"; - - // Send headers and page - - const std::chrono::milliseconds timeout(5000); - - socket.nonblock_send(headers, timeout); - socket.nonblock_send(s, timeout); - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/src/Test.h b/src/Test.h deleted file mode 100644 index 254aa58..0000000 --- a/src/Test.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "ServerRequest.h" -#include "ServerResponse.h" - -#include "Utils.h" - -#include - -bool test(HttpServer::ServerRequest &, HttpServer::ServerResponse &); diff --git a/src/Utils.cpp b/src/Utils.cpp deleted file mode 100644 index 525a216..0000000 --- a/src/Utils.cpp +++ /dev/null @@ -1,459 +0,0 @@ - -#include "Utils.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace Utils -{ - void toLower(std::string &str, const std::locale &loc) - { - for (auto &c : str) - { - c = std::tolower(c, loc); - } - } - - void trim(std::string &str) - { - static const std::array whitespace { " \t\n\v\f\r" }; - - const size_t last = str.find_last_not_of(whitespace.data() ); - - if (std::string::npos == last) - { - return str.clear(); - } - - str.assign(str.cbegin() + str.find_first_not_of(whitespace.data() ), str.cbegin() + last + 1); - } - - std::vector explode(const std::string &str, const char sep) - { - std::vector values; - - for (size_t pos = 0; std::string::npos != pos;) - { - size_t delimiter = str.find(sep, pos); - - std::string value = str.substr(pos, delimiter); - trim(value); - - values.emplace_back(std::move(value) ); - - pos = delimiter; - - if (std::string::npos != pos) - { - ++pos; - } - } - - return values; - } - - std::string encodeHtmlSymbols(const std::string &str) - { - std::string buf; - buf.reserve(str.length() ); - - for (size_t pos = 0; pos < str.length(); ++pos) - { - switch (str[pos]) - { - case '&': buf.append("&"); break; - case '\"': buf.append("""); break; - case '\'': buf.append("'"); break; - case '<': buf.append("<"); break; - case '>': buf.append(">"); break; - default: buf.push_back(str[pos]); break; - } - } - - return buf; - } - - std::string binToHexString(const void *binData, const size_t dataSize) - { - std::string str(dataSize * 2, 0); - - const uint8_t *bin = reinterpret_cast(binData); - - static const std::array hexDigits { "0123456789abcdef" }; - - for (size_t i = dataSize - 1; std::numeric_limits::max() != i; --i) - { - str[i * 2 + 0] = hexDigits[bin[i] >> 4]; - str[i * 2 + 1] = hexDigits[bin[i] & 0x0F]; - } - - return str; - } - - static unsigned char hexStringToBinEncodeSymbol(const char c) - { - if (c >= '0' && c <= '9') - { - return c - 0x30; - } - else if (c >= 'a' && c <= 'f') - { - return c - 0x57; - } - else if (c >= 'A' && c <= 'F') - { - return c - 0x37; - } - - return 0; - } - - std::string hexStringToBin(const std::string &hexStr) - { - std::string bin(hexStr.length() / 2, 0); - - for (size_t i = 0; i < bin.length(); ++i) - { - const char a = hexStr[i * 2 + 0]; - const char b = hexStr[i * 2 + 1]; - - bin[i] = ( - (hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b) - ); - } - - return bin; - } - - unsigned long long htonll(const unsigned long long src) - { - enum Endianness { - INIT = 0, - LITE = 1, - BIGE = 2 - }; - - static int endian = Endianness::INIT; - - union { - unsigned long long ull; - unsigned char c[8]; - } x; - - if (endian == Endianness::INIT) - { - x.ull = 0x01; - endian = (x.c[7] == 0x01ULL) ? Endianness::BIGE : Endianness::LITE; - } - - if (endian == Endianness::BIGE) - { - return src; - } - - x.ull = src; - - unsigned char c; - - c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c; - c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c; - c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c; - c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c; - - return x.ull; - } - - std::string getUniqueName() - { - size_t time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); - - time = htonll(time); - - return binToHexString(&time, sizeof(time) ); - } - - char *stlStringToPChar(const std::string &str) - { - const size_t length = str.length(); - char *s = nullptr; - - if (length) - { - s = new char[length + 1]; - #ifdef WIN32 - ::strcpy_s(s, length + 1, str.c_str() ); - #elif POSIX - ::strcpy(s, str.c_str() ); - s[length] = '\0'; - #else - #error "Undefine platform" - #endif - } - - return s; - } - - void filesIncomingToRawFilesInfo(Utils::raw_fileinfo *raw[], const std::unordered_multimap &map) - { - if (raw && map.size() ) - { - raw_fileinfo *arr = new raw_fileinfo[map.size()]; - - *raw = arr; - - size_t i = 0; - - for (auto it = map.cbegin(); map.cend() != it; ++it, ++i) - { - arr[i].key = stlStringToPChar(it->first); - - const HttpServer::FileIncoming &file = it->second; - - arr[i].file_name = stlStringToPChar(file.getName() ); - arr[i].file_type = stlStringToPChar(file.getType() ); - arr[i].file_size = file.getSize(); - } - } - } - - void rawFilesInfoToFilesIncoming(std::unordered_multimap &map, const Utils::raw_fileinfo raw[], const size_t count) - { - for (size_t i = 0; i < count; ++i) - { - map.emplace(raw[i].key ? raw[i].key : "", HttpServer::FileIncoming(raw[i].file_name, raw[i].file_type, raw[i].file_size) ); - } - } - - void destroyRawPairs(Utils::raw_pair raw[], const size_t count) - { - if (raw) - { - for (size_t i = 0; i < count; ++i) - { - raw_pair &cur = raw[i]; - - delete[] cur.key; - delete[] cur.value; - } - - delete[] raw; - } - } - - void destroyRawFilesInfo(Utils::raw_fileinfo raw[], const size_t count) - { - if (raw) - { - for (size_t i = 0; i < count; ++i) - { - raw_fileinfo &cur = raw[i]; - - delete[] cur.key; - delete[] cur.file_name; - delete[] cur.file_type; - } - - delete[] raw; - } - } - - time_t stringTimeToTimestamp(const std::string &strTime) - { - static const std::unordered_map map_months { - {"Jan", 0}, {"Feb", 1}, {"Mar", 2}, {"Apr", 3}, {"May", 4}, {"Jun", 5}, {"Jul", 6}, {"Aug", 7}, {"Sep", 8}, {"Oct", 9}, {"Nov", 10}, {"Dec", 11} - }; - - if (strTime.length() > 64) - { - return ~0; - } - - const size_t str_mon_length = 64; - std::vector s_mon(str_mon_length); - - struct ::tm tc = {}; - - // Parse RFC 822 - #ifdef WIN32 - if (~0 != ::sscanf_s(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon.data(), static_cast(s_mon.size() ), &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) ) - #else - if (~0 != ::sscanf(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon.data(), &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) ) - #endif - { - tc.tm_year -= 1900; - - auto const it_mon = map_months.find(s_mon.data() ); - - if (map_months.cend() != it_mon) - { - tc.tm_mon = it_mon->second; - } - } - - tc.tm_isdst = -1; - - return ::mktime(&tc); - } - - std::string getDatetimeAsString(const ::time_t tTime, const bool isGmtTime) - { - std::array buf; - - ::time_t cur_time = tTime; - - if (tTime == ~0) - { - ::time(&cur_time); - } - - #ifdef WIN32 - struct ::tm stm = {}; - - isGmtTime ? - ::localtime_s(&stm, &cur_time) : - ::gmtime_s(&stm, &cur_time); - - // RFC 822 - ::strftime(buf.data(), buf.size(), "%a, %d %b %Y %H:%M:%S GMT", &stm); - #else - struct ::tm stm = {}; - - isGmtTime ? - ::localtime_r(&cur_time, &stm) : - ::gmtime_r(&cur_time, &stm); - - // RFC 822 - ::strftime(buf.data(), buf.size(), "%a, %d %b %G %H:%M:%S GMT", &stm); - #endif - - return std::string(buf.data() ); - } - - size_t getNumberLength(const size_t number) - { - size_t length = 0; - - size_t n = number; - - do - { - ++length; - n /= 10; - } - while (n); - - return length; - } - - bool parseCookies(const std::string &cookieHeader, std::unordered_multimap &cookies) - { - if (cookieHeader.empty() ) - { - return true; - } - - for (size_t cur_pos = 0, next_value; std::string::npos != cur_pos; cur_pos = next_value) - { - next_value = cookieHeader.find(';', cur_pos); - - size_t delimiter = cookieHeader.find('=', cur_pos); - - if (std::string::npos == delimiter || delimiter > next_value) - { - return false; - } - - std::string key = cookieHeader.substr(cur_pos, delimiter - cur_pos); - trim(key); - key = urlDecode(key); - - ++delimiter; - - std::string value = cookieHeader.substr(delimiter, std::string::npos != next_value ? next_value - delimiter : next_value); - trim(value); - value = urlDecode(value); - - cookies.emplace(std::move(key), std::move(value) ); - - if (std::string::npos != next_value) - { - ++next_value; - } - } - - return true; - } - - static inline bool isCharUrlAllowed(const char c) - { - return c == '-' || c == '_' || c == '.' || c == '~'; - } - - std::string urlEncode(const std::string &str) - { - std::string encoded; - - static const std::array hexDigits { "0123456789ABCDEF" }; - - for (size_t i = 0; i < str.length(); ++i) - { - const unsigned char c = str[i]; - - if (std::isalnum(c) || isCharUrlAllowed(c) ) - { - encoded.push_back(c); - } - else if (' ' == c) - { - encoded.push_back('+'); - } - else - { - const uint8_t a = c >> 4; - const uint8_t b = c & 0x0F; - - encoded.push_back('%'); - encoded.push_back(hexDigits[a]); - encoded.push_back(hexDigits[b]); - } - } - - return encoded; - } - - std::string urlDecode(const std::string &str) - { - std::string decoded; - - for (size_t i = 0; i < str.length(); ++i) - { - unsigned char c = str[i]; - - if ('%' == c) - { - if (i + 2 < str.length() ) - { - const char a = str[++i]; - const char b = str[++i]; - - c = ( - (hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b) - ); - } - } - else if ('+' == c) - { - c = ' '; - } - - decoded.push_back(c); - } - - return decoded; - } -}; \ No newline at end of file diff --git a/src/Utils.h b/src/Utils.h deleted file mode 100644 index b2e15c1..0000000 --- a/src/Utils.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "RawData.h" -#include "FileIncoming.h" - -#include -#include -#include - -namespace Utils -{ - void toLower(std::string &str, const std::locale &loc); - - void trim(std::string &str); - - std::vector explode(const std::string &str, const char sep); - - std::string encodeHtmlSymbols(const std::string &str); - - std::string binToHexString(const void *bin, const size_t size); - - std::string hexStringToBin(const std::string &hexStr); - - unsigned long long htonll(const unsigned long long src); - - std::string getUniqueName(); - - char *stlStringToPChar(const std::string &str); - - template - void stlToRawPairs(Utils::raw_pair *raw[], const T &stl) - { - if (raw && stl.size() ) - { - raw_pair *arr = new raw_pair[stl.size()]; - - *raw = arr; - - size_t i = 0; - - for (auto it = stl.cbegin(); stl.cend() != it; ++it, ++i) - { - arr[i].key = stlStringToPChar(it->first); - arr[i].value = stlStringToPChar(it->second); - } - } - } - - template - void rawPairsToStl(T &stl, const Utils::raw_pair raw[], const size_t count) - { - for (size_t i = 0; i < count; ++i) - { - stl.emplace(raw[i].key ? raw[i].key : "", raw[i].value ? raw[i].value : ""); - } - } - - void filesIncomingToRawFilesInfo(Utils::raw_fileinfo *raw[], const std::unordered_multimap &map); - void rawFilesInfoToFilesIncoming(std::unordered_multimap &map, const Utils::raw_fileinfo raw[], const size_t count); - - void destroyRawPairs(Utils::raw_pair raw[], const size_t count); - void destroyRawFilesInfo(Utils::raw_fileinfo raw[], const size_t count); - - time_t stringTimeToTimestamp(const std::string &strTime); - - std::string getDatetimeAsString(const ::time_t tTime = ~0, const bool isGmtTime = false); - - size_t getNumberLength(const size_t number); - - bool parseCookies(const std::string &cookieHeader, std::unordered_multimap &cookies); - - std::string urlEncode(const std::string &str); - std::string urlDecode(const std::string &str); -}; \ No newline at end of file diff --git a/src/application/Test.cpp b/src/application/Test.cpp new file mode 100644 index 0000000..7fea204 --- /dev/null +++ b/src/application/Test.cpp @@ -0,0 +1,147 @@ + +#include "Test.h" + +#include "../utils/Utils.h" + +namespace Application +{ + bool test(HttpClient::Request &request, HttpClient::Response &response) + { + // Output incoming headers + + std::string s = R"( + + + + + + + + + + +)"; + + for (auto const &pair : request.headers) + { + s += R"( + + + +)"; + } + + // Output incoming url parameters + + s += R"( + + + + + + + + + + +)"; + + for (auto const &pair : request.params) + { + s += R"( + + + +)"; + } + + // Output incoming form data + + s += R"( + + + + + + + + + + +)"; + + for (auto const &pair : request.data) + { + s += R"( + + + +)"; + } + + // Output info about incoming files + + s += R"( + + + + + + + + + + + + + +)"; + + for (auto const &pair : request.files) + { + const std::string &field_name = pair.first; + const Transfer::FileIncoming &file = pair.second; + + s += R"( + + + + + + +)"; + } + + s += R"( +
Incoming headers
Header nameHeader value
)" + pair.first + R"()" + pair.second + R"(
Incoming url parameters
Parameter nameParameter value
)" + pair.first + R"()" + pair.second + R"(
Incoming form data
Form fieldField value
)" + pair.first + R"()" + pair.second + R"(
Incoming files
Form fieldOriginal nameFile typeFile sizeUploaded name
)" + field_name + R"()" + file.getName() + R"()" + file.getType() + R"()" + std::to_string(file.getSize() ) + R"()" + file.getTmpName() + R"(
)"; + + std::unordered_map &headers = response.headers; + + // Set outgoing headers + + response.setStatusCode(Http::StatusCode::OK); + headers["content-type"] = "text/html; charset=utf-8"; + headers["accept-ranges"] = "bytes"; + headers["content-length"] = std::to_string(s.size() ); + headers["connection"] = "keep-alive"; + headers["date"] = Utils::getDatetimeAsString(); + + // Additional headers + // In additional headers may be placed values of cookies + std::vector > additional; + // additional.emplace_back("set-cookie", "key=value; expires=; path=/; domain=*"); + + // Send headers and data + + const std::chrono::milliseconds timeout(5000); + + response.sendHeaders(additional, timeout, s.empty() ); + + if (false == s.empty() ) + { + response.sendData(s.data(), s.size(), timeout, true); + } + + return EXIT_SUCCESS; + } +}; diff --git a/src/application/Test.h b/src/application/Test.h new file mode 100644 index 0000000..66764ce --- /dev/null +++ b/src/application/Test.h @@ -0,0 +1,9 @@ +#pragma once + +#include "../client/Request.h" +#include "../client/Response.h" + +namespace Application +{ + bool test(HttpClient::Request &, HttpClient::Response &); +}; diff --git a/src/client/Request.cpp b/src/client/Request.cpp new file mode 100644 index 0000000..c6686fc --- /dev/null +++ b/src/client/Request.cpp @@ -0,0 +1,54 @@ + +#include "Request.h" + +namespace HttpClient +{ + std::string Request::getHeader(const std::string &key) const + { + auto it = headers.find(key); + + return headers.end() != it ? it->second : ""; + } + + bool Request::isDataExists(const std::string &key) const + { + return data.cend() != data.find(key); + } + + std::string Request::getDataAsString(const std::string &key) const + { + auto it = data.find(key); + + return data.end() != it ? it->second : ""; + } + + std::vector Request::getDataAsArray(const std::string &key) const + { + std::vector arr; + + size_t count = data.count(key); + + if (count) + { + auto range = data.equal_range(key); + + arr.resize(count); + + size_t i = 0; + + for (auto it = range.first; it != range.second; ++it) + { + arr[i++] = it->second; + } + } + + return arr; + } + + std::string Request::getCookieAsString(const std::string &cookieName) const + { + auto it = cookies.find(cookieName); + + return cookies.end() != it ? it->second : ""; + } +}; diff --git a/src/client/Request.h b/src/client/Request.h new file mode 100644 index 0000000..cc74368 --- /dev/null +++ b/src/client/Request.h @@ -0,0 +1,50 @@ +#pragma once + +#include "protocol/ClientProtocol.h" +#include "../transfer/FileIncoming.h" +#include "../transfer/ProtocolVariant.h" + +#include + +namespace HttpClient +{ + /** + * Структура запроса (входные данные) + * + * @member const Socket::Adapter &socket - сокет клиента + * @member const std::string method - метод применяемый к ресурсу + * @member const std::string uri_reference - ссылка на ресурс + * @member const std::string document_root - корневая директория приложения + * @member const std::unordered_multimap params - параметры ресурса + * @member const std::unordered_map headers - заголовки запроса + * @member const std::unordered_multimap data - входящие данные запроса + * @member const std::unordered_multimap files - входящие файлы запроса + * @member const std::unordered_multimap cookies - входящие куки запроса + */ + struct Request + { + ClientProtocol *prot; + std::string document_root; + std::string host; + std::string path; + std::string method; + std::unordered_multimap params; + std::unordered_multimap headers; + std::unordered_multimap data; + std::unordered_multimap files; + std::unordered_multimap cookies; + + Transfer::ProtocolVariant protocol_variant; + + public: + std::string getHeader(const std::string &key) const; + + bool isDataExists(const std::string &key) const; + + std::string getDataAsString(const std::string &key) const; + + std::vector getDataAsArray(const std::string &key) const; + + std::string getCookieAsString(const std::string &cookieName) const; + }; +}; diff --git a/src/client/Response.cpp b/src/client/Response.cpp new file mode 100644 index 0000000..2af748a --- /dev/null +++ b/src/client/Response.cpp @@ -0,0 +1,29 @@ + +#include "Response.h" + +#include "../transfer/http2/HPack.h" + +#include + +namespace HttpClient +{ + void Response::setStatusCode(const Http::StatusCode status) + { + this->status = status; + } + + bool Response::sendHeaders(const std::vector > &additional, const std::chrono::milliseconds &timeout, const bool endStream) + { + std::vector > headers; + + std::copy(this->headers.begin(), this->headers.end(), std::back_inserter(headers) ); + std::copy(additional.begin(), additional.end(), std::back_inserter(headers) ); + + return this->prot->sendHeaders(this->status, headers, timeout, endStream); + } + + long Response::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const + { + return this->prot->sendData(src, size, timeout, endStream); + } +}; diff --git a/src/client/Response.h b/src/client/Response.h new file mode 100644 index 0000000..73b3343 --- /dev/null +++ b/src/client/Response.h @@ -0,0 +1,25 @@ +#pragma once + +#include "protocol/ClientProtocol.h" +#include "../transfer/ProtocolVariant.h" +#include "../transfer/HttpStatusCode.h" + +#include +#include + +namespace HttpClient +{ + struct Response + { + ClientProtocol *prot; + Transfer::ProtocolVariant protocol_variant; + std::unordered_map headers; + Http::StatusCode status; + + public: + void setStatusCode(const Http::StatusCode status); + + bool sendHeaders(const std::vector > &additional, const std::chrono::milliseconds &timeout, const bool endStream = true); + long sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream = true) const; + }; +}; diff --git a/src/client/protocol/ClientHttp1.cpp b/src/client/protocol/ClientHttp1.cpp new file mode 100644 index 0000000..cfa923b --- /dev/null +++ b/src/client/protocol/ClientHttp1.cpp @@ -0,0 +1,29 @@ + +#include "ClientHttp1.h" + +namespace HttpClient +{ + ClientHttp1::ClientHttp1(Socket::Adapter *sock) : ClientProtocol(sock) + { + + } + + bool ClientHttp1::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const + { + std::string out = "HTTP/1.1 " + std::to_string(static_cast(status) ) + "\r\n"; + + for (auto const &h : headers) + { + out += h.first + ": " + h.second + "\r\n"; + } + + out += "\r\n"; + + return this->sock->nonblock_send(out, timeout) > 0; + } + + long ClientHttp1::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const + { + return this->sock->nonblock_send(src, size, timeout); + } +}; diff --git a/src/client/protocol/ClientHttp1.h b/src/client/protocol/ClientHttp1.h new file mode 100644 index 0000000..556d231 --- /dev/null +++ b/src/client/protocol/ClientHttp1.h @@ -0,0 +1,15 @@ +#pragma once + +#include "ClientProtocol.h" + +namespace HttpClient +{ + class ClientHttp1 : public ClientProtocol + { + public: + ClientHttp1(Socket::Adapter *sock); + + virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; + virtual long sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; + }; +}; diff --git a/src/client/protocol/ClientHttp2.cpp b/src/client/protocol/ClientHttp2.cpp new file mode 100644 index 0000000..29caa18 --- /dev/null +++ b/src/client/protocol/ClientHttp2.cpp @@ -0,0 +1,186 @@ + +#include "ClientHttp2.h" + +#include "../../transfer/http2/HPack.h" + +#include + +namespace HttpClient +{ + ClientHttp2::ClientHttp2(Socket::Adapter *sock, Http2::OutStream *stream) + : ClientProtocol(sock), stream(stream) + { + + } + + ClientHttp2::~ClientHttp2() noexcept + { + delete this->stream; + } + + static uint8_t getPaddingSize(const size_t dataSize) + { + if (0 == dataSize) + { + return 0; + } + + std::random_device rd; + + uint8_t padding = rd(); + + while (dataSize <= padding) + { + padding /= 2; + } + + return padding; + } + + bool ClientHttp2::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const + { + std::vector buf; + buf.reserve(4096); + + headers.emplace(headers.begin(), ":status", std::to_string(static_cast(status) ) ); + + HPack::pack(buf, headers, this->stream->dynamic_table); + + uint32_t data_size = buf.size(); + + const uint8_t padding = getPaddingSize(data_size); + const uint16_t padding_size = padding + sizeof(uint8_t); + + if (padding_size) + { + if (data_size + padding_size > this->stream->settings.max_frame_size) + { + data_size = this->stream->settings.max_frame_size - padding_size; + } + } + + const size_t frame_size = data_size + padding_size; + + Http2::FrameFlag flags = Http2::FrameFlag::END_HEADERS; + + if (endStream) + { + flags |= Http2::FrameFlag::END_STREAM; + } + + if (padding_size) + { + flags |= Http2::FrameFlag::PADDED; + + buf.insert(buf.begin(), sizeof(uint8_t), padding); + + if (padding) + { + buf.insert(buf.end(), padding, 0); + } + } + + buf.insert(buf.begin(), Http2::FRAME_HEADER_SIZE, 0); + + this->stream->setHttp2FrameHeader(reinterpret_cast(buf.data() ), frame_size, Http2::FrameType::HEADERS, flags); + + return this->sock->nonblock_send(buf.data(), buf.size(), timeout) > 0; + } + + void ClientHttp2::sendWindowUpdate(const uint32_t size, const std::chrono::milliseconds &timeout) const + { + std::array buf; + uint8_t *addr = buf.data(); + + addr = this->stream->setHttp2FrameHeader(addr, sizeof(uint32_t), Http2::FrameType::WINDOW_UPDATE, Http2::FrameFlag::EMPTY); + + *reinterpret_cast(addr) = ::htonl(size); + + this->sock->nonblock_send(buf.data(), buf.size(), timeout); + } + + long ClientHttp2::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const + { + const uint8_t *data = reinterpret_cast(src); + + std::vector buf; + buf.reserve(this->stream->settings.max_frame_size + Http2::FRAME_HEADER_SIZE); + + size_t total = 0; + + while (total < size) + { + buf.resize(0); + + size_t data_size = (size - total < this->stream->settings.max_frame_size) ? size - total : this->stream->settings.max_frame_size; + + const uint8_t padding = getPaddingSize(data_size); + const uint16_t padding_size = padding + sizeof(uint8_t); + + if (padding_size) + { + if (data_size + padding_size > this->stream->settings.max_frame_size) + { + data_size = this->stream->settings.max_frame_size - padding_size; + } + } + + const size_t frame_size = data_size + padding_size; + + if (static_cast(this->stream->window_size_out - this->stream->settings.max_frame_size) <= 0) + { + size_t update_size = this->stream->settings.initial_window_size + (size - total) - this->stream->window_size_out; + + if (update_size > Http2::MAX_WINDOW_UPDATE) + { + update_size = Http2::MAX_WINDOW_UPDATE; + } + + this->sendWindowUpdate(static_cast(update_size), timeout); + + this->stream->window_size_out += update_size; + } + + Http2::FrameFlag flags = Http2::FrameFlag::EMPTY; + + if (endStream && (total + data_size >= size) ) + { + flags |= Http2::FrameFlag::END_STREAM; + } + + if (padding_size) + { + flags |= Http2::FrameFlag::PADDED; + + buf.insert(buf.begin(), sizeof(uint8_t), padding); + } + + buf.insert(buf.begin(), Http2::FRAME_HEADER_SIZE, 0); + + const Http2::FrameType frame_type = Http2::FrameType::DATA; + + this->stream->setHttp2FrameHeader(buf.data(), frame_size, frame_type, flags); + + std::copy(data, data + data_size, std::back_inserter(buf) ); + + if (padding) + { + buf.insert(buf.end(), padding, 0); + } + + long sended = this->sock->nonblock_send(buf.data(), buf.size(), timeout); + + if (sended <= 0) + { + break; + } + + this->stream->window_size_out -= frame_size; + + data += data_size; + total += data_size; + } + + return total; + } +}; diff --git a/src/client/protocol/ClientHttp2.h b/src/client/protocol/ClientHttp2.h new file mode 100644 index 0000000..9aedbca --- /dev/null +++ b/src/client/protocol/ClientHttp2.h @@ -0,0 +1,23 @@ +#pragma once + +#include "ClientProtocol.h" + +#include "../../transfer/http2/Http2.h" + +namespace HttpClient +{ + class ClientHttp2 : public ClientProtocol + { + protected: + Http2::OutStream *stream; + + public: + ClientHttp2(Socket::Adapter *sock, Http2::OutStream *stream); + virtual ~ClientHttp2() noexcept; + + void sendWindowUpdate(const uint32_t size, const std::chrono::milliseconds &timeout) const; + + virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; + virtual long sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; + }; +}; diff --git a/src/client/protocol/ClientProtocol.cpp b/src/client/protocol/ClientProtocol.cpp new file mode 100644 index 0000000..ca759f1 --- /dev/null +++ b/src/client/protocol/ClientProtocol.cpp @@ -0,0 +1,20 @@ + +#include "ClientProtocol.h" + +namespace HttpClient +{ + ClientProtocol::ClientProtocol(Socket::Adapter *sock) : sock(sock) + { + + } + + Socket::Adapter *ClientProtocol::getSocket() noexcept + { + return this->sock; + } + + void ClientProtocol::close() noexcept + { + this->sock->close(); + } +}; diff --git a/src/client/protocol/ClientProtocol.h b/src/client/protocol/ClientProtocol.h new file mode 100644 index 0000000..58ad9f2 --- /dev/null +++ b/src/client/protocol/ClientProtocol.h @@ -0,0 +1,24 @@ +#pragma once + +#include "../../socket/Adapter.h" +#include "../../transfer/HttpStatusCode.h" + +namespace HttpClient +{ + class ClientProtocol + { + protected: + Socket::Adapter *sock; + + public: + ClientProtocol(Socket::Adapter *sock); + virtual ~ClientProtocol() noexcept = default; + + Socket::Adapter *getSocket() noexcept; + + virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream = true) const = 0; + virtual long sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream = true) const = 0; + + virtual void close() noexcept; + }; +}; diff --git a/src/socket/Adapter.cpp b/src/socket/Adapter.cpp new file mode 100644 index 0000000..d0524b0 --- /dev/null +++ b/src/socket/Adapter.cpp @@ -0,0 +1,25 @@ + +#include "Adapter.h" + +namespace Socket +{ + long Adapter::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept + { + return this->nonblock_recv(buf.data(), buf.size(), timeout); + } + + long Adapter::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const noexcept + { + return this->nonblock_send(buf.data(), buf.length(), timeout); + } + + bool Adapter::operator ==(const Adapter &obj) const noexcept + { + return this->get_handle() == obj.get_handle(); + } + + bool Adapter::operator !=(const Adapter &obj) const noexcept + { + return this->get_handle() != obj.get_handle(); + } +}; diff --git a/src/socket/Adapter.h b/src/socket/Adapter.h new file mode 100644 index 0000000..554714f --- /dev/null +++ b/src/socket/Adapter.h @@ -0,0 +1,33 @@ +#pragma once + +#include "../system/System.h" + +#include +#include +#include + +#include + +namespace Socket +{ + class Adapter + { + public: + virtual ~Adapter() noexcept = default; + + virtual System::native_socket_type get_handle() const noexcept = 0; + virtual ::gnutls_session_t get_tls_session() const noexcept = 0; + virtual Adapter *copy() const noexcept = 0; + + long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept; + virtual long nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept = 0; + + long nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const noexcept; + virtual long nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept = 0; + + virtual void close() noexcept = 0; + + bool operator ==(const Adapter &obj) const noexcept; + bool operator !=(const Adapter &obj) const noexcept; + }; +}; diff --git a/src/socket/AdapterDefault.cpp b/src/socket/AdapterDefault.cpp new file mode 100644 index 0000000..d71d6a2 --- /dev/null +++ b/src/socket/AdapterDefault.cpp @@ -0,0 +1,44 @@ + +#include "AdapterDefault.h" + +namespace Socket +{ + AdapterDefault::AdapterDefault(const Socket &_sock) noexcept : sock(_sock) + { + + } + + System::native_socket_type AdapterDefault::get_handle() const noexcept + { + return sock.get_handle(); + } + + ::gnutls_session_t AdapterDefault::get_tls_session() const noexcept + { + return 0; + } + + Adapter *AdapterDefault::copy() const noexcept + { + return new AdapterDefault(this->sock); + } + + long AdapterDefault::nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept + { + return sock.nonblock_recv(buf, length, timeout); + } + + long AdapterDefault::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept + { + return sock.nonblock_send(buf, length, timeout); + } + + void AdapterDefault::close() noexcept + { + // Wait for send all data to client + sock.nonblock_send_sync(); + + sock.shutdown(); + sock.close(); + } +}; diff --git a/src/socket/AdapterDefault.h b/src/socket/AdapterDefault.h new file mode 100644 index 0000000..0008fa9 --- /dev/null +++ b/src/socket/AdapterDefault.h @@ -0,0 +1,26 @@ +#pragma once + +#include "Adapter.h" +#include "Socket.h" + +namespace Socket +{ + class AdapterDefault : public Adapter + { + private: + Socket sock; + + public: + AdapterDefault() = delete; + AdapterDefault(const Socket &_sock) noexcept; + + virtual System::native_socket_type get_handle() const noexcept override; + virtual ::gnutls_session_t get_tls_session() const noexcept override; + virtual Adapter *copy() const noexcept override; + + virtual long nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept override; + virtual long nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept override; + + virtual void close() noexcept override; + }; +}; diff --git a/src/socket/AdapterTls.cpp b/src/socket/AdapterTls.cpp new file mode 100644 index 0000000..2c88aec --- /dev/null +++ b/src/socket/AdapterTls.cpp @@ -0,0 +1,136 @@ + +#include "AdapterTls.h" + +namespace Socket +{ + AdapterTls::AdapterTls(const Socket &sock, ::gnutls_priority_t priority_cache, ::gnutls_certificate_credentials_t x509_cred) noexcept + { + // https://leandromoreira.com.br/2015/10/12/how-to-optimize-nginx-configuration-for-http2-tls-ssl/ + // https://www.gnutls.org/manual/html_node/False-Start.html + + #ifdef GNUTLS_ENABLE_FALSE_START + constexpr int flags = GNUTLS_SERVER | GNUTLS_ENABLE_FALSE_START; + #else + constexpr int flags = GNUTLS_SERVER; + #endif + + ::gnutls_init(&this->session, flags); + ::gnutls_priority_set(this->session, priority_cache); + ::gnutls_credentials_set(this->session, GNUTLS_CRD_CERTIFICATE, x509_cred); + + ::gnutls_certificate_server_set_request(this->session, GNUTLS_CERT_IGNORE); + + ::gnutls_transport_set_int2(this->session, sock.get_handle(), sock.get_handle() ); + + char h2[] = "h2"; + char http11[] = "http/1.1"; + + const ::gnutls_datum_t protocols[] { + { reinterpret_cast(h2), sizeof(h2) - 1 }, + { reinterpret_cast(http11), sizeof(http11) - 1 }, + }; + + ::gnutls_alpn_set_protocols(this->session, protocols, sizeof(protocols) / sizeof(::gnutls_datum_t), 0); + } + + AdapterTls::AdapterTls(const ::gnutls_session_t session) noexcept : session(session) + { + + } + + bool AdapterTls::handshake() noexcept + { + int ret; + + do + { + ret = ::gnutls_handshake(this->session); + } + while (ret < 0 && ::gnutls_error_is_fatal(ret) == 0); + + if (ret < 0) + { + Socket sock(this->get_handle() ); + + sock.close(); + ::gnutls_deinit(this->session); + + return false; + } + + return true; + } + + long AdapterTls::nonblock_send_all(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept + { + size_t record_size = ::gnutls_record_get_max_size(this->session); + + if (0 == record_size) + { + return -1; + } + + size_t total = 0; + + while (total < length) + { + ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); + + if (record_size > length - total) + { + record_size = length - total; + } + + const long send_size = ::gnutls_record_send(this->session, reinterpret_cast(buf) + total, record_size); + + if (send_size < 0) + { + return send_size; + } + + total += send_size; + } + + return static_cast(total); + } + + System::native_socket_type AdapterTls::get_handle() const noexcept + { + return static_cast(::gnutls_transport_get_int(this->session) ); + } + + ::gnutls_session_t AdapterTls::get_tls_session() const noexcept + { + return this->session; + } + + Adapter *AdapterTls::copy() const noexcept + { + return new AdapterTls(this->session); + } + + long AdapterTls::nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept + { + ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); + return ::gnutls_record_recv(this->session, buf, length); + } + + long AdapterTls::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept + { + return this->nonblock_send_all(buf, length, timeout); + } + + void AdapterTls::close() noexcept + { + Socket sock(this->get_handle() ); + + // Wait for send all data to client + sock.nonblock_send_sync(); + + ::gnutls_bye(this->session, GNUTLS_SHUT_RDWR); + + sock.close(); + + ::gnutls_deinit(this->session); + } +}; diff --git a/src/socket/AdapterTls.h b/src/socket/AdapterTls.h new file mode 100644 index 0000000..5751b7e --- /dev/null +++ b/src/socket/AdapterTls.h @@ -0,0 +1,30 @@ +#pragma once + +#include "Adapter.h" +#include "Socket.h" + +namespace Socket +{ + class AdapterTls : public Adapter + { + private: + ::gnutls_session_t session; + + public: + AdapterTls() = delete; + AdapterTls(const Socket &sock, ::gnutls_priority_t priority_cache, ::gnutls_certificate_credentials_t x509_cred) noexcept; + AdapterTls(const ::gnutls_session_t session) noexcept; + + bool handshake() noexcept; + long nonblock_send_all(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept; + + virtual System::native_socket_type get_handle() const noexcept override; + virtual ::gnutls_session_t get_tls_session() const noexcept override; + virtual Adapter *copy() const noexcept override; + + virtual long nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept override; + virtual long nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept override; + + virtual void close() noexcept override; + }; +}; diff --git a/src/socket/List.cpp b/src/socket/List.cpp new file mode 100644 index 0000000..2d07b23 --- /dev/null +++ b/src/socket/List.cpp @@ -0,0 +1,383 @@ + +#include "List.h" + +#ifdef POSIX + #include + #include + #include +#endif + +namespace Socket +{ + List::List() noexcept + { + #ifdef WIN32 + this->obj_list = INVALID_HANDLE_VALUE; + #elif POSIX + this->obj_list = ~0; + #else + #error "Undefine platform" + #endif + } + + List::List(List &&obj) noexcept + : obj_list(obj.obj_list) + { + #ifdef WIN32 + obj.obj_list = INVALID_HANDLE_VALUE; + obj.poll_events.swap(this->poll_events); + #elif POSIX + obj.obj_list = ~0; + obj.epoll_events.swap(this->epoll_events); + #else + #error "Undefine platform" + #endif + } + + List::~List() noexcept + { + this->destroy(); + } + + bool List::create(const size_t startListSize) + { + this->destroy(); + + #ifdef WIN32 + this->obj_list = (HANDLE) 1; + + if (startListSize > 0) + { + this->poll_events.reserve(startListSize); + } + + return true; + #elif POSIX + this->obj_list = ::epoll_create(startListSize); + + if (this->obj_list == ~0) + { + return false; + } + + if (startListSize > 0) + { + this->epoll_events.reserve(startListSize); + } + + return true; + #else + #error "Undefine platform" + #endif + } + + void List::destroy() noexcept + { + if (this->is_created() ) + { + #ifdef WIN32 + this->obj_list = INVALID_HANDLE_VALUE; + this->poll_events.clear(); + #elif POSIX + ::close(this->obj_list); + this->obj_list = ~0; + this->epoll_events.clear(); + #else + #error "Undefine platform" + #endif + } + } + + bool List::is_created() const noexcept + { + #ifdef WIN32 + return this->obj_list != INVALID_HANDLE_VALUE; + #elif POSIX + return this->obj_list != ~0; + #else + #error "Undefine platform" + #endif + } + + bool List::addSocket(const Socket &sock) noexcept + { + if (false == this->is_created() ) + { + return false; + } + + #ifdef WIN32 + WSAPOLLFD event = { + sock.get_handle(), + POLLRDNORM, + 0 + }; + + poll_events.emplace_back(event); + + return true; + #elif POSIX + struct ::epoll_event event = { + EPOLLIN | EPOLLET | EPOLLRDHUP, + reinterpret_cast(sock.get_handle() ) + }; + + const int result = ::epoll_ctl(this->obj_list, EPOLL_CTL_ADD, sock.get_handle(), &event); + + if (result == ~0) + { + return false; + } + + this->epoll_events.emplace_back(); + + return true; + #else + #error "Undefine platform" + #endif + } + + bool List::removeSocket(const Socket &sock) noexcept + { + if (false == this->is_created() ) + { + return false; + } + + #ifdef WIN32 + for (size_t i = 0; i < poll_events.size(); ++i) + { + if (sock.get_handle() == poll_events[i].fd) + { + poll_events.erase(poll_events.begin() + i); + return true; + } + } + + return false; + #elif POSIX + const int result = ::epoll_ctl(this->obj_list, EPOLL_CTL_DEL, sock.get_handle(), nullptr); + + if (result == ~0) + { + return false; + } + + this->epoll_events.pop_back(); + + return true; + #else + #error "Undefine platform" + #endif + } + + bool List::accept(std::vector &sockets) const noexcept + { + if (this->is_created() ) + { + #ifdef WIN32 + const int count = ::WSAPoll(this->poll_events.data(), static_cast<::ULONG>(this->poll_events.size() ), ~0); + + if (SOCKET_ERROR == count) + { + return false; + } + + for (size_t i = 0; i < this->poll_events.size(); ++i) + { + const WSAPOLLFD &event = this->poll_events[i]; + + if (event.revents & POLLRDNORM) + { + System::native_socket_type client_socket = ~0; + + do + { + client_socket = ::accept(event.fd, static_cast(nullptr), static_cast(nullptr) ); + + if (~0 != client_socket) + { + sockets.emplace_back(Socket(client_socket) ); + } + } + while (~0 != client_socket); + } + } + + return false == sockets.empty(); + #elif POSIX + const int count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); + + if (count == ~0) + { + return false; + } + + for (int i = 0; i < count; ++i) + { + const epoll_event &event = this->epoll_events[i]; + + if (event.events & EPOLLIN) + { + System::native_socket_type client_socket = ~0; + + do + { + client_socket = ::accept(event.data.fd, static_cast(nullptr), static_cast(nullptr) ); + + if (~0 != client_socket) + { + sockets.emplace_back(Socket(client_socket) ); + } + } + while (~0 != client_socket); + } + } + + return false == sockets.empty(); + #else + #error "Undefine platform" + #endif + } + + return false; + } + + bool List::accept(std::vector &sockets, std::vector &socketsAddress) const noexcept + { + if (this->is_created() ) + { + #ifdef WIN32 + const int count = ::WSAPoll(this->poll_events.data(), static_cast<::ULONG>(this->poll_events.size() ), ~0); + + if (SOCKET_ERROR == count) + { + return false; + } + + for (size_t i = 0; i < this->poll_events.size(); ++i) + { + const WSAPOLLFD &event = this->poll_events[i]; + + if (event.revents & POLLRDNORM) + { + System::native_socket_type client_socket = ~0; + + do + { + struct ::sockaddr_in client_addr = {}; + socklen_t client_addr_len = sizeof(client_addr); + + client_socket = ::accept(event.fd, static_cast(&client_addr), &client_addr_len); + + if (~0 != client_socket) + { + sockets.emplace_back(Socket(client_socket) ); + socketsAddress.emplace_back(client_addr); + } + } + while (~0 != client_socket); + } + } + + return false == sockets.empty(); + #elif POSIX + const int count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); + + if (count == ~0) + { + return false; + } + + for (int i = 0; i < count; ++i) + { + const epoll_event &event = this->epoll_events[i]; + + if (event.events & EPOLLIN) + { + System::native_socket_type client_socket = ~0; + + do + { + struct ::sockaddr_in client_addr = {}; + socklen_t client_addr_len = sizeof(client_addr); + + client_socket = ::accept(event.data.fd, reinterpret_cast(&client_addr), &client_addr_len); + + if (~0 != client_socket) + { + sockets.emplace_back(Socket(client_socket) ); + socketsAddress.emplace_back(client_addr); + } + } + while (~0 != client_socket); + } + } + + return false == sockets.empty(); + #else + #error "Undefine platform" + #endif + } + + return false; + } + + bool List::recv(std::vector &sockets, std::vector &disconnected, std::chrono::milliseconds timeout) const noexcept + { + if (false == this->is_created() ) + { + return false; + } + + #ifdef WIN32 + const int count = ::WSAPoll(this->poll_events.data(), static_cast<::ULONG>(this->poll_events.size() ), static_cast<::INT>(timeout.count() ) ); + + if (SOCKET_ERROR == count) + { + return false; + } + + for (size_t i = 0; i < this->poll_events.size(); ++i) + { + const WSAPOLLFD &event = this->poll_events[i]; + + if (event.revents & POLLRDNORM) + { + sockets.emplace_back(Socket(event.fd) ); + } + else if (event.revents & POLLHUP) + { + disconnected.emplace_back(Socket(event.fd) ); + } + } + + return false == sockets.empty() || false == disconnected.empty(); + #elif POSIX + const int count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), timeout.count() ); + + if (count == ~0) + { + return false; + } + + for (int i = 0; i < count; ++i) + { + const epoll_event &event = this->epoll_events[i]; + + if (event.events & EPOLLIN) + { + sockets.emplace_back(Socket(event.data.fd) ); + } + else if (event.events & EPOLLRDHUP) + { + disconnected.emplace_back(Socket(event.data.fd) ); + } + } + + return false == sockets.empty() || false == disconnected.empty(); + #else + #error "Undefine platform" + #endif + } +}; diff --git a/src/socket/List.h b/src/socket/List.h new file mode 100644 index 0000000..650447f --- /dev/null +++ b/src/socket/List.h @@ -0,0 +1,43 @@ +#pragma once + +#include "Socket.h" + +#ifdef POSIX + #include + #include +#endif + +namespace Socket +{ + class List + { + protected: + #ifdef WIN32 + HANDLE obj_list; + mutable std::vector poll_events; + #elif POSIX + int obj_list; + mutable std::vector epoll_events; + #else + #error "Undefine platform" + #endif + + public: + List() noexcept; + List(List &&obj) noexcept; + ~List() noexcept; + + bool create(const size_t startListSize = 1); + void destroy() noexcept; + + bool is_created() const noexcept; + + bool addSocket(const Socket &sock) noexcept; + bool removeSocket(const Socket &sock) noexcept; + + bool accept(std::vector &sockets) const noexcept; + bool accept(std::vector &sockets, std::vector &socketsAddress) const noexcept; + + bool recv(std::vector &sockets, std::vector &errors, std::chrono::milliseconds timeout = std::chrono::milliseconds(~0) ) const noexcept; + }; +}; diff --git a/src/Socket.cpp b/src/socket/Socket.cpp similarity index 65% rename from src/Socket.cpp rename to src/socket/Socket.cpp index ead8bb4..d9b9043 100644 --- a/src/Socket.cpp +++ b/src/socket/Socket.cpp @@ -1,9 +1,19 @@ #include "Socket.h" -namespace HttpServer +#ifdef POSIX + #include + #include + #include + #include + #include + #include + #include +#endif + +namespace Socket { - bool Socket::Startup() + bool Socket::Startup() noexcept { #ifdef WIN32 unsigned short version = MAKEWORD(2, 2); @@ -16,7 +26,7 @@ namespace HttpServer #endif } - bool Socket::Cleanup() + bool Socket::Cleanup() noexcept { #ifdef WIN32 return 0 == ::WSACleanup(); @@ -27,7 +37,7 @@ namespace HttpServer #endif } - int Socket::getLastError() + int Socket::getLastError() noexcept { #ifdef WIN32 return ::WSAGetLastError(); @@ -38,27 +48,27 @@ namespace HttpServer #endif } - Socket::Socket(): socket_handle(~0) + Socket::Socket() noexcept : socket_handle(~0) { } - Socket::Socket(const System::native_socket_type fd) : socket_handle(fd) + Socket::Socket(const System::native_socket_type fd) noexcept : socket_handle(fd) { } - Socket::Socket(const Socket &obj) : socket_handle(obj.socket_handle) + Socket::Socket(const Socket &obj) noexcept : socket_handle(obj.socket_handle) { } - Socket::Socket(Socket &&obj) : socket_handle(obj.socket_handle) + Socket::Socket(Socket &&obj) noexcept : socket_handle(obj.socket_handle) { obj.socket_handle = ~0; } - bool Socket::open() + bool Socket::open() noexcept { this->close(); @@ -67,7 +77,7 @@ namespace HttpServer return this->is_open(); } - bool Socket::close() + bool Socket::close() noexcept { if (this->is_open() ) { @@ -90,7 +100,23 @@ namespace HttpServer return false; } - bool Socket::bind(const int port) const + bool Socket::is_open() const noexcept + { + #ifdef WIN32 + return INVALID_SOCKET != this->socket_handle; + #elif POSIX + return ~0 != this->socket_handle; + #else + #error "Undefine platform" + #endif + } + + System::native_socket_type Socket::get_handle() const noexcept + { + return this->socket_handle; + } + + bool Socket::bind(const int port) const noexcept { const ::sockaddr_in sock_addr = { AF_INET, @@ -102,12 +128,12 @@ namespace HttpServer return 0 == ::bind(this->socket_handle, reinterpret_cast(&sock_addr), sizeof(sockaddr_in) ); } - bool Socket::listen() const + bool Socket::listen() const noexcept { return 0 == ::listen(this->socket_handle, SOMAXCONN); } - Socket Socket::accept() const + Socket Socket::accept() const noexcept { #ifdef WIN32 System::native_socket_type client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); @@ -119,7 +145,7 @@ namespace HttpServer return Socket(client_socket); } - Socket Socket::nonblock_accept() const + Socket Socket::nonblock_accept() const noexcept { System::native_socket_type client_socket = ~0; #ifdef WIN32 @@ -150,7 +176,7 @@ namespace HttpServer return Socket(client_socket); } - Socket Socket::nonblock_accept(const std::chrono::milliseconds &timeout) const + Socket Socket::nonblock_accept(const std::chrono::milliseconds &timeout) const noexcept { System::native_socket_type client_socket = ~0; #ifdef WIN32 @@ -160,7 +186,7 @@ namespace HttpServer 0 }; - if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLRDNORM) + if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLRDNORM) { client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); } @@ -181,7 +207,7 @@ namespace HttpServer return Socket(client_socket); } - bool Socket::shutdown() const + bool Socket::shutdown() const noexcept { if (is_open() ) { @@ -197,7 +223,7 @@ namespace HttpServer return false; } - bool Socket::nonblock(const bool isNonBlock) const + bool Socket::nonblock(const bool isNonBlock) const noexcept { #ifdef WIN32 unsigned long value = isNonBlock; @@ -210,7 +236,7 @@ namespace HttpServer } /* - bool Socket::is_nonblock() const + bool Socket::is_nonblock() const noexcept { #ifdef WIN32 @@ -223,7 +249,7 @@ namespace HttpServer } */ - bool Socket::tcp_nodelay(const bool nodelay) const + bool Socket::tcp_nodelay(const bool nodelay) const noexcept { #ifdef WIN32 int flags = nodelay ? 1 : 0; @@ -236,41 +262,51 @@ namespace HttpServer #endif } - long Socket::recv(std::vector &buf) const + long Socket::recv(std::vector &buf) const noexcept + { + return this->recv(buf.data(), buf.size() ); + } + + long Socket::recv(void *buf, const size_t length) const noexcept { #ifdef WIN32 - return ::recv(this->socket_handle, buf.data(), buf.size(), 0); + return ::recv(this->socket_handle, buf, static_cast(length), 0); #elif POSIX - return ::recv(this->socket_handle, buf.data(), buf.size(), 0); + return ::recv(this->socket_handle, buf, length, 0); #else #error "Undefine platform" #endif } - long Socket::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const + long Socket::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept + { + return this->nonblock_recv(buf.data(), buf.size(), timeout); + } + + long Socket::nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { long recv_len = ~0; #ifdef WIN32 - WSAPOLLFD event = { + WSAPOLLFD event = { this->socket_handle, - POLLRDNORM, - 0 - }; + POLLRDNORM, + 0 + }; - if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLRDNORM) - { - recv_len = ::recv(this->socket_handle, buf.data(), buf.size(), 0); + if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLRDNORM) + { + recv_len = this->recv(this->socket_handle, buf, static_cast(length), 0); } #elif POSIX - struct ::pollfd event = { + struct ::pollfd event = { this->socket_handle, - POLLIN, - 0 - }; + POLLIN, + 0 + }; if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLIN) { - recv_len = ::recv(this->socket_handle, buf.data(), buf.size(), 0); + recv_len = ::recv(this->socket_handle, buf, length, 0); } #else #error "Undefine platform" @@ -278,7 +314,7 @@ namespace HttpServer return recv_len; } - static long send_all(const System::native_socket_type socket_handle, const void *data, const size_t length) + static long send_all(const System::native_socket_type socket_handle, const void *data, const size_t length) noexcept { size_t total = 0; @@ -294,20 +330,20 @@ namespace HttpServer total += send_size; } - return total; + return static_cast(total); } - long Socket::send(const std::string &buf) const + long Socket::send(const std::string &buf) const noexcept { - return send_all(this->socket_handle, buf.data(), buf.length() ); + return this->send(buf.data(), buf.length() ); } - long Socket::send(const std::vector &buf, const size_t length) const + long Socket::send(const void *buf, const size_t length) const noexcept { - return send_all(this->socket_handle, buf.data(), length); + return send_all(this->socket_handle, buf, length); } - static long nonblock_send_all(const System::native_socket_type socket_handle, const void *data, const size_t length, const std::chrono::milliseconds &timeout) + static long nonblock_send_all(const System::native_socket_type socket_handle, const void *data, const size_t length, const std::chrono::milliseconds &timeout) noexcept { size_t total = 0; @@ -320,9 +356,9 @@ namespace HttpServer while (total < length) { - if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLWRNORM) + if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLWRNORM) { - const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, length - total, 0); + const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, static_cast(length - total), 0); if (send_size < 0) { @@ -366,20 +402,20 @@ namespace HttpServer #error "Undefine platform" #endif - return total; + return static_cast(total); } - long Socket::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const + long Socket::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const noexcept { - return nonblock_send_all(this->socket_handle, buf.data(), buf.length(), timeout); + return this->nonblock_send(buf.data(), buf.length(), timeout); } - long Socket::nonblock_send(const std::vector &buf, const size_t length, const std::chrono::milliseconds &timeout) const + long Socket::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { - return nonblock_send_all(this->socket_handle, buf.data(), length, timeout); + return nonblock_send_all(this->socket_handle, buf, length, timeout); } - void Socket::nonblock_send_sync() const + void Socket::nonblock_send_sync() const noexcept { #ifdef WIN32 WSAPOLLFD event = { @@ -402,19 +438,19 @@ namespace HttpServer #endif } - Socket &Socket::operator=(const Socket &obj) + Socket &Socket::operator=(const Socket &obj) noexcept { this->socket_handle = obj.socket_handle; return *this; } - bool Socket::operator ==(const Socket &obj) const + bool Socket::operator ==(const Socket &obj) const noexcept { return this->socket_handle == obj.socket_handle; } - bool Socket::operator !=(const Socket &obj) const + bool Socket::operator !=(const Socket &obj) const noexcept { return this->socket_handle != obj.socket_handle; } -}; \ No newline at end of file +}; diff --git a/src/socket/Socket.h b/src/socket/Socket.h new file mode 100644 index 0000000..26f40a5 --- /dev/null +++ b/src/socket/Socket.h @@ -0,0 +1,79 @@ +#pragma once + +#include "../system/System.h" + +#include +#include +#include + +namespace Socket +{ + class Socket + { + protected: + System::native_socket_type socket_handle; + + public: + bool static Startup() noexcept; + bool static Cleanup() noexcept; + int static getLastError() noexcept; + + public: + Socket() noexcept; + Socket(const System::native_socket_type fd) noexcept; + Socket(const Socket &obj) noexcept; + Socket(Socket &&obj) noexcept; + + ~Socket() noexcept = default; + + bool open() noexcept; + bool close() noexcept; + + bool is_open() const noexcept; + System::native_socket_type get_handle() const noexcept; + + bool bind(const int port) const noexcept; + bool listen() const noexcept; + + Socket accept() const noexcept; + Socket nonblock_accept() const noexcept; + Socket nonblock_accept(const std::chrono::milliseconds &timeout) const noexcept; + + bool shutdown() const noexcept; + + bool nonblock(const bool isNonBlock = true) const noexcept; + // bool is_nonblock() const noexcept; + bool tcp_nodelay(const bool nodelay = true) const noexcept; + + long recv(std::vector &buf) const noexcept; + long recv(void *buf, const size_t length) const noexcept; + + long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept; + long nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept; + + long send(const std::string &buf) const noexcept; + long send(const void *buf, const size_t length) const noexcept; + + long nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const noexcept; + long nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept; + + void nonblock_send_sync() const noexcept; + + Socket &operator =(const Socket &obj) noexcept; + + bool operator ==(const Socket &obj) const noexcept; + bool operator !=(const Socket &obj) const noexcept; + }; +}; + +namespace std +{ + // Hash for Socket + template<> struct hash + { + std::size_t operator()(const Socket::Socket &obj) const noexcept + { + return std::hash{}(obj.get_handle() ); + } + }; +}; diff --git a/src/System.cpp b/src/system/System.cpp similarity index 58% rename from src/System.cpp rename to src/system/System.cpp index 636f4cd..b32f51c 100644 --- a/src/System.cpp +++ b/src/system/System.cpp @@ -10,6 +10,11 @@ #ifdef UNICODE #include #endif +#elif POSIX + #include + #include + #include + #include #endif namespace System @@ -33,7 +38,7 @@ namespace System { std::array<::TCHAR, 257> class_name; - ::GetClassName(hWnd, class_name.data(), class_name.size() - 1); + ::GetClassName(hWnd, class_name.data(), static_cast(class_name.size() - 1) ); if (0 == ::_tcscmp(class_name.data(), myWndClassName) ) { @@ -47,7 +52,48 @@ namespace System } #endif - bool sendSignal(const native_processid_type pid, const int signal) + native_processid_type getProcessId() noexcept + { + #ifdef WIN32 + return ::GetCurrentProcessId(); + #elif POSIX + return ::getpid(); + #else + #error "Undefine platform" + #endif + } + + bool changeCurrentDirectory(const std::string &dir) + { + #ifdef WIN32 + #ifdef UNICODE + std::wstring_convert > converter; + const std::wstring target = converter.from_bytes(dir); + #else + const std::string &target = dir; + #endif + return 0 != ::SetCurrentDirectory(target.c_str() ); + #elif POSIX + return 0 == ::chdir(dir.c_str() ); + #else + #error "Undefine platform" + #endif + } + + bool isProcessExists(const native_processid_type pid) noexcept + { + #ifdef WIN32 + HANDLE hProcess = ::OpenProcess(SYNCHRONIZE, false, pid); + ::CloseHandle(hProcess); + return 0 != hProcess; + #elif POSIX + return 0 == ::kill(pid, 0); + #else + #error "Undefine platform" + #endif + } + + bool sendSignal(const native_processid_type pid, const int signal) noexcept { #ifdef WIN32 EnumData ed = {pid, 0}; @@ -67,15 +113,26 @@ namespace System #endif } + bool isDoneThread(const std::thread::native_handle_type handle) noexcept + { + #ifdef WIN32 + return WAIT_OBJECT_0 == ::WaitForSingleObject(handle, 0); + #elif POSIX + return 0 != ::pthread_kill(handle, 0); + #else + #error "Undefine platform" + #endif + } + std::string getTempDir() { #ifdef WIN32 - std::array buf; + std::array<::TCHAR, MAX_PATH + 1> buf; - auto const len = ::GetTempPath(buf.size(), buf.data() ); + auto const len = ::GetTempPath(static_cast<::DWORD>(buf.size() ), buf.data() ); #ifdef UNICODE - std::wstring_convert> converter; + std::wstring_convert > converter; return converter.to_bytes(buf.data() ); #else return std::string(buf.cbegin(), buf.cbegin() + len); @@ -207,4 +264,57 @@ namespace System #error "Undefine platform" #endif } -}; \ No newline at end of file + + void filterSharedMemoryName(std::string &memName) + { + #ifdef WIN32 + #ifdef UNICODE + std::wstring_convert > converter; + std::wstring memory_name = converter.from_bytes(memName); + const std::wstring file_ext = L".exe"; + #else + std::string &memory_name = memName; + const std::string file_ext = ".exe"; + #endif + + const size_t pos = memory_name.rfind(file_ext); + + if (pos == memory_name.length() - file_ext.length() ) + { + memory_name.erase(memory_name.begin() + pos, memory_name.end() ); + } + + ::TCHAR buf[MAX_PATH + 1] = {}; + ::GetFullPathName(memory_name.c_str(), MAX_PATH, buf, nullptr); + + #ifdef UNICODE + memName = converter.to_bytes(buf); + #else + memName = buf; + #endif + + for (size_t i = 1; i < memName.length(); ++i) + { + if ('/' == memName[i] || '\\' == memName[i]) + { + memName[i] = '-'; + } + } + #elif POSIX + if ('/' != memName.front() ) + { + memName = '/' + memName; + } + + for (size_t i = 1; i < memName.length(); ++i) + { + if ('/' == memName[i] || '\\' == memName[i]) + { + memName[i] = '-'; + } + } + #else + #error "Undefine platform" + #endif + } +}; diff --git a/src/System.h b/src/system/System.h similarity index 64% rename from src/System.h rename to src/system/System.h index 87d0fac..1ce46d2 100644 --- a/src/System.h +++ b/src/system/System.h @@ -2,9 +2,8 @@ #ifdef WIN32 #include - #include - #undef min - #undef max + + typedef long ssize_t; ::TCHAR myWndClassName[]; @@ -26,15 +25,11 @@ #define SIGUSR2 (WM_USER + 12) #endif #elif POSIX - #include - #include - #include - #include + #include #else #error "Undefine platform" #endif -#include #include #include #include @@ -57,33 +52,21 @@ namespace System #error "Undefine platform" #endif - inline native_processid_type getProcessId() - { - #ifdef WIN32 - return ::GetCurrentProcessId(); - #elif POSIX - return ::getpid(); - #else - #error "Undefine platform" - #endif - } - - bool sendSignal(const native_processid_type pid, const int signal); - - inline bool isDoneThread(const std::thread::native_handle_type handle) - { - #ifdef WIN32 - return WAIT_OBJECT_0 == ::WaitForSingleObject(handle, 0); - #elif POSIX - return 0 != ::pthread_kill(handle, 0); - #else - #error "Undefine platform" - #endif - } + native_processid_type getProcessId() noexcept; + + bool changeCurrentDirectory(const std::string &dir); + + bool isProcessExists(const native_processid_type pid) noexcept; + + bool sendSignal(const native_processid_type pid, const int signal) noexcept; + + bool isDoneThread(const std::thread::native_handle_type handle) noexcept; std::string getTempDir(); bool isFileExists(const std::string &fileName); bool getFileSizeAndTimeGmt(const std::string &filePath, size_t *fileSize, time_t *fileTime); -}; \ No newline at end of file + + void filterSharedMemoryName(std::string &memName); +}; diff --git a/src/transfer/AppRequest.h b/src/transfer/AppRequest.h new file mode 100644 index 0000000..5676b34 --- /dev/null +++ b/src/transfer/AppRequest.h @@ -0,0 +1,23 @@ +#pragma once + +#include "../socket/AdapterTls.h" +#include "FileIncoming.h" + +#include + +namespace Transfer +{ + struct request_data + { + std::unordered_multimap incoming_headers; + std::unordered_multimap incoming_data; + std::unordered_multimap incoming_files; + }; + + struct app_request + { + const System::native_socket_type socket; + const ::gnutls_session_t tls_session; + const void * const request_data; + }; +}; diff --git a/src/transfer/AppResponse.h b/src/transfer/AppResponse.h new file mode 100644 index 0000000..80937dd --- /dev/null +++ b/src/transfer/AppResponse.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +namespace Transfer +{ + struct app_response + { + void *response_data; + size_t data_size; + }; +}; diff --git a/src/transfer/FileIncoming.cpp b/src/transfer/FileIncoming.cpp new file mode 100644 index 0000000..58188fc --- /dev/null +++ b/src/transfer/FileIncoming.cpp @@ -0,0 +1,108 @@ + +#include "FileIncoming.h" +#include "../utils/Utils.h" + +#include + +namespace Transfer +{ + FileIncoming::FileIncoming(std::string &&fileTmpName, std::string &&fileName, std::string &&fileType, const size_t fileSize) noexcept + : file_tmp_name(std::move(fileTmpName) ), file_name(std::move(fileName) ), + file_type(std::move(fileType) ), file_size(fileSize) + { + + } + + FileIncoming::FileIncoming(const FileIncoming &obj) + : file_tmp_name(obj.file_tmp_name), file_name(obj.file_name), + file_type(obj.file_type), file_size(obj.file_size) + { + + } + + FileIncoming::FileIncoming(FileIncoming &&obj) noexcept + : file_tmp_name(std::move(obj.file_tmp_name) ), file_name(std::move(obj.file_name) ), + file_type(std::move(obj.file_type) ), file_size(obj.file_size) + { + obj.file_size = 0; + } + + const std::string &FileIncoming::getTmpName() const noexcept + { + return this->file_tmp_name; + } + + const std::string &FileIncoming::getName() const noexcept + { + return this->file_name; + } + + const std::string &FileIncoming::getType() const noexcept + { + return this->file_type; + } + + size_t FileIncoming::getSize() const noexcept + { + return this->file_size; + } + + bool FileIncoming::isExists() const noexcept + { + std::ifstream file(this->file_tmp_name, std::ifstream::binary); + + const bool is_exists = file.good(); + + file.close(); + + return is_exists; + } +}; + +namespace Utils +{ + void packFilesIncoming(std::vector &buf, const std::unordered_multimap &map) + { + packNumber(buf, map.size() ); + + for (auto it = map.cbegin(); map.cend() != it; ++it) + { + packString(buf, it->first); + + const Transfer::FileIncoming &file = it->second; + + packString(buf, file.getTmpName() ); + packString(buf, file.getName() ); + packString(buf, file.getType() ); + packNumber(buf, file.getSize() ); + } + } + + const uint8_t *unpackFilesIncoming(std::unordered_multimap &map, const uint8_t *src) + { + size_t count; + src = unpackNumber(&count, src); + + for (size_t i = 0; i < count; ++i) + { + std::string key; + src = unpackString(key, src); + + std::string file_tmp_name; + src = unpackString(file_tmp_name, src); + + std::string file_name; + src = unpackString(file_name, src); + + std::string file_type; + src = unpackString(file_type, src); + + size_t file_size; + src = unpackNumber(&file_size, src); + + map.emplace(std::move(key), Transfer::FileIncoming(std::move(file_tmp_name), std::move(file_name), std::move(file_type), file_size) ); + } + + return src; + } +}; diff --git a/src/transfer/FileIncoming.h b/src/transfer/FileIncoming.h new file mode 100644 index 0000000..0d853eb --- /dev/null +++ b/src/transfer/FileIncoming.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include + +namespace Transfer +{ + class FileIncoming + { + protected: + std::string file_tmp_name; + std::string file_name; + std::string file_type; + size_t file_size; + + private: + FileIncoming() = delete; + + public: + FileIncoming(std::string &&fileTmpName, std::string &&fileName, std::string &&fileType, const size_t fileSize) noexcept; + FileIncoming(const FileIncoming &obj); + FileIncoming(FileIncoming &&obj) noexcept; + + ~FileIncoming() noexcept = default; + + const std::string &getTmpName() const noexcept; + const std::string &getName() const noexcept; + const std::string &getType() const noexcept; + size_t getSize() const noexcept; + + bool isExists() const noexcept; + }; +}; + +namespace Utils +{ + void packFilesIncoming(std::vector &buf, const std::unordered_multimap &map); + const uint8_t *unpackFilesIncoming(std::unordered_multimap &map, const uint8_t *src); +}; diff --git a/src/transfer/HttpStatusCode.h b/src/transfer/HttpStatusCode.h new file mode 100644 index 0000000..169326a --- /dev/null +++ b/src/transfer/HttpStatusCode.h @@ -0,0 +1,52 @@ +#pragma once + +namespace Http +{ + enum class StatusCode + { + EMPTY = 0, + + CONTINUE = 100, + SWITCHING_PROTOCOLS = 101, + PROCESSING = 102, + + OK = 200, + CREATED = 201, + ACCEPTED = 202, + NON_AUTHORITATIVE_INFORMATION = 203, + NO_CONTENT = 204, + RESET_CONTENT = 205, + PARTIAL_CONTENT = 206, + MULTI_STATUS = 207, + + MULTIPLE_CHOISES = 300, + MOVED_PERMANENTLY = 301, + MOVED_TEMPORARILY = 302, + FOUND = 302, + SEE_OTHER = 303, + NOT_MODIFIED = 304, + USE_PROXY = 305, + TEMPORARY_REDIRECT = 307, + + BAD_REQUEST = 400, + UNAUTHORIZED = 401, + PAYMENT_REQUIRED = 402, + FORBIDDEN = 403, + NOT_FOUND = 404, + METHOD_NOT_ALLOWED = 405, + NOT_ACCEPTABLE = 406, + PROXY_AUTHENTICATION_REQUIRED = 407, + REQUEST_TIMEOUT = 408, + CONFLICT = 409, + GONE = 410, + REQUEST_ENTITY_TOO_LARGE = 413, + REQUESTED_RANGE_NOT_SATISFIABLE = 416, + + INTERNAL_SERVER_ERROR = 500, + NOT_IMPLEMENTED = 501, + BAD_GATEWAY = 502, + SERVICE_UNAVAILABLE = 503, + GATEWAY_TIMEOUT = 504, + HTTP_VERSION_NOT_SUPPORTED = 505, + }; +}; diff --git a/src/transfer/ProtocolVariant.h b/src/transfer/ProtocolVariant.h new file mode 100644 index 0000000..11954bf --- /dev/null +++ b/src/transfer/ProtocolVariant.h @@ -0,0 +1,11 @@ +#pragma once + +namespace Transfer +{ + enum class ProtocolVariant + { + UNKNOWN = 0, + HTTP_1, + HTTP_2 + }; +}; diff --git a/src/transfer/http2/HPack.cpp b/src/transfer/http2/HPack.cpp new file mode 100644 index 0000000..60889d2 --- /dev/null +++ b/src/transfer/http2/HPack.cpp @@ -0,0 +1,6038 @@ +/** + * This code getting from https://github.com/tatsuhiro-t/go-http2-hpack + */ + +#include "HPack.h" + +#include +#include +#include +#include + +namespace HPack +{ + struct HuffmanSymbol + { + int nbits; + uint32_t code; + }; + + static const HuffmanSymbol huffmanSymbolTable[] { + {13, 0x1ff8}, + {23, 0x7fffd8}, + {28, 0xfffffe2}, + {28, 0xfffffe3}, + {28, 0xfffffe4}, + {28, 0xfffffe5}, + {28, 0xfffffe6}, + {28, 0xfffffe7}, + {28, 0xfffffe8}, + {24, 0xffffea}, + {30, 0x3ffffffc}, + {28, 0xfffffe9}, + {28, 0xfffffea}, + {30, 0x3ffffffd}, + {28, 0xfffffeb}, + {28, 0xfffffec}, + {28, 0xfffffed}, + {28, 0xfffffee}, + {28, 0xfffffef}, + {28, 0xffffff0}, + {28, 0xffffff1}, + {28, 0xffffff2}, + {30, 0x3ffffffe}, + {28, 0xffffff3}, + {28, 0xffffff4}, + {28, 0xffffff5}, + {28, 0xffffff6}, + {28, 0xffffff7}, + {28, 0xffffff8}, + {28, 0xffffff9}, + {28, 0xffffffa}, + {28, 0xffffffb}, + {6, 0x14}, + {10, 0x3f8}, + {10, 0x3f9}, + {12, 0xffa}, + {13, 0x1ff9}, + {6, 0x15}, + {8, 0xf8}, + {11, 0x7fa}, + {10, 0x3fa}, + {10, 0x3fb}, + {8, 0xf9}, + {11, 0x7fb}, + {8, 0xfa}, + {6, 0x16}, + {6, 0x17}, + {6, 0x18}, + {5, 0x0}, + {5, 0x1}, + {5, 0x2}, + {6, 0x19}, + {6, 0x1a}, + {6, 0x1b}, + {6, 0x1c}, + {6, 0x1d}, + {6, 0x1e}, + {6, 0x1f}, + {7, 0x5c}, + {8, 0xfb}, + {15, 0x7ffc}, + {6, 0x20}, + {12, 0xffb}, + {10, 0x3fc}, + {13, 0x1ffa}, + {6, 0x21}, + {7, 0x5d}, + {7, 0x5e}, + {7, 0x5f}, + {7, 0x60}, + {7, 0x61}, + {7, 0x62}, + {7, 0x63}, + {7, 0x64}, + {7, 0x65}, + {7, 0x66}, + {7, 0x67}, + {7, 0x68}, + {7, 0x69}, + {7, 0x6a}, + {7, 0x6b}, + {7, 0x6c}, + {7, 0x6d}, + {7, 0x6e}, + {7, 0x6f}, + {7, 0x70}, + {7, 0x71}, + {7, 0x72}, + {8, 0xfc}, + {7, 0x73}, + {8, 0xfd}, + {13, 0x1ffb}, + {19, 0x7fff0}, + {13, 0x1ffc}, + {14, 0x3ffc}, + {6, 0x22}, + {15, 0x7ffd}, + {5, 0x3}, + {6, 0x23}, + {5, 0x4}, + {6, 0x24}, + {5, 0x5}, + {6, 0x25}, + {6, 0x26}, + {6, 0x27}, + {5, 0x6}, + {7, 0x74}, + {7, 0x75}, + {6, 0x28}, + {6, 0x29}, + {6, 0x2a}, + {5, 0x7}, + {6, 0x2b}, + {7, 0x76}, + {6, 0x2c}, + {5, 0x8}, + {5, 0x9}, + {6, 0x2d}, + {7, 0x77}, + {7, 0x78}, + {7, 0x79}, + {7, 0x7a}, + {7, 0x7b}, + {15, 0x7ffe}, + {11, 0x7fc}, + {14, 0x3ffd}, + {13, 0x1ffd}, + {28, 0xffffffc}, + {20, 0xfffe6}, + {22, 0x3fffd2}, + {20, 0xfffe7}, + {20, 0xfffe8}, + {22, 0x3fffd3}, + {22, 0x3fffd4}, + {22, 0x3fffd5}, + {23, 0x7fffd9}, + {22, 0x3fffd6}, + {23, 0x7fffda}, + {23, 0x7fffdb}, + {23, 0x7fffdc}, + {23, 0x7fffdd}, + {23, 0x7fffde}, + {24, 0xffffeb}, + {23, 0x7fffdf}, + {24, 0xffffec}, + {24, 0xffffed}, + {22, 0x3fffd7}, + {23, 0x7fffe0}, + {24, 0xffffee}, + {23, 0x7fffe1}, + {23, 0x7fffe2}, + {23, 0x7fffe3}, + {23, 0x7fffe4}, + {21, 0x1fffdc}, + {22, 0x3fffd8}, + {23, 0x7fffe5}, + {22, 0x3fffd9}, + {23, 0x7fffe6}, + {23, 0x7fffe7}, + {24, 0xffffef}, + {22, 0x3fffda}, + {21, 0x1fffdd}, + {20, 0xfffe9}, + {22, 0x3fffdb}, + {22, 0x3fffdc}, + {23, 0x7fffe8}, + {23, 0x7fffe9}, + {21, 0x1fffde}, + {23, 0x7fffea}, + {22, 0x3fffdd}, + {22, 0x3fffde}, + {24, 0xfffff0}, + {21, 0x1fffdf}, + {22, 0x3fffdf}, + {23, 0x7fffeb}, + {23, 0x7fffec}, + {21, 0x1fffe0}, + {21, 0x1fffe1}, + {22, 0x3fffe0}, + {21, 0x1fffe2}, + {23, 0x7fffed}, + {22, 0x3fffe1}, + {23, 0x7fffee}, + {23, 0x7fffef}, + {20, 0xfffea}, + {22, 0x3fffe2}, + {22, 0x3fffe3}, + {22, 0x3fffe4}, + {23, 0x7ffff0}, + {22, 0x3fffe5}, + {22, 0x3fffe6}, + {23, 0x7ffff1}, + {26, 0x3ffffe0}, + {26, 0x3ffffe1}, + {20, 0xfffeb}, + {19, 0x7fff1}, + {22, 0x3fffe7}, + {23, 0x7ffff2}, + {22, 0x3fffe8}, + {25, 0x1ffffec}, + {26, 0x3ffffe2}, + {26, 0x3ffffe3}, + {26, 0x3ffffe4}, + {27, 0x7ffffde}, + {27, 0x7ffffdf}, + {26, 0x3ffffe5}, + {24, 0xfffff1}, + {25, 0x1ffffed}, + {19, 0x7fff2}, + {21, 0x1fffe3}, + {26, 0x3ffffe6}, + {27, 0x7ffffe0}, + {27, 0x7ffffe1}, + {26, 0x3ffffe7}, + {27, 0x7ffffe2}, + {24, 0xfffff2}, + {21, 0x1fffe4}, + {21, 0x1fffe5}, + {26, 0x3ffffe8}, + {26, 0x3ffffe9}, + {28, 0xffffffd}, + {27, 0x7ffffe3}, + {27, 0x7ffffe4}, + {27, 0x7ffffe5}, + {20, 0xfffec}, + {24, 0xfffff3}, + {20, 0xfffed}, + {21, 0x1fffe6}, + {22, 0x3fffe9}, + {21, 0x1fffe7}, + {21, 0x1fffe8}, + {23, 0x7ffff3}, + {22, 0x3fffea}, + {22, 0x3fffeb}, + {25, 0x1ffffee}, + {25, 0x1ffffef}, + {24, 0xfffff4}, + {24, 0xfffff5}, + {26, 0x3ffffea}, + {23, 0x7ffff4}, + {26, 0x3ffffeb}, + {27, 0x7ffffe6}, + {26, 0x3ffffec}, + {26, 0x3ffffed}, + {27, 0x7ffffe7}, + {27, 0x7ffffe8}, + {27, 0x7ffffe9}, + {27, 0x7ffffea}, + {27, 0x7ffffeb}, + {28, 0xffffffe}, + {27, 0x7ffffec}, + {27, 0x7ffffed}, + {27, 0x7ffffee}, + {27, 0x7ffffef}, + {27, 0x7fffff0}, + {26, 0x3ffffee}, + {30, 0x3fffffff}, + }; + + struct HuffmanDecodeNode + { + uint8_t state; + uint8_t flags; + uint8_t symbol; + }; + + static const HuffmanDecodeNode huffmanDecodeTable[][16] { + { + {4, 0x00, 0}, + {5, 0x00, 0}, + {7, 0x00, 0}, + {8, 0x00, 0}, + {11, 0x00, 0}, + {12, 0x00, 0}, + {16, 0x00, 0}, + {19, 0x00, 0}, + {25, 0x00, 0}, + {28, 0x00, 0}, + {32, 0x00, 0}, + {35, 0x00, 0}, + {42, 0x00, 0}, + {49, 0x00, 0}, + {57, 0x00, 0}, + {64, 0x01, 0}, + }, + + { + {0, 0x03, 48}, + {0, 0x03, 49}, + {0, 0x03, 50}, + {0, 0x03, 97}, + {0, 0x03, 99}, + {0, 0x03, 101}, + {0, 0x03, 105}, + {0, 0x03, 111}, + {0, 0x03, 115}, + {0, 0x03, 116}, + {13, 0x00, 0}, + {14, 0x00, 0}, + {17, 0x00, 0}, + {18, 0x00, 0}, + {20, 0x00, 0}, + {21, 0x00, 0}, + }, + + { + {1, 0x02, 48}, + {22, 0x03, 48}, + {1, 0x02, 49}, + {22, 0x03, 49}, + {1, 0x02, 50}, + {22, 0x03, 50}, + {1, 0x02, 97}, + {22, 0x03, 97}, + {1, 0x02, 99}, + {22, 0x03, 99}, + {1, 0x02, 101}, + {22, 0x03, 101}, + {1, 0x02, 105}, + {22, 0x03, 105}, + {1, 0x02, 111}, + {22, 0x03, 111}, + }, + + { + {2, 0x02, 48}, + {9, 0x02, 48}, + {23, 0x02, 48}, + {40, 0x03, 48}, + {2, 0x02, 49}, + {9, 0x02, 49}, + {23, 0x02, 49}, + {40, 0x03, 49}, + {2, 0x02, 50}, + {9, 0x02, 50}, + {23, 0x02, 50}, + {40, 0x03, 50}, + {2, 0x02, 97}, + {9, 0x02, 97}, + {23, 0x02, 97}, + {40, 0x03, 97}, + }, + + { + {3, 0x02, 48}, + {6, 0x02, 48}, + {10, 0x02, 48}, + {15, 0x02, 48}, + {24, 0x02, 48}, + {31, 0x02, 48}, + {41, 0x02, 48}, + {56, 0x03, 48}, + {3, 0x02, 49}, + {6, 0x02, 49}, + {10, 0x02, 49}, + {15, 0x02, 49}, + {24, 0x02, 49}, + {31, 0x02, 49}, + {41, 0x02, 49}, + {56, 0x03, 49}, + }, + + { + {3, 0x02, 50}, + {6, 0x02, 50}, + {10, 0x02, 50}, + {15, 0x02, 50}, + {24, 0x02, 50}, + {31, 0x02, 50}, + {41, 0x02, 50}, + {56, 0x03, 50}, + {3, 0x02, 97}, + {6, 0x02, 97}, + {10, 0x02, 97}, + {15, 0x02, 97}, + {24, 0x02, 97}, + {31, 0x02, 97}, + {41, 0x02, 97}, + {56, 0x03, 97}, + }, + + { + {2, 0x02, 99}, + {9, 0x02, 99}, + {23, 0x02, 99}, + {40, 0x03, 99}, + {2, 0x02, 101}, + {9, 0x02, 101}, + {23, 0x02, 101}, + {40, 0x03, 101}, + {2, 0x02, 105}, + {9, 0x02, 105}, + {23, 0x02, 105}, + {40, 0x03, 105}, + {2, 0x02, 111}, + {9, 0x02, 111}, + {23, 0x02, 111}, + {40, 0x03, 111}, + }, + + { + {3, 0x02, 99}, + {6, 0x02, 99}, + {10, 0x02, 99}, + {15, 0x02, 99}, + {24, 0x02, 99}, + {31, 0x02, 99}, + {41, 0x02, 99}, + {56, 0x03, 99}, + {3, 0x02, 101}, + {6, 0x02, 101}, + {10, 0x02, 101}, + {15, 0x02, 101}, + {24, 0x02, 101}, + {31, 0x02, 101}, + {41, 0x02, 101}, + {56, 0x03, 101}, + }, + + { + {3, 0x02, 105}, + {6, 0x02, 105}, + {10, 0x02, 105}, + {15, 0x02, 105}, + {24, 0x02, 105}, + {31, 0x02, 105}, + {41, 0x02, 105}, + {56, 0x03, 105}, + {3, 0x02, 111}, + {6, 0x02, 111}, + {10, 0x02, 111}, + {15, 0x02, 111}, + {24, 0x02, 111}, + {31, 0x02, 111}, + {41, 0x02, 111}, + {56, 0x03, 111}, + }, + + { + {1, 0x02, 115}, + {22, 0x03, 115}, + {1, 0x02, 116}, + {22, 0x03, 116}, + {0, 0x03, 32}, + {0, 0x03, 37}, + {0, 0x03, 45}, + {0, 0x03, 46}, + {0, 0x03, 47}, + {0, 0x03, 51}, + {0, 0x03, 52}, + {0, 0x03, 53}, + {0, 0x03, 54}, + {0, 0x03, 55}, + {0, 0x03, 56}, + {0, 0x03, 57}, + }, + + { + {2, 0x02, 115}, + {9, 0x02, 115}, + {23, 0x02, 115}, + {40, 0x03, 115}, + {2, 0x02, 116}, + {9, 0x02, 116}, + {23, 0x02, 116}, + {40, 0x03, 116}, + {1, 0x02, 32}, + {22, 0x03, 32}, + {1, 0x02, 37}, + {22, 0x03, 37}, + {1, 0x02, 45}, + {22, 0x03, 45}, + {1, 0x02, 46}, + {22, 0x03, 46}, + }, + + { + {3, 0x02, 115}, + {6, 0x02, 115}, + {10, 0x02, 115}, + {15, 0x02, 115}, + {24, 0x02, 115}, + {31, 0x02, 115}, + {41, 0x02, 115}, + {56, 0x03, 115}, + {3, 0x02, 116}, + {6, 0x02, 116}, + {10, 0x02, 116}, + {15, 0x02, 116}, + {24, 0x02, 116}, + {31, 0x02, 116}, + {41, 0x02, 116}, + {56, 0x03, 116}, + }, + + { + {2, 0x02, 32}, + {9, 0x02, 32}, + {23, 0x02, 32}, + {40, 0x03, 32}, + {2, 0x02, 37}, + {9, 0x02, 37}, + {23, 0x02, 37}, + {40, 0x03, 37}, + {2, 0x02, 45}, + {9, 0x02, 45}, + {23, 0x02, 45}, + {40, 0x03, 45}, + {2, 0x02, 46}, + {9, 0x02, 46}, + {23, 0x02, 46}, + {40, 0x03, 46}, + }, + + { + {3, 0x02, 32}, + {6, 0x02, 32}, + {10, 0x02, 32}, + {15, 0x02, 32}, + {24, 0x02, 32}, + {31, 0x02, 32}, + {41, 0x02, 32}, + {56, 0x03, 32}, + {3, 0x02, 37}, + {6, 0x02, 37}, + {10, 0x02, 37}, + {15, 0x02, 37}, + {24, 0x02, 37}, + {31, 0x02, 37}, + {41, 0x02, 37}, + {56, 0x03, 37}, + }, + + { + {3, 0x02, 45}, + {6, 0x02, 45}, + {10, 0x02, 45}, + {15, 0x02, 45}, + {24, 0x02, 45}, + {31, 0x02, 45}, + {41, 0x02, 45}, + {56, 0x03, 45}, + {3, 0x02, 46}, + {6, 0x02, 46}, + {10, 0x02, 46}, + {15, 0x02, 46}, + {24, 0x02, 46}, + {31, 0x02, 46}, + {41, 0x02, 46}, + {56, 0x03, 46}, + }, + + { + {1, 0x02, 47}, + {22, 0x03, 47}, + {1, 0x02, 51}, + {22, 0x03, 51}, + {1, 0x02, 52}, + {22, 0x03, 52}, + {1, 0x02, 53}, + {22, 0x03, 53}, + {1, 0x02, 54}, + {22, 0x03, 54}, + {1, 0x02, 55}, + {22, 0x03, 55}, + {1, 0x02, 56}, + {22, 0x03, 56}, + {1, 0x02, 57}, + {22, 0x03, 57}, + }, + + { + {2, 0x02, 47}, + {9, 0x02, 47}, + {23, 0x02, 47}, + {40, 0x03, 47}, + {2, 0x02, 51}, + {9, 0x02, 51}, + {23, 0x02, 51}, + {40, 0x03, 51}, + {2, 0x02, 52}, + {9, 0x02, 52}, + {23, 0x02, 52}, + {40, 0x03, 52}, + {2, 0x02, 53}, + {9, 0x02, 53}, + {23, 0x02, 53}, + {40, 0x03, 53}, + }, + + { + {3, 0x02, 47}, + {6, 0x02, 47}, + {10, 0x02, 47}, + {15, 0x02, 47}, + {24, 0x02, 47}, + {31, 0x02, 47}, + {41, 0x02, 47}, + {56, 0x03, 47}, + {3, 0x02, 51}, + {6, 0x02, 51}, + {10, 0x02, 51}, + {15, 0x02, 51}, + {24, 0x02, 51}, + {31, 0x02, 51}, + {41, 0x02, 51}, + {56, 0x03, 51}, + }, + + { + {3, 0x02, 52}, + {6, 0x02, 52}, + {10, 0x02, 52}, + {15, 0x02, 52}, + {24, 0x02, 52}, + {31, 0x02, 52}, + {41, 0x02, 52}, + {56, 0x03, 52}, + {3, 0x02, 53}, + {6, 0x02, 53}, + {10, 0x02, 53}, + {15, 0x02, 53}, + {24, 0x02, 53}, + {31, 0x02, 53}, + {41, 0x02, 53}, + {56, 0x03, 53}, + }, + + { + {2, 0x02, 54}, + {9, 0x02, 54}, + {23, 0x02, 54}, + {40, 0x03, 54}, + {2, 0x02, 55}, + {9, 0x02, 55}, + {23, 0x02, 55}, + {40, 0x03, 55}, + {2, 0x02, 56}, + {9, 0x02, 56}, + {23, 0x02, 56}, + {40, 0x03, 56}, + {2, 0x02, 57}, + {9, 0x02, 57}, + {23, 0x02, 57}, + {40, 0x03, 57}, + }, + + { + {3, 0x02, 54}, + {6, 0x02, 54}, + {10, 0x02, 54}, + {15, 0x02, 54}, + {24, 0x02, 54}, + {31, 0x02, 54}, + {41, 0x02, 54}, + {56, 0x03, 54}, + {3, 0x02, 55}, + {6, 0x02, 55}, + {10, 0x02, 55}, + {15, 0x02, 55}, + {24, 0x02, 55}, + {31, 0x02, 55}, + {41, 0x02, 55}, + {56, 0x03, 55}, + }, + + { + {3, 0x02, 56}, + {6, 0x02, 56}, + {10, 0x02, 56}, + {15, 0x02, 56}, + {24, 0x02, 56}, + {31, 0x02, 56}, + {41, 0x02, 56}, + {56, 0x03, 56}, + {3, 0x02, 57}, + {6, 0x02, 57}, + {10, 0x02, 57}, + {15, 0x02, 57}, + {24, 0x02, 57}, + {31, 0x02, 57}, + {41, 0x02, 57}, + {56, 0x03, 57}, + }, + + { + {26, 0x00, 0}, + {27, 0x00, 0}, + {29, 0x00, 0}, + {30, 0x00, 0}, + {33, 0x00, 0}, + {34, 0x00, 0}, + {36, 0x00, 0}, + {37, 0x00, 0}, + {43, 0x00, 0}, + {46, 0x00, 0}, + {50, 0x00, 0}, + {53, 0x00, 0}, + {58, 0x00, 0}, + {61, 0x00, 0}, + {65, 0x00, 0}, + {68, 0x01, 0}, + }, + + { + {0, 0x03, 61}, + {0, 0x03, 65}, + {0, 0x03, 95}, + {0, 0x03, 98}, + {0, 0x03, 100}, + {0, 0x03, 102}, + {0, 0x03, 103}, + {0, 0x03, 104}, + {0, 0x03, 108}, + {0, 0x03, 109}, + {0, 0x03, 110}, + {0, 0x03, 112}, + {0, 0x03, 114}, + {0, 0x03, 117}, + {38, 0x00, 0}, + {39, 0x00, 0}, + }, + + { + {1, 0x02, 61}, + {22, 0x03, 61}, + {1, 0x02, 65}, + {22, 0x03, 65}, + {1, 0x02, 95}, + {22, 0x03, 95}, + {1, 0x02, 98}, + {22, 0x03, 98}, + {1, 0x02, 100}, + {22, 0x03, 100}, + {1, 0x02, 102}, + {22, 0x03, 102}, + {1, 0x02, 103}, + {22, 0x03, 103}, + {1, 0x02, 104}, + {22, 0x03, 104}, + }, + + { + {2, 0x02, 61}, + {9, 0x02, 61}, + {23, 0x02, 61}, + {40, 0x03, 61}, + {2, 0x02, 65}, + {9, 0x02, 65}, + {23, 0x02, 65}, + {40, 0x03, 65}, + {2, 0x02, 95}, + {9, 0x02, 95}, + {23, 0x02, 95}, + {40, 0x03, 95}, + {2, 0x02, 98}, + {9, 0x02, 98}, + {23, 0x02, 98}, + {40, 0x03, 98}, + }, + + { + {3, 0x02, 61}, + {6, 0x02, 61}, + {10, 0x02, 61}, + {15, 0x02, 61}, + {24, 0x02, 61}, + {31, 0x02, 61}, + {41, 0x02, 61}, + {56, 0x03, 61}, + {3, 0x02, 65}, + {6, 0x02, 65}, + {10, 0x02, 65}, + {15, 0x02, 65}, + {24, 0x02, 65}, + {31, 0x02, 65}, + {41, 0x02, 65}, + {56, 0x03, 65}, + }, + + { + {3, 0x02, 95}, + {6, 0x02, 95}, + {10, 0x02, 95}, + {15, 0x02, 95}, + {24, 0x02, 95}, + {31, 0x02, 95}, + {41, 0x02, 95}, + {56, 0x03, 95}, + {3, 0x02, 98}, + {6, 0x02, 98}, + {10, 0x02, 98}, + {15, 0x02, 98}, + {24, 0x02, 98}, + {31, 0x02, 98}, + {41, 0x02, 98}, + {56, 0x03, 98}, + }, + + { + {2, 0x02, 100}, + {9, 0x02, 100}, + {23, 0x02, 100}, + {40, 0x03, 100}, + {2, 0x02, 102}, + {9, 0x02, 102}, + {23, 0x02, 102}, + {40, 0x03, 102}, + {2, 0x02, 103}, + {9, 0x02, 103}, + {23, 0x02, 103}, + {40, 0x03, 103}, + {2, 0x02, 104}, + {9, 0x02, 104}, + {23, 0x02, 104}, + {40, 0x03, 104}, + }, + + { + {3, 0x02, 100}, + {6, 0x02, 100}, + {10, 0x02, 100}, + {15, 0x02, 100}, + {24, 0x02, 100}, + {31, 0x02, 100}, + {41, 0x02, 100}, + {56, 0x03, 100}, + {3, 0x02, 102}, + {6, 0x02, 102}, + {10, 0x02, 102}, + {15, 0x02, 102}, + {24, 0x02, 102}, + {31, 0x02, 102}, + {41, 0x02, 102}, + {56, 0x03, 102}, + }, + + { + {3, 0x02, 103}, + {6, 0x02, 103}, + {10, 0x02, 103}, + {15, 0x02, 103}, + {24, 0x02, 103}, + {31, 0x02, 103}, + {41, 0x02, 103}, + {56, 0x03, 103}, + {3, 0x02, 104}, + {6, 0x02, 104}, + {10, 0x02, 104}, + {15, 0x02, 104}, + {24, 0x02, 104}, + {31, 0x02, 104}, + {41, 0x02, 104}, + {56, 0x03, 104}, + }, + + { + {1, 0x02, 108}, + {22, 0x03, 108}, + {1, 0x02, 109}, + {22, 0x03, 109}, + {1, 0x02, 110}, + {22, 0x03, 110}, + {1, 0x02, 112}, + {22, 0x03, 112}, + {1, 0x02, 114}, + {22, 0x03, 114}, + {1, 0x02, 117}, + {22, 0x03, 117}, + {0, 0x03, 58}, + {0, 0x03, 66}, + {0, 0x03, 67}, + {0, 0x03, 68}, + }, + + { + {2, 0x02, 108}, + {9, 0x02, 108}, + {23, 0x02, 108}, + {40, 0x03, 108}, + {2, 0x02, 109}, + {9, 0x02, 109}, + {23, 0x02, 109}, + {40, 0x03, 109}, + {2, 0x02, 110}, + {9, 0x02, 110}, + {23, 0x02, 110}, + {40, 0x03, 110}, + {2, 0x02, 112}, + {9, 0x02, 112}, + {23, 0x02, 112}, + {40, 0x03, 112}, + }, + + { + {3, 0x02, 108}, + {6, 0x02, 108}, + {10, 0x02, 108}, + {15, 0x02, 108}, + {24, 0x02, 108}, + {31, 0x02, 108}, + {41, 0x02, 108}, + {56, 0x03, 108}, + {3, 0x02, 109}, + {6, 0x02, 109}, + {10, 0x02, 109}, + {15, 0x02, 109}, + {24, 0x02, 109}, + {31, 0x02, 109}, + {41, 0x02, 109}, + {56, 0x03, 109}, + }, + + { + {3, 0x02, 110}, + {6, 0x02, 110}, + {10, 0x02, 110}, + {15, 0x02, 110}, + {24, 0x02, 110}, + {31, 0x02, 110}, + {41, 0x02, 110}, + {56, 0x03, 110}, + {3, 0x02, 112}, + {6, 0x02, 112}, + {10, 0x02, 112}, + {15, 0x02, 112}, + {24, 0x02, 112}, + {31, 0x02, 112}, + {41, 0x02, 112}, + {56, 0x03, 112}, + }, + + { + {2, 0x02, 114}, + {9, 0x02, 114}, + {23, 0x02, 114}, + {40, 0x03, 114}, + {2, 0x02, 117}, + {9, 0x02, 117}, + {23, 0x02, 117}, + {40, 0x03, 117}, + {1, 0x02, 58}, + {22, 0x03, 58}, + {1, 0x02, 66}, + {22, 0x03, 66}, + {1, 0x02, 67}, + {22, 0x03, 67}, + {1, 0x02, 68}, + {22, 0x03, 68}, + }, + + { + {3, 0x02, 114}, + {6, 0x02, 114}, + {10, 0x02, 114}, + {15, 0x02, 114}, + {24, 0x02, 114}, + {31, 0x02, 114}, + {41, 0x02, 114}, + {56, 0x03, 114}, + {3, 0x02, 117}, + {6, 0x02, 117}, + {10, 0x02, 117}, + {15, 0x02, 117}, + {24, 0x02, 117}, + {31, 0x02, 117}, + {41, 0x02, 117}, + {56, 0x03, 117}, + }, + + { + {2, 0x02, 58}, + {9, 0x02, 58}, + {23, 0x02, 58}, + {40, 0x03, 58}, + {2, 0x02, 66}, + {9, 0x02, 66}, + {23, 0x02, 66}, + {40, 0x03, 66}, + {2, 0x02, 67}, + {9, 0x02, 67}, + {23, 0x02, 67}, + {40, 0x03, 67}, + {2, 0x02, 68}, + {9, 0x02, 68}, + {23, 0x02, 68}, + {40, 0x03, 68}, + }, + + { + {3, 0x02, 58}, + {6, 0x02, 58}, + {10, 0x02, 58}, + {15, 0x02, 58}, + {24, 0x02, 58}, + {31, 0x02, 58}, + {41, 0x02, 58}, + {56, 0x03, 58}, + {3, 0x02, 66}, + {6, 0x02, 66}, + {10, 0x02, 66}, + {15, 0x02, 66}, + {24, 0x02, 66}, + {31, 0x02, 66}, + {41, 0x02, 66}, + {56, 0x03, 66}, + }, + + { + {3, 0x02, 67}, + {6, 0x02, 67}, + {10, 0x02, 67}, + {15, 0x02, 67}, + {24, 0x02, 67}, + {31, 0x02, 67}, + {41, 0x02, 67}, + {56, 0x03, 67}, + {3, 0x02, 68}, + {6, 0x02, 68}, + {10, 0x02, 68}, + {15, 0x02, 68}, + {24, 0x02, 68}, + {31, 0x02, 68}, + {41, 0x02, 68}, + {56, 0x03, 68}, + }, + + { + {44, 0x00, 0}, + {45, 0x00, 0}, + {47, 0x00, 0}, + {48, 0x00, 0}, + {51, 0x00, 0}, + {52, 0x00, 0}, + {54, 0x00, 0}, + {55, 0x00, 0}, + {59, 0x00, 0}, + {60, 0x00, 0}, + {62, 0x00, 0}, + {63, 0x00, 0}, + {66, 0x00, 0}, + {67, 0x00, 0}, + {69, 0x00, 0}, + {72, 0x01, 0}, + }, + + { + {0, 0x03, 69}, + {0, 0x03, 70}, + {0, 0x03, 71}, + {0, 0x03, 72}, + {0, 0x03, 73}, + {0, 0x03, 74}, + {0, 0x03, 75}, + {0, 0x03, 76}, + {0, 0x03, 77}, + {0, 0x03, 78}, + {0, 0x03, 79}, + {0, 0x03, 80}, + {0, 0x03, 81}, + {0, 0x03, 82}, + {0, 0x03, 83}, + {0, 0x03, 84}, + }, + + { + {1, 0x02, 69}, + {22, 0x03, 69}, + {1, 0x02, 70}, + {22, 0x03, 70}, + {1, 0x02, 71}, + {22, 0x03, 71}, + {1, 0x02, 72}, + {22, 0x03, 72}, + {1, 0x02, 73}, + {22, 0x03, 73}, + {1, 0x02, 74}, + {22, 0x03, 74}, + {1, 0x02, 75}, + {22, 0x03, 75}, + {1, 0x02, 76}, + {22, 0x03, 76}, + }, + + { + {2, 0x02, 69}, + {9, 0x02, 69}, + {23, 0x02, 69}, + {40, 0x03, 69}, + {2, 0x02, 70}, + {9, 0x02, 70}, + {23, 0x02, 70}, + {40, 0x03, 70}, + {2, 0x02, 71}, + {9, 0x02, 71}, + {23, 0x02, 71}, + {40, 0x03, 71}, + {2, 0x02, 72}, + {9, 0x02, 72}, + {23, 0x02, 72}, + {40, 0x03, 72}, + }, + + { + {3, 0x02, 69}, + {6, 0x02, 69}, + {10, 0x02, 69}, + {15, 0x02, 69}, + {24, 0x02, 69}, + {31, 0x02, 69}, + {41, 0x02, 69}, + {56, 0x03, 69}, + {3, 0x02, 70}, + {6, 0x02, 70}, + {10, 0x02, 70}, + {15, 0x02, 70}, + {24, 0x02, 70}, + {31, 0x02, 70}, + {41, 0x02, 70}, + {56, 0x03, 70}, + }, + + { + {3, 0x02, 71}, + {6, 0x02, 71}, + {10, 0x02, 71}, + {15, 0x02, 71}, + {24, 0x02, 71}, + {31, 0x02, 71}, + {41, 0x02, 71}, + {56, 0x03, 71}, + {3, 0x02, 72}, + {6, 0x02, 72}, + {10, 0x02, 72}, + {15, 0x02, 72}, + {24, 0x02, 72}, + {31, 0x02, 72}, + {41, 0x02, 72}, + {56, 0x03, 72}, + }, + + { + {2, 0x02, 73}, + {9, 0x02, 73}, + {23, 0x02, 73}, + {40, 0x03, 73}, + {2, 0x02, 74}, + {9, 0x02, 74}, + {23, 0x02, 74}, + {40, 0x03, 74}, + {2, 0x02, 75}, + {9, 0x02, 75}, + {23, 0x02, 75}, + {40, 0x03, 75}, + {2, 0x02, 76}, + {9, 0x02, 76}, + {23, 0x02, 76}, + {40, 0x03, 76}, + }, + + { + {3, 0x02, 73}, + {6, 0x02, 73}, + {10, 0x02, 73}, + {15, 0x02, 73}, + {24, 0x02, 73}, + {31, 0x02, 73}, + {41, 0x02, 73}, + {56, 0x03, 73}, + {3, 0x02, 74}, + {6, 0x02, 74}, + {10, 0x02, 74}, + {15, 0x02, 74}, + {24, 0x02, 74}, + {31, 0x02, 74}, + {41, 0x02, 74}, + {56, 0x03, 74}, + }, + + { + {3, 0x02, 75}, + {6, 0x02, 75}, + {10, 0x02, 75}, + {15, 0x02, 75}, + {24, 0x02, 75}, + {31, 0x02, 75}, + {41, 0x02, 75}, + {56, 0x03, 75}, + {3, 0x02, 76}, + {6, 0x02, 76}, + {10, 0x02, 76}, + {15, 0x02, 76}, + {24, 0x02, 76}, + {31, 0x02, 76}, + {41, 0x02, 76}, + {56, 0x03, 76}, + }, + + { + {1, 0x02, 77}, + {22, 0x03, 77}, + {1, 0x02, 78}, + {22, 0x03, 78}, + {1, 0x02, 79}, + {22, 0x03, 79}, + {1, 0x02, 80}, + {22, 0x03, 80}, + {1, 0x02, 81}, + {22, 0x03, 81}, + {1, 0x02, 82}, + {22, 0x03, 82}, + {1, 0x02, 83}, + {22, 0x03, 83}, + {1, 0x02, 84}, + {22, 0x03, 84}, + }, + + { + {2, 0x02, 77}, + {9, 0x02, 77}, + {23, 0x02, 77}, + {40, 0x03, 77}, + {2, 0x02, 78}, + {9, 0x02, 78}, + {23, 0x02, 78}, + {40, 0x03, 78}, + {2, 0x02, 79}, + {9, 0x02, 79}, + {23, 0x02, 79}, + {40, 0x03, 79}, + {2, 0x02, 80}, + {9, 0x02, 80}, + {23, 0x02, 80}, + {40, 0x03, 80}, + }, + + { + {3, 0x02, 77}, + {6, 0x02, 77}, + {10, 0x02, 77}, + {15, 0x02, 77}, + {24, 0x02, 77}, + {31, 0x02, 77}, + {41, 0x02, 77}, + {56, 0x03, 77}, + {3, 0x02, 78}, + {6, 0x02, 78}, + {10, 0x02, 78}, + {15, 0x02, 78}, + {24, 0x02, 78}, + {31, 0x02, 78}, + {41, 0x02, 78}, + {56, 0x03, 78}, + }, + + { + {3, 0x02, 79}, + {6, 0x02, 79}, + {10, 0x02, 79}, + {15, 0x02, 79}, + {24, 0x02, 79}, + {31, 0x02, 79}, + {41, 0x02, 79}, + {56, 0x03, 79}, + {3, 0x02, 80}, + {6, 0x02, 80}, + {10, 0x02, 80}, + {15, 0x02, 80}, + {24, 0x02, 80}, + {31, 0x02, 80}, + {41, 0x02, 80}, + {56, 0x03, 80}, + }, + + { + {2, 0x02, 81}, + {9, 0x02, 81}, + {23, 0x02, 81}, + {40, 0x03, 81}, + {2, 0x02, 82}, + {9, 0x02, 82}, + {23, 0x02, 82}, + {40, 0x03, 82}, + {2, 0x02, 83}, + {9, 0x02, 83}, + {23, 0x02, 83}, + {40, 0x03, 83}, + {2, 0x02, 84}, + {9, 0x02, 84}, + {23, 0x02, 84}, + {40, 0x03, 84}, + }, + + { + {3, 0x02, 81}, + {6, 0x02, 81}, + {10, 0x02, 81}, + {15, 0x02, 81}, + {24, 0x02, 81}, + {31, 0x02, 81}, + {41, 0x02, 81}, + {56, 0x03, 81}, + {3, 0x02, 82}, + {6, 0x02, 82}, + {10, 0x02, 82}, + {15, 0x02, 82}, + {24, 0x02, 82}, + {31, 0x02, 82}, + {41, 0x02, 82}, + {56, 0x03, 82}, + }, + + { + {3, 0x02, 83}, + {6, 0x02, 83}, + {10, 0x02, 83}, + {15, 0x02, 83}, + {24, 0x02, 83}, + {31, 0x02, 83}, + {41, 0x02, 83}, + {56, 0x03, 83}, + {3, 0x02, 84}, + {6, 0x02, 84}, + {10, 0x02, 84}, + {15, 0x02, 84}, + {24, 0x02, 84}, + {31, 0x02, 84}, + {41, 0x02, 84}, + {56, 0x03, 84}, + }, + + { + {0, 0x03, 85}, + {0, 0x03, 86}, + {0, 0x03, 87}, + {0, 0x03, 89}, + {0, 0x03, 106}, + {0, 0x03, 107}, + {0, 0x03, 113}, + {0, 0x03, 118}, + {0, 0x03, 119}, + {0, 0x03, 120}, + {0, 0x03, 121}, + {0, 0x03, 122}, + {70, 0x00, 0}, + {71, 0x00, 0}, + {73, 0x00, 0}, + {74, 0x01, 0}, + }, + + { + {1, 0x02, 85}, + {22, 0x03, 85}, + {1, 0x02, 86}, + {22, 0x03, 86}, + {1, 0x02, 87}, + {22, 0x03, 87}, + {1, 0x02, 89}, + {22, 0x03, 89}, + {1, 0x02, 106}, + {22, 0x03, 106}, + {1, 0x02, 107}, + {22, 0x03, 107}, + {1, 0x02, 113}, + {22, 0x03, 113}, + {1, 0x02, 118}, + {22, 0x03, 118}, + }, + + { + {2, 0x02, 85}, + {9, 0x02, 85}, + {23, 0x02, 85}, + {40, 0x03, 85}, + {2, 0x02, 86}, + {9, 0x02, 86}, + {23, 0x02, 86}, + {40, 0x03, 86}, + {2, 0x02, 87}, + {9, 0x02, 87}, + {23, 0x02, 87}, + {40, 0x03, 87}, + {2, 0x02, 89}, + {9, 0x02, 89}, + {23, 0x02, 89}, + {40, 0x03, 89}, + }, + + { + {3, 0x02, 85}, + {6, 0x02, 85}, + {10, 0x02, 85}, + {15, 0x02, 85}, + {24, 0x02, 85}, + {31, 0x02, 85}, + {41, 0x02, 85}, + {56, 0x03, 85}, + {3, 0x02, 86}, + {6, 0x02, 86}, + {10, 0x02, 86}, + {15, 0x02, 86}, + {24, 0x02, 86}, + {31, 0x02, 86}, + {41, 0x02, 86}, + {56, 0x03, 86}, + }, + + { + {3, 0x02, 87}, + {6, 0x02, 87}, + {10, 0x02, 87}, + {15, 0x02, 87}, + {24, 0x02, 87}, + {31, 0x02, 87}, + {41, 0x02, 87}, + {56, 0x03, 87}, + {3, 0x02, 89}, + {6, 0x02, 89}, + {10, 0x02, 89}, + {15, 0x02, 89}, + {24, 0x02, 89}, + {31, 0x02, 89}, + {41, 0x02, 89}, + {56, 0x03, 89}, + }, + + { + {2, 0x02, 106}, + {9, 0x02, 106}, + {23, 0x02, 106}, + {40, 0x03, 106}, + {2, 0x02, 107}, + {9, 0x02, 107}, + {23, 0x02, 107}, + {40, 0x03, 107}, + {2, 0x02, 113}, + {9, 0x02, 113}, + {23, 0x02, 113}, + {40, 0x03, 113}, + {2, 0x02, 118}, + {9, 0x02, 118}, + {23, 0x02, 118}, + {40, 0x03, 118}, + }, + + { + {3, 0x02, 106}, + {6, 0x02, 106}, + {10, 0x02, 106}, + {15, 0x02, 106}, + {24, 0x02, 106}, + {31, 0x02, 106}, + {41, 0x02, 106}, + {56, 0x03, 106}, + {3, 0x02, 107}, + {6, 0x02, 107}, + {10, 0x02, 107}, + {15, 0x02, 107}, + {24, 0x02, 107}, + {31, 0x02, 107}, + {41, 0x02, 107}, + {56, 0x03, 107}, + }, + + { + {3, 0x02, 113}, + {6, 0x02, 113}, + {10, 0x02, 113}, + {15, 0x02, 113}, + {24, 0x02, 113}, + {31, 0x02, 113}, + {41, 0x02, 113}, + {56, 0x03, 113}, + {3, 0x02, 118}, + {6, 0x02, 118}, + {10, 0x02, 118}, + {15, 0x02, 118}, + {24, 0x02, 118}, + {31, 0x02, 118}, + {41, 0x02, 118}, + {56, 0x03, 118}, + }, + + { + {1, 0x02, 119}, + {22, 0x03, 119}, + {1, 0x02, 120}, + {22, 0x03, 120}, + {1, 0x02, 121}, + {22, 0x03, 121}, + {1, 0x02, 122}, + {22, 0x03, 122}, + {0, 0x03, 38}, + {0, 0x03, 42}, + {0, 0x03, 44}, + {0, 0x03, 59}, + {0, 0x03, 88}, + {0, 0x03, 90}, + {75, 0x00, 0}, + {78, 0x00, 0}, + }, + + { + {2, 0x02, 119}, + {9, 0x02, 119}, + {23, 0x02, 119}, + {40, 0x03, 119}, + {2, 0x02, 120}, + {9, 0x02, 120}, + {23, 0x02, 120}, + {40, 0x03, 120}, + {2, 0x02, 121}, + {9, 0x02, 121}, + {23, 0x02, 121}, + {40, 0x03, 121}, + {2, 0x02, 122}, + {9, 0x02, 122}, + {23, 0x02, 122}, + {40, 0x03, 122}, + }, + + { + {3, 0x02, 119}, + {6, 0x02, 119}, + {10, 0x02, 119}, + {15, 0x02, 119}, + {24, 0x02, 119}, + {31, 0x02, 119}, + {41, 0x02, 119}, + {56, 0x03, 119}, + {3, 0x02, 120}, + {6, 0x02, 120}, + {10, 0x02, 120}, + {15, 0x02, 120}, + {24, 0x02, 120}, + {31, 0x02, 120}, + {41, 0x02, 120}, + {56, 0x03, 120}, + }, + + { + {3, 0x02, 121}, + {6, 0x02, 121}, + {10, 0x02, 121}, + {15, 0x02, 121}, + {24, 0x02, 121}, + {31, 0x02, 121}, + {41, 0x02, 121}, + {56, 0x03, 121}, + {3, 0x02, 122}, + {6, 0x02, 122}, + {10, 0x02, 122}, + {15, 0x02, 122}, + {24, 0x02, 122}, + {31, 0x02, 122}, + {41, 0x02, 122}, + {56, 0x03, 122}, + }, + + { + {1, 0x02, 38}, + {22, 0x03, 38}, + {1, 0x02, 42}, + {22, 0x03, 42}, + {1, 0x02, 44}, + {22, 0x03, 44}, + {1, 0x02, 59}, + {22, 0x03, 59}, + {1, 0x02, 88}, + {22, 0x03, 88}, + {1, 0x02, 90}, + {22, 0x03, 90}, + {76, 0x00, 0}, + {77, 0x00, 0}, + {79, 0x00, 0}, + {81, 0x00, 0}, + }, + + { + {2, 0x02, 38}, + {9, 0x02, 38}, + {23, 0x02, 38}, + {40, 0x03, 38}, + {2, 0x02, 42}, + {9, 0x02, 42}, + {23, 0x02, 42}, + {40, 0x03, 42}, + {2, 0x02, 44}, + {9, 0x02, 44}, + {23, 0x02, 44}, + {40, 0x03, 44}, + {2, 0x02, 59}, + {9, 0x02, 59}, + {23, 0x02, 59}, + {40, 0x03, 59}, + }, + + { + {3, 0x02, 38}, + {6, 0x02, 38}, + {10, 0x02, 38}, + {15, 0x02, 38}, + {24, 0x02, 38}, + {31, 0x02, 38}, + {41, 0x02, 38}, + {56, 0x03, 38}, + {3, 0x02, 42}, + {6, 0x02, 42}, + {10, 0x02, 42}, + {15, 0x02, 42}, + {24, 0x02, 42}, + {31, 0x02, 42}, + {41, 0x02, 42}, + {56, 0x03, 42}, + }, + + { + {3, 0x02, 44}, + {6, 0x02, 44}, + {10, 0x02, 44}, + {15, 0x02, 44}, + {24, 0x02, 44}, + {31, 0x02, 44}, + {41, 0x02, 44}, + {56, 0x03, 44}, + {3, 0x02, 59}, + {6, 0x02, 59}, + {10, 0x02, 59}, + {15, 0x02, 59}, + {24, 0x02, 59}, + {31, 0x02, 59}, + {41, 0x02, 59}, + {56, 0x03, 59}, + }, + + { + {2, 0x02, 88}, + {9, 0x02, 88}, + {23, 0x02, 88}, + {40, 0x03, 88}, + {2, 0x02, 90}, + {9, 0x02, 90}, + {23, 0x02, 90}, + {40, 0x03, 90}, + {0, 0x03, 33}, + {0, 0x03, 34}, + {0, 0x03, 40}, + {0, 0x03, 41}, + {0, 0x03, 63}, + {80, 0x00, 0}, + {82, 0x00, 0}, + {84, 0x00, 0}, + }, + + { + {3, 0x02, 88}, + {6, 0x02, 88}, + {10, 0x02, 88}, + {15, 0x02, 88}, + {24, 0x02, 88}, + {31, 0x02, 88}, + {41, 0x02, 88}, + {56, 0x03, 88}, + {3, 0x02, 90}, + {6, 0x02, 90}, + {10, 0x02, 90}, + {15, 0x02, 90}, + {24, 0x02, 90}, + {31, 0x02, 90}, + {41, 0x02, 90}, + {56, 0x03, 90}, + }, + + { + {1, 0x02, 33}, + {22, 0x03, 33}, + {1, 0x02, 34}, + {22, 0x03, 34}, + {1, 0x02, 40}, + {22, 0x03, 40}, + {1, 0x02, 41}, + {22, 0x03, 41}, + {1, 0x02, 63}, + {22, 0x03, 63}, + {0, 0x03, 39}, + {0, 0x03, 43}, + {0, 0x03, 124}, + {83, 0x00, 0}, + {85, 0x00, 0}, + {88, 0x00, 0}, + }, + + { + {2, 0x02, 33}, + {9, 0x02, 33}, + {23, 0x02, 33}, + {40, 0x03, 33}, + {2, 0x02, 34}, + {9, 0x02, 34}, + {23, 0x02, 34}, + {40, 0x03, 34}, + {2, 0x02, 40}, + {9, 0x02, 40}, + {23, 0x02, 40}, + {40, 0x03, 40}, + {2, 0x02, 41}, + {9, 0x02, 41}, + {23, 0x02, 41}, + {40, 0x03, 41}, + }, + + { + {3, 0x02, 33}, + {6, 0x02, 33}, + {10, 0x02, 33}, + {15, 0x02, 33}, + {24, 0x02, 33}, + {31, 0x02, 33}, + {41, 0x02, 33}, + {56, 0x03, 33}, + {3, 0x02, 34}, + {6, 0x02, 34}, + {10, 0x02, 34}, + {15, 0x02, 34}, + {24, 0x02, 34}, + {31, 0x02, 34}, + {41, 0x02, 34}, + {56, 0x03, 34}, + }, + + { + {3, 0x02, 40}, + {6, 0x02, 40}, + {10, 0x02, 40}, + {15, 0x02, 40}, + {24, 0x02, 40}, + {31, 0x02, 40}, + {41, 0x02, 40}, + {56, 0x03, 40}, + {3, 0x02, 41}, + {6, 0x02, 41}, + {10, 0x02, 41}, + {15, 0x02, 41}, + {24, 0x02, 41}, + {31, 0x02, 41}, + {41, 0x02, 41}, + {56, 0x03, 41}, + }, + + { + {2, 0x02, 63}, + {9, 0x02, 63}, + {23, 0x02, 63}, + {40, 0x03, 63}, + {1, 0x02, 39}, + {22, 0x03, 39}, + {1, 0x02, 43}, + {22, 0x03, 43}, + {1, 0x02, 124}, + {22, 0x03, 124}, + {0, 0x03, 35}, + {0, 0x03, 62}, + {86, 0x00, 0}, + {87, 0x00, 0}, + {89, 0x00, 0}, + {90, 0x00, 0}, + }, + + { + {3, 0x02, 63}, + {6, 0x02, 63}, + {10, 0x02, 63}, + {15, 0x02, 63}, + {24, 0x02, 63}, + {31, 0x02, 63}, + {41, 0x02, 63}, + {56, 0x03, 63}, + {2, 0x02, 39}, + {9, 0x02, 39}, + {23, 0x02, 39}, + {40, 0x03, 39}, + {2, 0x02, 43}, + {9, 0x02, 43}, + {23, 0x02, 43}, + {40, 0x03, 43}, + }, + + { + {3, 0x02, 39}, + {6, 0x02, 39}, + {10, 0x02, 39}, + {15, 0x02, 39}, + {24, 0x02, 39}, + {31, 0x02, 39}, + {41, 0x02, 39}, + {56, 0x03, 39}, + {3, 0x02, 43}, + {6, 0x02, 43}, + {10, 0x02, 43}, + {15, 0x02, 43}, + {24, 0x02, 43}, + {31, 0x02, 43}, + {41, 0x02, 43}, + {56, 0x03, 43}, + }, + + { + {2, 0x02, 124}, + {9, 0x02, 124}, + {23, 0x02, 124}, + {40, 0x03, 124}, + {1, 0x02, 35}, + {22, 0x03, 35}, + {1, 0x02, 62}, + {22, 0x03, 62}, + {0, 0x03, 0}, + {0, 0x03, 36}, + {0, 0x03, 64}, + {0, 0x03, 91}, + {0, 0x03, 93}, + {0, 0x03, 126}, + {91, 0x00, 0}, + {92, 0x00, 0}, + }, + + { + {3, 0x02, 124}, + {6, 0x02, 124}, + {10, 0x02, 124}, + {15, 0x02, 124}, + {24, 0x02, 124}, + {31, 0x02, 124}, + {41, 0x02, 124}, + {56, 0x03, 124}, + {2, 0x02, 35}, + {9, 0x02, 35}, + {23, 0x02, 35}, + {40, 0x03, 35}, + {2, 0x02, 62}, + {9, 0x02, 62}, + {23, 0x02, 62}, + {40, 0x03, 62}, + }, + + { + {3, 0x02, 35}, + {6, 0x02, 35}, + {10, 0x02, 35}, + {15, 0x02, 35}, + {24, 0x02, 35}, + {31, 0x02, 35}, + {41, 0x02, 35}, + {56, 0x03, 35}, + {3, 0x02, 62}, + {6, 0x02, 62}, + {10, 0x02, 62}, + {15, 0x02, 62}, + {24, 0x02, 62}, + {31, 0x02, 62}, + {41, 0x02, 62}, + {56, 0x03, 62}, + }, + + { + {1, 0x02, 0}, + {22, 0x03, 0}, + {1, 0x02, 36}, + {22, 0x03, 36}, + {1, 0x02, 64}, + {22, 0x03, 64}, + {1, 0x02, 91}, + {22, 0x03, 91}, + {1, 0x02, 93}, + {22, 0x03, 93}, + {1, 0x02, 126}, + {22, 0x03, 126}, + {0, 0x03, 94}, + {0, 0x03, 125}, + {93, 0x00, 0}, + {94, 0x00, 0}, + }, + + { + {2, 0x02, 0}, + {9, 0x02, 0}, + {23, 0x02, 0}, + {40, 0x03, 0}, + {2, 0x02, 36}, + {9, 0x02, 36}, + {23, 0x02, 36}, + {40, 0x03, 36}, + {2, 0x02, 64}, + {9, 0x02, 64}, + {23, 0x02, 64}, + {40, 0x03, 64}, + {2, 0x02, 91}, + {9, 0x02, 91}, + {23, 0x02, 91}, + {40, 0x03, 91}, + }, + + { + {3, 0x02, 0}, + {6, 0x02, 0}, + {10, 0x02, 0}, + {15, 0x02, 0}, + {24, 0x02, 0}, + {31, 0x02, 0}, + {41, 0x02, 0}, + {56, 0x03, 0}, + {3, 0x02, 36}, + {6, 0x02, 36}, + {10, 0x02, 36}, + {15, 0x02, 36}, + {24, 0x02, 36}, + {31, 0x02, 36}, + {41, 0x02, 36}, + {56, 0x03, 36}, + }, + + { + {3, 0x02, 64}, + {6, 0x02, 64}, + {10, 0x02, 64}, + {15, 0x02, 64}, + {24, 0x02, 64}, + {31, 0x02, 64}, + {41, 0x02, 64}, + {56, 0x03, 64}, + {3, 0x02, 91}, + {6, 0x02, 91}, + {10, 0x02, 91}, + {15, 0x02, 91}, + {24, 0x02, 91}, + {31, 0x02, 91}, + {41, 0x02, 91}, + {56, 0x03, 91}, + }, + + { + {2, 0x02, 93}, + {9, 0x02, 93}, + {23, 0x02, 93}, + {40, 0x03, 93}, + {2, 0x02, 126}, + {9, 0x02, 126}, + {23, 0x02, 126}, + {40, 0x03, 126}, + {1, 0x02, 94}, + {22, 0x03, 94}, + {1, 0x02, 125}, + {22, 0x03, 125}, + {0, 0x03, 60}, + {0, 0x03, 96}, + {0, 0x03, 123}, + {95, 0x00, 0}, + }, + + { + {3, 0x02, 93}, + {6, 0x02, 93}, + {10, 0x02, 93}, + {15, 0x02, 93}, + {24, 0x02, 93}, + {31, 0x02, 93}, + {41, 0x02, 93}, + {56, 0x03, 93}, + {3, 0x02, 126}, + {6, 0x02, 126}, + {10, 0x02, 126}, + {15, 0x02, 126}, + {24, 0x02, 126}, + {31, 0x02, 126}, + {41, 0x02, 126}, + {56, 0x03, 126}, + }, + + { + {2, 0x02, 94}, + {9, 0x02, 94}, + {23, 0x02, 94}, + {40, 0x03, 94}, + {2, 0x02, 125}, + {9, 0x02, 125}, + {23, 0x02, 125}, + {40, 0x03, 125}, + {1, 0x02, 60}, + {22, 0x03, 60}, + {1, 0x02, 96}, + {22, 0x03, 96}, + {1, 0x02, 123}, + {22, 0x03, 123}, + {96, 0x00, 0}, + {110, 0x00, 0}, + }, + + { + {3, 0x02, 94}, + {6, 0x02, 94}, + {10, 0x02, 94}, + {15, 0x02, 94}, + {24, 0x02, 94}, + {31, 0x02, 94}, + {41, 0x02, 94}, + {56, 0x03, 94}, + {3, 0x02, 125}, + {6, 0x02, 125}, + {10, 0x02, 125}, + {15, 0x02, 125}, + {24, 0x02, 125}, + {31, 0x02, 125}, + {41, 0x02, 125}, + {56, 0x03, 125}, + }, + + { + {2, 0x02, 60}, + {9, 0x02, 60}, + {23, 0x02, 60}, + {40, 0x03, 60}, + {2, 0x02, 96}, + {9, 0x02, 96}, + {23, 0x02, 96}, + {40, 0x03, 96}, + {2, 0x02, 123}, + {9, 0x02, 123}, + {23, 0x02, 123}, + {40, 0x03, 123}, + {97, 0x00, 0}, + {101, 0x00, 0}, + {111, 0x00, 0}, + {133, 0x00, 0}, + }, + + { + {3, 0x02, 60}, + {6, 0x02, 60}, + {10, 0x02, 60}, + {15, 0x02, 60}, + {24, 0x02, 60}, + {31, 0x02, 60}, + {41, 0x02, 60}, + {56, 0x03, 60}, + {3, 0x02, 96}, + {6, 0x02, 96}, + {10, 0x02, 96}, + {15, 0x02, 96}, + {24, 0x02, 96}, + {31, 0x02, 96}, + {41, 0x02, 96}, + {56, 0x03, 96}, + }, + + { + {3, 0x02, 123}, + {6, 0x02, 123}, + {10, 0x02, 123}, + {15, 0x02, 123}, + {24, 0x02, 123}, + {31, 0x02, 123}, + {41, 0x02, 123}, + {56, 0x03, 123}, + {98, 0x00, 0}, + {99, 0x00, 0}, + {102, 0x00, 0}, + {105, 0x00, 0}, + {112, 0x00, 0}, + {119, 0x00, 0}, + {134, 0x00, 0}, + {153, 0x00, 0}, + }, + + { + {0, 0x03, 92}, + {0, 0x03, 195}, + {0, 0x03, 208}, + {100, 0x00, 0}, + {103, 0x00, 0}, + {104, 0x00, 0}, + {106, 0x00, 0}, + {107, 0x00, 0}, + {113, 0x00, 0}, + {116, 0x00, 0}, + {120, 0x00, 0}, + {126, 0x00, 0}, + {135, 0x00, 0}, + {142, 0x00, 0}, + {154, 0x00, 0}, + {169, 0x00, 0}, + }, + + { + {1, 0x02, 92}, + {22, 0x03, 92}, + {1, 0x02, 195}, + {22, 0x03, 195}, + {1, 0x02, 208}, + {22, 0x03, 208}, + {0, 0x03, 128}, + {0, 0x03, 130}, + {0, 0x03, 131}, + {0, 0x03, 162}, + {0, 0x03, 184}, + {0, 0x03, 194}, + {0, 0x03, 224}, + {0, 0x03, 226}, + {108, 0x00, 0}, + {109, 0x00, 0}, + }, + + { + {2, 0x02, 92}, + {9, 0x02, 92}, + {23, 0x02, 92}, + {40, 0x03, 92}, + {2, 0x02, 195}, + {9, 0x02, 195}, + {23, 0x02, 195}, + {40, 0x03, 195}, + {2, 0x02, 208}, + {9, 0x02, 208}, + {23, 0x02, 208}, + {40, 0x03, 208}, + {1, 0x02, 128}, + {22, 0x03, 128}, + {1, 0x02, 130}, + {22, 0x03, 130}, + }, + + { + {3, 0x02, 92}, + {6, 0x02, 92}, + {10, 0x02, 92}, + {15, 0x02, 92}, + {24, 0x02, 92}, + {31, 0x02, 92}, + {41, 0x02, 92}, + {56, 0x03, 92}, + {3, 0x02, 195}, + {6, 0x02, 195}, + {10, 0x02, 195}, + {15, 0x02, 195}, + {24, 0x02, 195}, + {31, 0x02, 195}, + {41, 0x02, 195}, + {56, 0x03, 195}, + }, + + { + {3, 0x02, 208}, + {6, 0x02, 208}, + {10, 0x02, 208}, + {15, 0x02, 208}, + {24, 0x02, 208}, + {31, 0x02, 208}, + {41, 0x02, 208}, + {56, 0x03, 208}, + {2, 0x02, 128}, + {9, 0x02, 128}, + {23, 0x02, 128}, + {40, 0x03, 128}, + {2, 0x02, 130}, + {9, 0x02, 130}, + {23, 0x02, 130}, + {40, 0x03, 130}, + }, + + { + {3, 0x02, 128}, + {6, 0x02, 128}, + {10, 0x02, 128}, + {15, 0x02, 128}, + {24, 0x02, 128}, + {31, 0x02, 128}, + {41, 0x02, 128}, + {56, 0x03, 128}, + {3, 0x02, 130}, + {6, 0x02, 130}, + {10, 0x02, 130}, + {15, 0x02, 130}, + {24, 0x02, 130}, + {31, 0x02, 130}, + {41, 0x02, 130}, + {56, 0x03, 130}, + }, + + { + {1, 0x02, 131}, + {22, 0x03, 131}, + {1, 0x02, 162}, + {22, 0x03, 162}, + {1, 0x02, 184}, + {22, 0x03, 184}, + {1, 0x02, 194}, + {22, 0x03, 194}, + {1, 0x02, 224}, + {22, 0x03, 224}, + {1, 0x02, 226}, + {22, 0x03, 226}, + {0, 0x03, 153}, + {0, 0x03, 161}, + {0, 0x03, 167}, + {0, 0x03, 172}, + }, + + { + {2, 0x02, 131}, + {9, 0x02, 131}, + {23, 0x02, 131}, + {40, 0x03, 131}, + {2, 0x02, 162}, + {9, 0x02, 162}, + {23, 0x02, 162}, + {40, 0x03, 162}, + {2, 0x02, 184}, + {9, 0x02, 184}, + {23, 0x02, 184}, + {40, 0x03, 184}, + {2, 0x02, 194}, + {9, 0x02, 194}, + {23, 0x02, 194}, + {40, 0x03, 194}, + }, + + { + {3, 0x02, 131}, + {6, 0x02, 131}, + {10, 0x02, 131}, + {15, 0x02, 131}, + {24, 0x02, 131}, + {31, 0x02, 131}, + {41, 0x02, 131}, + {56, 0x03, 131}, + {3, 0x02, 162}, + {6, 0x02, 162}, + {10, 0x02, 162}, + {15, 0x02, 162}, + {24, 0x02, 162}, + {31, 0x02, 162}, + {41, 0x02, 162}, + {56, 0x03, 162}, + }, + + { + {3, 0x02, 184}, + {6, 0x02, 184}, + {10, 0x02, 184}, + {15, 0x02, 184}, + {24, 0x02, 184}, + {31, 0x02, 184}, + {41, 0x02, 184}, + {56, 0x03, 184}, + {3, 0x02, 194}, + {6, 0x02, 194}, + {10, 0x02, 194}, + {15, 0x02, 194}, + {24, 0x02, 194}, + {31, 0x02, 194}, + {41, 0x02, 194}, + {56, 0x03, 194}, + }, + + { + {2, 0x02, 224}, + {9, 0x02, 224}, + {23, 0x02, 224}, + {40, 0x03, 224}, + {2, 0x02, 226}, + {9, 0x02, 226}, + {23, 0x02, 226}, + {40, 0x03, 226}, + {1, 0x02, 153}, + {22, 0x03, 153}, + {1, 0x02, 161}, + {22, 0x03, 161}, + {1, 0x02, 167}, + {22, 0x03, 167}, + {1, 0x02, 172}, + {22, 0x03, 172}, + }, + + { + {3, 0x02, 224}, + {6, 0x02, 224}, + {10, 0x02, 224}, + {15, 0x02, 224}, + {24, 0x02, 224}, + {31, 0x02, 224}, + {41, 0x02, 224}, + {56, 0x03, 224}, + {3, 0x02, 226}, + {6, 0x02, 226}, + {10, 0x02, 226}, + {15, 0x02, 226}, + {24, 0x02, 226}, + {31, 0x02, 226}, + {41, 0x02, 226}, + {56, 0x03, 226}, + }, + + { + {2, 0x02, 153}, + {9, 0x02, 153}, + {23, 0x02, 153}, + {40, 0x03, 153}, + {2, 0x02, 161}, + {9, 0x02, 161}, + {23, 0x02, 161}, + {40, 0x03, 161}, + {2, 0x02, 167}, + {9, 0x02, 167}, + {23, 0x02, 167}, + {40, 0x03, 167}, + {2, 0x02, 172}, + {9, 0x02, 172}, + {23, 0x02, 172}, + {40, 0x03, 172}, + }, + + { + {3, 0x02, 153}, + {6, 0x02, 153}, + {10, 0x02, 153}, + {15, 0x02, 153}, + {24, 0x02, 153}, + {31, 0x02, 153}, + {41, 0x02, 153}, + {56, 0x03, 153}, + {3, 0x02, 161}, + {6, 0x02, 161}, + {10, 0x02, 161}, + {15, 0x02, 161}, + {24, 0x02, 161}, + {31, 0x02, 161}, + {41, 0x02, 161}, + {56, 0x03, 161}, + }, + + { + {3, 0x02, 167}, + {6, 0x02, 167}, + {10, 0x02, 167}, + {15, 0x02, 167}, + {24, 0x02, 167}, + {31, 0x02, 167}, + {41, 0x02, 167}, + {56, 0x03, 167}, + {3, 0x02, 172}, + {6, 0x02, 172}, + {10, 0x02, 172}, + {15, 0x02, 172}, + {24, 0x02, 172}, + {31, 0x02, 172}, + {41, 0x02, 172}, + {56, 0x03, 172}, + }, + + { + {114, 0x00, 0}, + {115, 0x00, 0}, + {117, 0x00, 0}, + {118, 0x00, 0}, + {121, 0x00, 0}, + {123, 0x00, 0}, + {127, 0x00, 0}, + {130, 0x00, 0}, + {136, 0x00, 0}, + {139, 0x00, 0}, + {143, 0x00, 0}, + {146, 0x00, 0}, + {155, 0x00, 0}, + {162, 0x00, 0}, + {170, 0x00, 0}, + {180, 0x00, 0}, + }, + + { + {0, 0x03, 176}, + {0, 0x03, 177}, + {0, 0x03, 179}, + {0, 0x03, 209}, + {0, 0x03, 216}, + {0, 0x03, 217}, + {0, 0x03, 227}, + {0, 0x03, 229}, + {0, 0x03, 230}, + {122, 0x00, 0}, + {124, 0x00, 0}, + {125, 0x00, 0}, + {128, 0x00, 0}, + {129, 0x00, 0}, + {131, 0x00, 0}, + {132, 0x00, 0}, + }, + + { + {1, 0x02, 176}, + {22, 0x03, 176}, + {1, 0x02, 177}, + {22, 0x03, 177}, + {1, 0x02, 179}, + {22, 0x03, 179}, + {1, 0x02, 209}, + {22, 0x03, 209}, + {1, 0x02, 216}, + {22, 0x03, 216}, + {1, 0x02, 217}, + {22, 0x03, 217}, + {1, 0x02, 227}, + {22, 0x03, 227}, + {1, 0x02, 229}, + {22, 0x03, 229}, + }, + + { + {2, 0x02, 176}, + {9, 0x02, 176}, + {23, 0x02, 176}, + {40, 0x03, 176}, + {2, 0x02, 177}, + {9, 0x02, 177}, + {23, 0x02, 177}, + {40, 0x03, 177}, + {2, 0x02, 179}, + {9, 0x02, 179}, + {23, 0x02, 179}, + {40, 0x03, 179}, + {2, 0x02, 209}, + {9, 0x02, 209}, + {23, 0x02, 209}, + {40, 0x03, 209}, + }, + + { + {3, 0x02, 176}, + {6, 0x02, 176}, + {10, 0x02, 176}, + {15, 0x02, 176}, + {24, 0x02, 176}, + {31, 0x02, 176}, + {41, 0x02, 176}, + {56, 0x03, 176}, + {3, 0x02, 177}, + {6, 0x02, 177}, + {10, 0x02, 177}, + {15, 0x02, 177}, + {24, 0x02, 177}, + {31, 0x02, 177}, + {41, 0x02, 177}, + {56, 0x03, 177}, + }, + + { + {3, 0x02, 179}, + {6, 0x02, 179}, + {10, 0x02, 179}, + {15, 0x02, 179}, + {24, 0x02, 179}, + {31, 0x02, 179}, + {41, 0x02, 179}, + {56, 0x03, 179}, + {3, 0x02, 209}, + {6, 0x02, 209}, + {10, 0x02, 209}, + {15, 0x02, 209}, + {24, 0x02, 209}, + {31, 0x02, 209}, + {41, 0x02, 209}, + {56, 0x03, 209}, + }, + + { + {2, 0x02, 216}, + {9, 0x02, 216}, + {23, 0x02, 216}, + {40, 0x03, 216}, + {2, 0x02, 217}, + {9, 0x02, 217}, + {23, 0x02, 217}, + {40, 0x03, 217}, + {2, 0x02, 227}, + {9, 0x02, 227}, + {23, 0x02, 227}, + {40, 0x03, 227}, + {2, 0x02, 229}, + {9, 0x02, 229}, + {23, 0x02, 229}, + {40, 0x03, 229}, + }, + + { + {3, 0x02, 216}, + {6, 0x02, 216}, + {10, 0x02, 216}, + {15, 0x02, 216}, + {24, 0x02, 216}, + {31, 0x02, 216}, + {41, 0x02, 216}, + {56, 0x03, 216}, + {3, 0x02, 217}, + {6, 0x02, 217}, + {10, 0x02, 217}, + {15, 0x02, 217}, + {24, 0x02, 217}, + {31, 0x02, 217}, + {41, 0x02, 217}, + {56, 0x03, 217}, + }, + + { + {3, 0x02, 227}, + {6, 0x02, 227}, + {10, 0x02, 227}, + {15, 0x02, 227}, + {24, 0x02, 227}, + {31, 0x02, 227}, + {41, 0x02, 227}, + {56, 0x03, 227}, + {3, 0x02, 229}, + {6, 0x02, 229}, + {10, 0x02, 229}, + {15, 0x02, 229}, + {24, 0x02, 229}, + {31, 0x02, 229}, + {41, 0x02, 229}, + {56, 0x03, 229}, + }, + + { + {1, 0x02, 230}, + {22, 0x03, 230}, + {0, 0x03, 129}, + {0, 0x03, 132}, + {0, 0x03, 133}, + {0, 0x03, 134}, + {0, 0x03, 136}, + {0, 0x03, 146}, + {0, 0x03, 154}, + {0, 0x03, 156}, + {0, 0x03, 160}, + {0, 0x03, 163}, + {0, 0x03, 164}, + {0, 0x03, 169}, + {0, 0x03, 170}, + {0, 0x03, 173}, + }, + + { + {2, 0x02, 230}, + {9, 0x02, 230}, + {23, 0x02, 230}, + {40, 0x03, 230}, + {1, 0x02, 129}, + {22, 0x03, 129}, + {1, 0x02, 132}, + {22, 0x03, 132}, + {1, 0x02, 133}, + {22, 0x03, 133}, + {1, 0x02, 134}, + {22, 0x03, 134}, + {1, 0x02, 136}, + {22, 0x03, 136}, + {1, 0x02, 146}, + {22, 0x03, 146}, + }, + + { + {3, 0x02, 230}, + {6, 0x02, 230}, + {10, 0x02, 230}, + {15, 0x02, 230}, + {24, 0x02, 230}, + {31, 0x02, 230}, + {41, 0x02, 230}, + {56, 0x03, 230}, + {2, 0x02, 129}, + {9, 0x02, 129}, + {23, 0x02, 129}, + {40, 0x03, 129}, + {2, 0x02, 132}, + {9, 0x02, 132}, + {23, 0x02, 132}, + {40, 0x03, 132}, + }, + + { + {3, 0x02, 129}, + {6, 0x02, 129}, + {10, 0x02, 129}, + {15, 0x02, 129}, + {24, 0x02, 129}, + {31, 0x02, 129}, + {41, 0x02, 129}, + {56, 0x03, 129}, + {3, 0x02, 132}, + {6, 0x02, 132}, + {10, 0x02, 132}, + {15, 0x02, 132}, + {24, 0x02, 132}, + {31, 0x02, 132}, + {41, 0x02, 132}, + {56, 0x03, 132}, + }, + + { + {2, 0x02, 133}, + {9, 0x02, 133}, + {23, 0x02, 133}, + {40, 0x03, 133}, + {2, 0x02, 134}, + {9, 0x02, 134}, + {23, 0x02, 134}, + {40, 0x03, 134}, + {2, 0x02, 136}, + {9, 0x02, 136}, + {23, 0x02, 136}, + {40, 0x03, 136}, + {2, 0x02, 146}, + {9, 0x02, 146}, + {23, 0x02, 146}, + {40, 0x03, 146}, + }, + + { + {3, 0x02, 133}, + {6, 0x02, 133}, + {10, 0x02, 133}, + {15, 0x02, 133}, + {24, 0x02, 133}, + {31, 0x02, 133}, + {41, 0x02, 133}, + {56, 0x03, 133}, + {3, 0x02, 134}, + {6, 0x02, 134}, + {10, 0x02, 134}, + {15, 0x02, 134}, + {24, 0x02, 134}, + {31, 0x02, 134}, + {41, 0x02, 134}, + {56, 0x03, 134}, + }, + + { + {3, 0x02, 136}, + {6, 0x02, 136}, + {10, 0x02, 136}, + {15, 0x02, 136}, + {24, 0x02, 136}, + {31, 0x02, 136}, + {41, 0x02, 136}, + {56, 0x03, 136}, + {3, 0x02, 146}, + {6, 0x02, 146}, + {10, 0x02, 146}, + {15, 0x02, 146}, + {24, 0x02, 146}, + {31, 0x02, 146}, + {41, 0x02, 146}, + {56, 0x03, 146}, + }, + + { + {1, 0x02, 154}, + {22, 0x03, 154}, + {1, 0x02, 156}, + {22, 0x03, 156}, + {1, 0x02, 160}, + {22, 0x03, 160}, + {1, 0x02, 163}, + {22, 0x03, 163}, + {1, 0x02, 164}, + {22, 0x03, 164}, + {1, 0x02, 169}, + {22, 0x03, 169}, + {1, 0x02, 170}, + {22, 0x03, 170}, + {1, 0x02, 173}, + {22, 0x03, 173}, + }, + + { + {2, 0x02, 154}, + {9, 0x02, 154}, + {23, 0x02, 154}, + {40, 0x03, 154}, + {2, 0x02, 156}, + {9, 0x02, 156}, + {23, 0x02, 156}, + {40, 0x03, 156}, + {2, 0x02, 160}, + {9, 0x02, 160}, + {23, 0x02, 160}, + {40, 0x03, 160}, + {2, 0x02, 163}, + {9, 0x02, 163}, + {23, 0x02, 163}, + {40, 0x03, 163}, + }, + + { + {3, 0x02, 154}, + {6, 0x02, 154}, + {10, 0x02, 154}, + {15, 0x02, 154}, + {24, 0x02, 154}, + {31, 0x02, 154}, + {41, 0x02, 154}, + {56, 0x03, 154}, + {3, 0x02, 156}, + {6, 0x02, 156}, + {10, 0x02, 156}, + {15, 0x02, 156}, + {24, 0x02, 156}, + {31, 0x02, 156}, + {41, 0x02, 156}, + {56, 0x03, 156}, + }, + + { + {3, 0x02, 160}, + {6, 0x02, 160}, + {10, 0x02, 160}, + {15, 0x02, 160}, + {24, 0x02, 160}, + {31, 0x02, 160}, + {41, 0x02, 160}, + {56, 0x03, 160}, + {3, 0x02, 163}, + {6, 0x02, 163}, + {10, 0x02, 163}, + {15, 0x02, 163}, + {24, 0x02, 163}, + {31, 0x02, 163}, + {41, 0x02, 163}, + {56, 0x03, 163}, + }, + + { + {2, 0x02, 164}, + {9, 0x02, 164}, + {23, 0x02, 164}, + {40, 0x03, 164}, + {2, 0x02, 169}, + {9, 0x02, 169}, + {23, 0x02, 169}, + {40, 0x03, 169}, + {2, 0x02, 170}, + {9, 0x02, 170}, + {23, 0x02, 170}, + {40, 0x03, 170}, + {2, 0x02, 173}, + {9, 0x02, 173}, + {23, 0x02, 173}, + {40, 0x03, 173}, + }, + + { + {3, 0x02, 164}, + {6, 0x02, 164}, + {10, 0x02, 164}, + {15, 0x02, 164}, + {24, 0x02, 164}, + {31, 0x02, 164}, + {41, 0x02, 164}, + {56, 0x03, 164}, + {3, 0x02, 169}, + {6, 0x02, 169}, + {10, 0x02, 169}, + {15, 0x02, 169}, + {24, 0x02, 169}, + {31, 0x02, 169}, + {41, 0x02, 169}, + {56, 0x03, 169}, + }, + + { + {3, 0x02, 170}, + {6, 0x02, 170}, + {10, 0x02, 170}, + {15, 0x02, 170}, + {24, 0x02, 170}, + {31, 0x02, 170}, + {41, 0x02, 170}, + {56, 0x03, 170}, + {3, 0x02, 173}, + {6, 0x02, 173}, + {10, 0x02, 173}, + {15, 0x02, 173}, + {24, 0x02, 173}, + {31, 0x02, 173}, + {41, 0x02, 173}, + {56, 0x03, 173}, + }, + + { + {137, 0x00, 0}, + {138, 0x00, 0}, + {140, 0x00, 0}, + {141, 0x00, 0}, + {144, 0x00, 0}, + {145, 0x00, 0}, + {147, 0x00, 0}, + {150, 0x00, 0}, + {156, 0x00, 0}, + {159, 0x00, 0}, + {163, 0x00, 0}, + {166, 0x00, 0}, + {171, 0x00, 0}, + {174, 0x00, 0}, + {181, 0x00, 0}, + {190, 0x00, 0}, + }, + + { + {0, 0x03, 178}, + {0, 0x03, 181}, + {0, 0x03, 185}, + {0, 0x03, 186}, + {0, 0x03, 187}, + {0, 0x03, 189}, + {0, 0x03, 190}, + {0, 0x03, 196}, + {0, 0x03, 198}, + {0, 0x03, 228}, + {0, 0x03, 232}, + {0, 0x03, 233}, + {148, 0x00, 0}, + {149, 0x00, 0}, + {151, 0x00, 0}, + {152, 0x00, 0}, + }, + + { + {1, 0x02, 178}, + {22, 0x03, 178}, + {1, 0x02, 181}, + {22, 0x03, 181}, + {1, 0x02, 185}, + {22, 0x03, 185}, + {1, 0x02, 186}, + {22, 0x03, 186}, + {1, 0x02, 187}, + {22, 0x03, 187}, + {1, 0x02, 189}, + {22, 0x03, 189}, + {1, 0x02, 190}, + {22, 0x03, 190}, + {1, 0x02, 196}, + {22, 0x03, 196}, + }, + + { + {2, 0x02, 178}, + {9, 0x02, 178}, + {23, 0x02, 178}, + {40, 0x03, 178}, + {2, 0x02, 181}, + {9, 0x02, 181}, + {23, 0x02, 181}, + {40, 0x03, 181}, + {2, 0x02, 185}, + {9, 0x02, 185}, + {23, 0x02, 185}, + {40, 0x03, 185}, + {2, 0x02, 186}, + {9, 0x02, 186}, + {23, 0x02, 186}, + {40, 0x03, 186}, + }, + + { + {3, 0x02, 178}, + {6, 0x02, 178}, + {10, 0x02, 178}, + {15, 0x02, 178}, + {24, 0x02, 178}, + {31, 0x02, 178}, + {41, 0x02, 178}, + {56, 0x03, 178}, + {3, 0x02, 181}, + {6, 0x02, 181}, + {10, 0x02, 181}, + {15, 0x02, 181}, + {24, 0x02, 181}, + {31, 0x02, 181}, + {41, 0x02, 181}, + {56, 0x03, 181}, + }, + + { + {3, 0x02, 185}, + {6, 0x02, 185}, + {10, 0x02, 185}, + {15, 0x02, 185}, + {24, 0x02, 185}, + {31, 0x02, 185}, + {41, 0x02, 185}, + {56, 0x03, 185}, + {3, 0x02, 186}, + {6, 0x02, 186}, + {10, 0x02, 186}, + {15, 0x02, 186}, + {24, 0x02, 186}, + {31, 0x02, 186}, + {41, 0x02, 186}, + {56, 0x03, 186}, + }, + + { + {2, 0x02, 187}, + {9, 0x02, 187}, + {23, 0x02, 187}, + {40, 0x03, 187}, + {2, 0x02, 189}, + {9, 0x02, 189}, + {23, 0x02, 189}, + {40, 0x03, 189}, + {2, 0x02, 190}, + {9, 0x02, 190}, + {23, 0x02, 190}, + {40, 0x03, 190}, + {2, 0x02, 196}, + {9, 0x02, 196}, + {23, 0x02, 196}, + {40, 0x03, 196}, + }, + + { + {3, 0x02, 187}, + {6, 0x02, 187}, + {10, 0x02, 187}, + {15, 0x02, 187}, + {24, 0x02, 187}, + {31, 0x02, 187}, + {41, 0x02, 187}, + {56, 0x03, 187}, + {3, 0x02, 189}, + {6, 0x02, 189}, + {10, 0x02, 189}, + {15, 0x02, 189}, + {24, 0x02, 189}, + {31, 0x02, 189}, + {41, 0x02, 189}, + {56, 0x03, 189}, + }, + + { + {3, 0x02, 190}, + {6, 0x02, 190}, + {10, 0x02, 190}, + {15, 0x02, 190}, + {24, 0x02, 190}, + {31, 0x02, 190}, + {41, 0x02, 190}, + {56, 0x03, 190}, + {3, 0x02, 196}, + {6, 0x02, 196}, + {10, 0x02, 196}, + {15, 0x02, 196}, + {24, 0x02, 196}, + {31, 0x02, 196}, + {41, 0x02, 196}, + {56, 0x03, 196}, + }, + + { + {1, 0x02, 198}, + {22, 0x03, 198}, + {1, 0x02, 228}, + {22, 0x03, 228}, + {1, 0x02, 232}, + {22, 0x03, 232}, + {1, 0x02, 233}, + {22, 0x03, 233}, + {0, 0x03, 1}, + {0, 0x03, 135}, + {0, 0x03, 137}, + {0, 0x03, 138}, + {0, 0x03, 139}, + {0, 0x03, 140}, + {0, 0x03, 141}, + {0, 0x03, 143}, + }, + + { + {2, 0x02, 198}, + {9, 0x02, 198}, + {23, 0x02, 198}, + {40, 0x03, 198}, + {2, 0x02, 228}, + {9, 0x02, 228}, + {23, 0x02, 228}, + {40, 0x03, 228}, + {2, 0x02, 232}, + {9, 0x02, 232}, + {23, 0x02, 232}, + {40, 0x03, 232}, + {2, 0x02, 233}, + {9, 0x02, 233}, + {23, 0x02, 233}, + {40, 0x03, 233}, + }, + + { + {3, 0x02, 198}, + {6, 0x02, 198}, + {10, 0x02, 198}, + {15, 0x02, 198}, + {24, 0x02, 198}, + {31, 0x02, 198}, + {41, 0x02, 198}, + {56, 0x03, 198}, + {3, 0x02, 228}, + {6, 0x02, 228}, + {10, 0x02, 228}, + {15, 0x02, 228}, + {24, 0x02, 228}, + {31, 0x02, 228}, + {41, 0x02, 228}, + {56, 0x03, 228}, + }, + + { + {3, 0x02, 232}, + {6, 0x02, 232}, + {10, 0x02, 232}, + {15, 0x02, 232}, + {24, 0x02, 232}, + {31, 0x02, 232}, + {41, 0x02, 232}, + {56, 0x03, 232}, + {3, 0x02, 233}, + {6, 0x02, 233}, + {10, 0x02, 233}, + {15, 0x02, 233}, + {24, 0x02, 233}, + {31, 0x02, 233}, + {41, 0x02, 233}, + {56, 0x03, 233}, + }, + + { + {1, 0x02, 1}, + {22, 0x03, 1}, + {1, 0x02, 135}, + {22, 0x03, 135}, + {1, 0x02, 137}, + {22, 0x03, 137}, + {1, 0x02, 138}, + {22, 0x03, 138}, + {1, 0x02, 139}, + {22, 0x03, 139}, + {1, 0x02, 140}, + {22, 0x03, 140}, + {1, 0x02, 141}, + {22, 0x03, 141}, + {1, 0x02, 143}, + {22, 0x03, 143}, + }, + + { + {2, 0x02, 1}, + {9, 0x02, 1}, + {23, 0x02, 1}, + {40, 0x03, 1}, + {2, 0x02, 135}, + {9, 0x02, 135}, + {23, 0x02, 135}, + {40, 0x03, 135}, + {2, 0x02, 137}, + {9, 0x02, 137}, + {23, 0x02, 137}, + {40, 0x03, 137}, + {2, 0x02, 138}, + {9, 0x02, 138}, + {23, 0x02, 138}, + {40, 0x03, 138}, + }, + + { + {3, 0x02, 1}, + {6, 0x02, 1}, + {10, 0x02, 1}, + {15, 0x02, 1}, + {24, 0x02, 1}, + {31, 0x02, 1}, + {41, 0x02, 1}, + {56, 0x03, 1}, + {3, 0x02, 135}, + {6, 0x02, 135}, + {10, 0x02, 135}, + {15, 0x02, 135}, + {24, 0x02, 135}, + {31, 0x02, 135}, + {41, 0x02, 135}, + {56, 0x03, 135}, + }, + + { + {3, 0x02, 137}, + {6, 0x02, 137}, + {10, 0x02, 137}, + {15, 0x02, 137}, + {24, 0x02, 137}, + {31, 0x02, 137}, + {41, 0x02, 137}, + {56, 0x03, 137}, + {3, 0x02, 138}, + {6, 0x02, 138}, + {10, 0x02, 138}, + {15, 0x02, 138}, + {24, 0x02, 138}, + {31, 0x02, 138}, + {41, 0x02, 138}, + {56, 0x03, 138}, + }, + + { + {2, 0x02, 139}, + {9, 0x02, 139}, + {23, 0x02, 139}, + {40, 0x03, 139}, + {2, 0x02, 140}, + {9, 0x02, 140}, + {23, 0x02, 140}, + {40, 0x03, 140}, + {2, 0x02, 141}, + {9, 0x02, 141}, + {23, 0x02, 141}, + {40, 0x03, 141}, + {2, 0x02, 143}, + {9, 0x02, 143}, + {23, 0x02, 143}, + {40, 0x03, 143}, + }, + + { + {3, 0x02, 139}, + {6, 0x02, 139}, + {10, 0x02, 139}, + {15, 0x02, 139}, + {24, 0x02, 139}, + {31, 0x02, 139}, + {41, 0x02, 139}, + {56, 0x03, 139}, + {3, 0x02, 140}, + {6, 0x02, 140}, + {10, 0x02, 140}, + {15, 0x02, 140}, + {24, 0x02, 140}, + {31, 0x02, 140}, + {41, 0x02, 140}, + {56, 0x03, 140}, + }, + + { + {3, 0x02, 141}, + {6, 0x02, 141}, + {10, 0x02, 141}, + {15, 0x02, 141}, + {24, 0x02, 141}, + {31, 0x02, 141}, + {41, 0x02, 141}, + {56, 0x03, 141}, + {3, 0x02, 143}, + {6, 0x02, 143}, + {10, 0x02, 143}, + {15, 0x02, 143}, + {24, 0x02, 143}, + {31, 0x02, 143}, + {41, 0x02, 143}, + {56, 0x03, 143}, + }, + + { + {157, 0x00, 0}, + {158, 0x00, 0}, + {160, 0x00, 0}, + {161, 0x00, 0}, + {164, 0x00, 0}, + {165, 0x00, 0}, + {167, 0x00, 0}, + {168, 0x00, 0}, + {172, 0x00, 0}, + {173, 0x00, 0}, + {175, 0x00, 0}, + {177, 0x00, 0}, + {182, 0x00, 0}, + {185, 0x00, 0}, + {191, 0x00, 0}, + {207, 0x00, 0}, + }, + + { + {0, 0x03, 147}, + {0, 0x03, 149}, + {0, 0x03, 150}, + {0, 0x03, 151}, + {0, 0x03, 152}, + {0, 0x03, 155}, + {0, 0x03, 157}, + {0, 0x03, 158}, + {0, 0x03, 165}, + {0, 0x03, 166}, + {0, 0x03, 168}, + {0, 0x03, 174}, + {0, 0x03, 175}, + {0, 0x03, 180}, + {0, 0x03, 182}, + {0, 0x03, 183}, + }, + + { + {1, 0x02, 147}, + {22, 0x03, 147}, + {1, 0x02, 149}, + {22, 0x03, 149}, + {1, 0x02, 150}, + {22, 0x03, 150}, + {1, 0x02, 151}, + {22, 0x03, 151}, + {1, 0x02, 152}, + {22, 0x03, 152}, + {1, 0x02, 155}, + {22, 0x03, 155}, + {1, 0x02, 157}, + {22, 0x03, 157}, + {1, 0x02, 158}, + {22, 0x03, 158}, + }, + + { + {2, 0x02, 147}, + {9, 0x02, 147}, + {23, 0x02, 147}, + {40, 0x03, 147}, + {2, 0x02, 149}, + {9, 0x02, 149}, + {23, 0x02, 149}, + {40, 0x03, 149}, + {2, 0x02, 150}, + {9, 0x02, 150}, + {23, 0x02, 150}, + {40, 0x03, 150}, + {2, 0x02, 151}, + {9, 0x02, 151}, + {23, 0x02, 151}, + {40, 0x03, 151}, + }, + + { + {3, 0x02, 147}, + {6, 0x02, 147}, + {10, 0x02, 147}, + {15, 0x02, 147}, + {24, 0x02, 147}, + {31, 0x02, 147}, + {41, 0x02, 147}, + {56, 0x03, 147}, + {3, 0x02, 149}, + {6, 0x02, 149}, + {10, 0x02, 149}, + {15, 0x02, 149}, + {24, 0x02, 149}, + {31, 0x02, 149}, + {41, 0x02, 149}, + {56, 0x03, 149}, + }, + + { + {3, 0x02, 150}, + {6, 0x02, 150}, + {10, 0x02, 150}, + {15, 0x02, 150}, + {24, 0x02, 150}, + {31, 0x02, 150}, + {41, 0x02, 150}, + {56, 0x03, 150}, + {3, 0x02, 151}, + {6, 0x02, 151}, + {10, 0x02, 151}, + {15, 0x02, 151}, + {24, 0x02, 151}, + {31, 0x02, 151}, + {41, 0x02, 151}, + {56, 0x03, 151}, + }, + + { + {2, 0x02, 152}, + {9, 0x02, 152}, + {23, 0x02, 152}, + {40, 0x03, 152}, + {2, 0x02, 155}, + {9, 0x02, 155}, + {23, 0x02, 155}, + {40, 0x03, 155}, + {2, 0x02, 157}, + {9, 0x02, 157}, + {23, 0x02, 157}, + {40, 0x03, 157}, + {2, 0x02, 158}, + {9, 0x02, 158}, + {23, 0x02, 158}, + {40, 0x03, 158}, + }, + + { + {3, 0x02, 152}, + {6, 0x02, 152}, + {10, 0x02, 152}, + {15, 0x02, 152}, + {24, 0x02, 152}, + {31, 0x02, 152}, + {41, 0x02, 152}, + {56, 0x03, 152}, + {3, 0x02, 155}, + {6, 0x02, 155}, + {10, 0x02, 155}, + {15, 0x02, 155}, + {24, 0x02, 155}, + {31, 0x02, 155}, + {41, 0x02, 155}, + {56, 0x03, 155}, + }, + + { + {3, 0x02, 157}, + {6, 0x02, 157}, + {10, 0x02, 157}, + {15, 0x02, 157}, + {24, 0x02, 157}, + {31, 0x02, 157}, + {41, 0x02, 157}, + {56, 0x03, 157}, + {3, 0x02, 158}, + {6, 0x02, 158}, + {10, 0x02, 158}, + {15, 0x02, 158}, + {24, 0x02, 158}, + {31, 0x02, 158}, + {41, 0x02, 158}, + {56, 0x03, 158}, + }, + + { + {1, 0x02, 165}, + {22, 0x03, 165}, + {1, 0x02, 166}, + {22, 0x03, 166}, + {1, 0x02, 168}, + {22, 0x03, 168}, + {1, 0x02, 174}, + {22, 0x03, 174}, + {1, 0x02, 175}, + {22, 0x03, 175}, + {1, 0x02, 180}, + {22, 0x03, 180}, + {1, 0x02, 182}, + {22, 0x03, 182}, + {1, 0x02, 183}, + {22, 0x03, 183}, + }, + + { + {2, 0x02, 165}, + {9, 0x02, 165}, + {23, 0x02, 165}, + {40, 0x03, 165}, + {2, 0x02, 166}, + {9, 0x02, 166}, + {23, 0x02, 166}, + {40, 0x03, 166}, + {2, 0x02, 168}, + {9, 0x02, 168}, + {23, 0x02, 168}, + {40, 0x03, 168}, + {2, 0x02, 174}, + {9, 0x02, 174}, + {23, 0x02, 174}, + {40, 0x03, 174}, + }, + + { + {3, 0x02, 165}, + {6, 0x02, 165}, + {10, 0x02, 165}, + {15, 0x02, 165}, + {24, 0x02, 165}, + {31, 0x02, 165}, + {41, 0x02, 165}, + {56, 0x03, 165}, + {3, 0x02, 166}, + {6, 0x02, 166}, + {10, 0x02, 166}, + {15, 0x02, 166}, + {24, 0x02, 166}, + {31, 0x02, 166}, + {41, 0x02, 166}, + {56, 0x03, 166}, + }, + + { + {3, 0x02, 168}, + {6, 0x02, 168}, + {10, 0x02, 168}, + {15, 0x02, 168}, + {24, 0x02, 168}, + {31, 0x02, 168}, + {41, 0x02, 168}, + {56, 0x03, 168}, + {3, 0x02, 174}, + {6, 0x02, 174}, + {10, 0x02, 174}, + {15, 0x02, 174}, + {24, 0x02, 174}, + {31, 0x02, 174}, + {41, 0x02, 174}, + {56, 0x03, 174}, + }, + + { + {2, 0x02, 175}, + {9, 0x02, 175}, + {23, 0x02, 175}, + {40, 0x03, 175}, + {2, 0x02, 180}, + {9, 0x02, 180}, + {23, 0x02, 180}, + {40, 0x03, 180}, + {2, 0x02, 182}, + {9, 0x02, 182}, + {23, 0x02, 182}, + {40, 0x03, 182}, + {2, 0x02, 183}, + {9, 0x02, 183}, + {23, 0x02, 183}, + {40, 0x03, 183}, + }, + + { + {3, 0x02, 175}, + {6, 0x02, 175}, + {10, 0x02, 175}, + {15, 0x02, 175}, + {24, 0x02, 175}, + {31, 0x02, 175}, + {41, 0x02, 175}, + {56, 0x03, 175}, + {3, 0x02, 180}, + {6, 0x02, 180}, + {10, 0x02, 180}, + {15, 0x02, 180}, + {24, 0x02, 180}, + {31, 0x02, 180}, + {41, 0x02, 180}, + {56, 0x03, 180}, + }, + + { + {3, 0x02, 182}, + {6, 0x02, 182}, + {10, 0x02, 182}, + {15, 0x02, 182}, + {24, 0x02, 182}, + {31, 0x02, 182}, + {41, 0x02, 182}, + {56, 0x03, 182}, + {3, 0x02, 183}, + {6, 0x02, 183}, + {10, 0x02, 183}, + {15, 0x02, 183}, + {24, 0x02, 183}, + {31, 0x02, 183}, + {41, 0x02, 183}, + {56, 0x03, 183}, + }, + + { + {0, 0x03, 188}, + {0, 0x03, 191}, + {0, 0x03, 197}, + {0, 0x03, 231}, + {0, 0x03, 239}, + {176, 0x00, 0}, + {178, 0x00, 0}, + {179, 0x00, 0}, + {183, 0x00, 0}, + {184, 0x00, 0}, + {186, 0x00, 0}, + {187, 0x00, 0}, + {192, 0x00, 0}, + {199, 0x00, 0}, + {208, 0x00, 0}, + {223, 0x00, 0}, + }, + + { + {1, 0x02, 188}, + {22, 0x03, 188}, + {1, 0x02, 191}, + {22, 0x03, 191}, + {1, 0x02, 197}, + {22, 0x03, 197}, + {1, 0x02, 231}, + {22, 0x03, 231}, + {1, 0x02, 239}, + {22, 0x03, 239}, + {0, 0x03, 9}, + {0, 0x03, 142}, + {0, 0x03, 144}, + {0, 0x03, 145}, + {0, 0x03, 148}, + {0, 0x03, 159}, + }, + + { + {2, 0x02, 188}, + {9, 0x02, 188}, + {23, 0x02, 188}, + {40, 0x03, 188}, + {2, 0x02, 191}, + {9, 0x02, 191}, + {23, 0x02, 191}, + {40, 0x03, 191}, + {2, 0x02, 197}, + {9, 0x02, 197}, + {23, 0x02, 197}, + {40, 0x03, 197}, + {2, 0x02, 231}, + {9, 0x02, 231}, + {23, 0x02, 231}, + {40, 0x03, 231}, + }, + + { + {3, 0x02, 188}, + {6, 0x02, 188}, + {10, 0x02, 188}, + {15, 0x02, 188}, + {24, 0x02, 188}, + {31, 0x02, 188}, + {41, 0x02, 188}, + {56, 0x03, 188}, + {3, 0x02, 191}, + {6, 0x02, 191}, + {10, 0x02, 191}, + {15, 0x02, 191}, + {24, 0x02, 191}, + {31, 0x02, 191}, + {41, 0x02, 191}, + {56, 0x03, 191}, + }, + + { + {3, 0x02, 197}, + {6, 0x02, 197}, + {10, 0x02, 197}, + {15, 0x02, 197}, + {24, 0x02, 197}, + {31, 0x02, 197}, + {41, 0x02, 197}, + {56, 0x03, 197}, + {3, 0x02, 231}, + {6, 0x02, 231}, + {10, 0x02, 231}, + {15, 0x02, 231}, + {24, 0x02, 231}, + {31, 0x02, 231}, + {41, 0x02, 231}, + {56, 0x03, 231}, + }, + + { + {2, 0x02, 239}, + {9, 0x02, 239}, + {23, 0x02, 239}, + {40, 0x03, 239}, + {1, 0x02, 9}, + {22, 0x03, 9}, + {1, 0x02, 142}, + {22, 0x03, 142}, + {1, 0x02, 144}, + {22, 0x03, 144}, + {1, 0x02, 145}, + {22, 0x03, 145}, + {1, 0x02, 148}, + {22, 0x03, 148}, + {1, 0x02, 159}, + {22, 0x03, 159}, + }, + + { + {3, 0x02, 239}, + {6, 0x02, 239}, + {10, 0x02, 239}, + {15, 0x02, 239}, + {24, 0x02, 239}, + {31, 0x02, 239}, + {41, 0x02, 239}, + {56, 0x03, 239}, + {2, 0x02, 9}, + {9, 0x02, 9}, + {23, 0x02, 9}, + {40, 0x03, 9}, + {2, 0x02, 142}, + {9, 0x02, 142}, + {23, 0x02, 142}, + {40, 0x03, 142}, + }, + + { + {3, 0x02, 9}, + {6, 0x02, 9}, + {10, 0x02, 9}, + {15, 0x02, 9}, + {24, 0x02, 9}, + {31, 0x02, 9}, + {41, 0x02, 9}, + {56, 0x03, 9}, + {3, 0x02, 142}, + {6, 0x02, 142}, + {10, 0x02, 142}, + {15, 0x02, 142}, + {24, 0x02, 142}, + {31, 0x02, 142}, + {41, 0x02, 142}, + {56, 0x03, 142}, + }, + + { + {2, 0x02, 144}, + {9, 0x02, 144}, + {23, 0x02, 144}, + {40, 0x03, 144}, + {2, 0x02, 145}, + {9, 0x02, 145}, + {23, 0x02, 145}, + {40, 0x03, 145}, + {2, 0x02, 148}, + {9, 0x02, 148}, + {23, 0x02, 148}, + {40, 0x03, 148}, + {2, 0x02, 159}, + {9, 0x02, 159}, + {23, 0x02, 159}, + {40, 0x03, 159}, + }, + + { + {3, 0x02, 144}, + {6, 0x02, 144}, + {10, 0x02, 144}, + {15, 0x02, 144}, + {24, 0x02, 144}, + {31, 0x02, 144}, + {41, 0x02, 144}, + {56, 0x03, 144}, + {3, 0x02, 145}, + {6, 0x02, 145}, + {10, 0x02, 145}, + {15, 0x02, 145}, + {24, 0x02, 145}, + {31, 0x02, 145}, + {41, 0x02, 145}, + {56, 0x03, 145}, + }, + + { + {3, 0x02, 148}, + {6, 0x02, 148}, + {10, 0x02, 148}, + {15, 0x02, 148}, + {24, 0x02, 148}, + {31, 0x02, 148}, + {41, 0x02, 148}, + {56, 0x03, 148}, + {3, 0x02, 159}, + {6, 0x02, 159}, + {10, 0x02, 159}, + {15, 0x02, 159}, + {24, 0x02, 159}, + {31, 0x02, 159}, + {41, 0x02, 159}, + {56, 0x03, 159}, + }, + + { + {0, 0x03, 171}, + {0, 0x03, 206}, + {0, 0x03, 215}, + {0, 0x03, 225}, + {0, 0x03, 236}, + {0, 0x03, 237}, + {188, 0x00, 0}, + {189, 0x00, 0}, + {193, 0x00, 0}, + {196, 0x00, 0}, + {200, 0x00, 0}, + {203, 0x00, 0}, + {209, 0x00, 0}, + {216, 0x00, 0}, + {224, 0x00, 0}, + {238, 0x00, 0}, + }, + + { + {1, 0x02, 171}, + {22, 0x03, 171}, + {1, 0x02, 206}, + {22, 0x03, 206}, + {1, 0x02, 215}, + {22, 0x03, 215}, + {1, 0x02, 225}, + {22, 0x03, 225}, + {1, 0x02, 236}, + {22, 0x03, 236}, + {1, 0x02, 237}, + {22, 0x03, 237}, + {0, 0x03, 199}, + {0, 0x03, 207}, + {0, 0x03, 234}, + {0, 0x03, 235}, + }, + + { + {2, 0x02, 171}, + {9, 0x02, 171}, + {23, 0x02, 171}, + {40, 0x03, 171}, + {2, 0x02, 206}, + {9, 0x02, 206}, + {23, 0x02, 206}, + {40, 0x03, 206}, + {2, 0x02, 215}, + {9, 0x02, 215}, + {23, 0x02, 215}, + {40, 0x03, 215}, + {2, 0x02, 225}, + {9, 0x02, 225}, + {23, 0x02, 225}, + {40, 0x03, 225}, + }, + + { + {3, 0x02, 171}, + {6, 0x02, 171}, + {10, 0x02, 171}, + {15, 0x02, 171}, + {24, 0x02, 171}, + {31, 0x02, 171}, + {41, 0x02, 171}, + {56, 0x03, 171}, + {3, 0x02, 206}, + {6, 0x02, 206}, + {10, 0x02, 206}, + {15, 0x02, 206}, + {24, 0x02, 206}, + {31, 0x02, 206}, + {41, 0x02, 206}, + {56, 0x03, 206}, + }, + + { + {3, 0x02, 215}, + {6, 0x02, 215}, + {10, 0x02, 215}, + {15, 0x02, 215}, + {24, 0x02, 215}, + {31, 0x02, 215}, + {41, 0x02, 215}, + {56, 0x03, 215}, + {3, 0x02, 225}, + {6, 0x02, 225}, + {10, 0x02, 225}, + {15, 0x02, 225}, + {24, 0x02, 225}, + {31, 0x02, 225}, + {41, 0x02, 225}, + {56, 0x03, 225}, + }, + + { + {2, 0x02, 236}, + {9, 0x02, 236}, + {23, 0x02, 236}, + {40, 0x03, 236}, + {2, 0x02, 237}, + {9, 0x02, 237}, + {23, 0x02, 237}, + {40, 0x03, 237}, + {1, 0x02, 199}, + {22, 0x03, 199}, + {1, 0x02, 207}, + {22, 0x03, 207}, + {1, 0x02, 234}, + {22, 0x03, 234}, + {1, 0x02, 235}, + {22, 0x03, 235}, + }, + + { + {3, 0x02, 236}, + {6, 0x02, 236}, + {10, 0x02, 236}, + {15, 0x02, 236}, + {24, 0x02, 236}, + {31, 0x02, 236}, + {41, 0x02, 236}, + {56, 0x03, 236}, + {3, 0x02, 237}, + {6, 0x02, 237}, + {10, 0x02, 237}, + {15, 0x02, 237}, + {24, 0x02, 237}, + {31, 0x02, 237}, + {41, 0x02, 237}, + {56, 0x03, 237}, + }, + + { + {2, 0x02, 199}, + {9, 0x02, 199}, + {23, 0x02, 199}, + {40, 0x03, 199}, + {2, 0x02, 207}, + {9, 0x02, 207}, + {23, 0x02, 207}, + {40, 0x03, 207}, + {2, 0x02, 234}, + {9, 0x02, 234}, + {23, 0x02, 234}, + {40, 0x03, 234}, + {2, 0x02, 235}, + {9, 0x02, 235}, + {23, 0x02, 235}, + {40, 0x03, 235}, + }, + + { + {3, 0x02, 199}, + {6, 0x02, 199}, + {10, 0x02, 199}, + {15, 0x02, 199}, + {24, 0x02, 199}, + {31, 0x02, 199}, + {41, 0x02, 199}, + {56, 0x03, 199}, + {3, 0x02, 207}, + {6, 0x02, 207}, + {10, 0x02, 207}, + {15, 0x02, 207}, + {24, 0x02, 207}, + {31, 0x02, 207}, + {41, 0x02, 207}, + {56, 0x03, 207}, + }, + + { + {3, 0x02, 234}, + {6, 0x02, 234}, + {10, 0x02, 234}, + {15, 0x02, 234}, + {24, 0x02, 234}, + {31, 0x02, 234}, + {41, 0x02, 234}, + {56, 0x03, 234}, + {3, 0x02, 235}, + {6, 0x02, 235}, + {10, 0x02, 235}, + {15, 0x02, 235}, + {24, 0x02, 235}, + {31, 0x02, 235}, + {41, 0x02, 235}, + {56, 0x03, 235}, + }, + + { + {194, 0x00, 0}, + {195, 0x00, 0}, + {197, 0x00, 0}, + {198, 0x00, 0}, + {201, 0x00, 0}, + {202, 0x00, 0}, + {204, 0x00, 0}, + {205, 0x00, 0}, + {210, 0x00, 0}, + {213, 0x00, 0}, + {217, 0x00, 0}, + {220, 0x00, 0}, + {225, 0x00, 0}, + {231, 0x00, 0}, + {239, 0x00, 0}, + {246, 0x00, 0}, + }, + + { + {0, 0x03, 192}, + {0, 0x03, 193}, + {0, 0x03, 200}, + {0, 0x03, 201}, + {0, 0x03, 202}, + {0, 0x03, 205}, + {0, 0x03, 210}, + {0, 0x03, 213}, + {0, 0x03, 218}, + {0, 0x03, 219}, + {0, 0x03, 238}, + {0, 0x03, 240}, + {0, 0x03, 242}, + {0, 0x03, 243}, + {0, 0x03, 255}, + {206, 0x00, 0}, + }, + + { + {1, 0x02, 192}, + {22, 0x03, 192}, + {1, 0x02, 193}, + {22, 0x03, 193}, + {1, 0x02, 200}, + {22, 0x03, 200}, + {1, 0x02, 201}, + {22, 0x03, 201}, + {1, 0x02, 202}, + {22, 0x03, 202}, + {1, 0x02, 205}, + {22, 0x03, 205}, + {1, 0x02, 210}, + {22, 0x03, 210}, + {1, 0x02, 213}, + {22, 0x03, 213}, + }, + + { + {2, 0x02, 192}, + {9, 0x02, 192}, + {23, 0x02, 192}, + {40, 0x03, 192}, + {2, 0x02, 193}, + {9, 0x02, 193}, + {23, 0x02, 193}, + {40, 0x03, 193}, + {2, 0x02, 200}, + {9, 0x02, 200}, + {23, 0x02, 200}, + {40, 0x03, 200}, + {2, 0x02, 201}, + {9, 0x02, 201}, + {23, 0x02, 201}, + {40, 0x03, 201}, + }, + + { + {3, 0x02, 192}, + {6, 0x02, 192}, + {10, 0x02, 192}, + {15, 0x02, 192}, + {24, 0x02, 192}, + {31, 0x02, 192}, + {41, 0x02, 192}, + {56, 0x03, 192}, + {3, 0x02, 193}, + {6, 0x02, 193}, + {10, 0x02, 193}, + {15, 0x02, 193}, + {24, 0x02, 193}, + {31, 0x02, 193}, + {41, 0x02, 193}, + {56, 0x03, 193}, + }, + + { + {3, 0x02, 200}, + {6, 0x02, 200}, + {10, 0x02, 200}, + {15, 0x02, 200}, + {24, 0x02, 200}, + {31, 0x02, 200}, + {41, 0x02, 200}, + {56, 0x03, 200}, + {3, 0x02, 201}, + {6, 0x02, 201}, + {10, 0x02, 201}, + {15, 0x02, 201}, + {24, 0x02, 201}, + {31, 0x02, 201}, + {41, 0x02, 201}, + {56, 0x03, 201}, + }, + + { + {2, 0x02, 202}, + {9, 0x02, 202}, + {23, 0x02, 202}, + {40, 0x03, 202}, + {2, 0x02, 205}, + {9, 0x02, 205}, + {23, 0x02, 205}, + {40, 0x03, 205}, + {2, 0x02, 210}, + {9, 0x02, 210}, + {23, 0x02, 210}, + {40, 0x03, 210}, + {2, 0x02, 213}, + {9, 0x02, 213}, + {23, 0x02, 213}, + {40, 0x03, 213}, + }, + + { + {3, 0x02, 202}, + {6, 0x02, 202}, + {10, 0x02, 202}, + {15, 0x02, 202}, + {24, 0x02, 202}, + {31, 0x02, 202}, + {41, 0x02, 202}, + {56, 0x03, 202}, + {3, 0x02, 205}, + {6, 0x02, 205}, + {10, 0x02, 205}, + {15, 0x02, 205}, + {24, 0x02, 205}, + {31, 0x02, 205}, + {41, 0x02, 205}, + {56, 0x03, 205}, + }, + + { + {3, 0x02, 210}, + {6, 0x02, 210}, + {10, 0x02, 210}, + {15, 0x02, 210}, + {24, 0x02, 210}, + {31, 0x02, 210}, + {41, 0x02, 210}, + {56, 0x03, 210}, + {3, 0x02, 213}, + {6, 0x02, 213}, + {10, 0x02, 213}, + {15, 0x02, 213}, + {24, 0x02, 213}, + {31, 0x02, 213}, + {41, 0x02, 213}, + {56, 0x03, 213}, + }, + + { + {1, 0x02, 218}, + {22, 0x03, 218}, + {1, 0x02, 219}, + {22, 0x03, 219}, + {1, 0x02, 238}, + {22, 0x03, 238}, + {1, 0x02, 240}, + {22, 0x03, 240}, + {1, 0x02, 242}, + {22, 0x03, 242}, + {1, 0x02, 243}, + {22, 0x03, 243}, + {1, 0x02, 255}, + {22, 0x03, 255}, + {0, 0x03, 203}, + {0, 0x03, 204}, + }, + + { + {2, 0x02, 218}, + {9, 0x02, 218}, + {23, 0x02, 218}, + {40, 0x03, 218}, + {2, 0x02, 219}, + {9, 0x02, 219}, + {23, 0x02, 219}, + {40, 0x03, 219}, + {2, 0x02, 238}, + {9, 0x02, 238}, + {23, 0x02, 238}, + {40, 0x03, 238}, + {2, 0x02, 240}, + {9, 0x02, 240}, + {23, 0x02, 240}, + {40, 0x03, 240}, + }, + + { + {3, 0x02, 218}, + {6, 0x02, 218}, + {10, 0x02, 218}, + {15, 0x02, 218}, + {24, 0x02, 218}, + {31, 0x02, 218}, + {41, 0x02, 218}, + {56, 0x03, 218}, + {3, 0x02, 219}, + {6, 0x02, 219}, + {10, 0x02, 219}, + {15, 0x02, 219}, + {24, 0x02, 219}, + {31, 0x02, 219}, + {41, 0x02, 219}, + {56, 0x03, 219}, + }, + + { + {3, 0x02, 238}, + {6, 0x02, 238}, + {10, 0x02, 238}, + {15, 0x02, 238}, + {24, 0x02, 238}, + {31, 0x02, 238}, + {41, 0x02, 238}, + {56, 0x03, 238}, + {3, 0x02, 240}, + {6, 0x02, 240}, + {10, 0x02, 240}, + {15, 0x02, 240}, + {24, 0x02, 240}, + {31, 0x02, 240}, + {41, 0x02, 240}, + {56, 0x03, 240}, + }, + + { + {2, 0x02, 242}, + {9, 0x02, 242}, + {23, 0x02, 242}, + {40, 0x03, 242}, + {2, 0x02, 243}, + {9, 0x02, 243}, + {23, 0x02, 243}, + {40, 0x03, 243}, + {2, 0x02, 255}, + {9, 0x02, 255}, + {23, 0x02, 255}, + {40, 0x03, 255}, + {1, 0x02, 203}, + {22, 0x03, 203}, + {1, 0x02, 204}, + {22, 0x03, 204}, + }, + + { + {3, 0x02, 242}, + {6, 0x02, 242}, + {10, 0x02, 242}, + {15, 0x02, 242}, + {24, 0x02, 242}, + {31, 0x02, 242}, + {41, 0x02, 242}, + {56, 0x03, 242}, + {3, 0x02, 243}, + {6, 0x02, 243}, + {10, 0x02, 243}, + {15, 0x02, 243}, + {24, 0x02, 243}, + {31, 0x02, 243}, + {41, 0x02, 243}, + {56, 0x03, 243}, + }, + + { + {3, 0x02, 255}, + {6, 0x02, 255}, + {10, 0x02, 255}, + {15, 0x02, 255}, + {24, 0x02, 255}, + {31, 0x02, 255}, + {41, 0x02, 255}, + {56, 0x03, 255}, + {2, 0x02, 203}, + {9, 0x02, 203}, + {23, 0x02, 203}, + {40, 0x03, 203}, + {2, 0x02, 204}, + {9, 0x02, 204}, + {23, 0x02, 204}, + {40, 0x03, 204}, + }, + + { + {3, 0x02, 203}, + {6, 0x02, 203}, + {10, 0x02, 203}, + {15, 0x02, 203}, + {24, 0x02, 203}, + {31, 0x02, 203}, + {41, 0x02, 203}, + {56, 0x03, 203}, + {3, 0x02, 204}, + {6, 0x02, 204}, + {10, 0x02, 204}, + {15, 0x02, 204}, + {24, 0x02, 204}, + {31, 0x02, 204}, + {41, 0x02, 204}, + {56, 0x03, 204}, + }, + + { + {211, 0x00, 0}, + {212, 0x00, 0}, + {214, 0x00, 0}, + {215, 0x00, 0}, + {218, 0x00, 0}, + {219, 0x00, 0}, + {221, 0x00, 0}, + {222, 0x00, 0}, + {226, 0x00, 0}, + {228, 0x00, 0}, + {232, 0x00, 0}, + {235, 0x00, 0}, + {240, 0x00, 0}, + {243, 0x00, 0}, + {247, 0x00, 0}, + {250, 0x00, 0}, + }, + + { + {0, 0x03, 211}, + {0, 0x03, 212}, + {0, 0x03, 214}, + {0, 0x03, 221}, + {0, 0x03, 222}, + {0, 0x03, 223}, + {0, 0x03, 241}, + {0, 0x03, 244}, + {0, 0x03, 245}, + {0, 0x03, 246}, + {0, 0x03, 247}, + {0, 0x03, 248}, + {0, 0x03, 250}, + {0, 0x03, 251}, + {0, 0x03, 252}, + {0, 0x03, 253}, + }, + + { + {1, 0x02, 211}, + {22, 0x03, 211}, + {1, 0x02, 212}, + {22, 0x03, 212}, + {1, 0x02, 214}, + {22, 0x03, 214}, + {1, 0x02, 221}, + {22, 0x03, 221}, + {1, 0x02, 222}, + {22, 0x03, 222}, + {1, 0x02, 223}, + {22, 0x03, 223}, + {1, 0x02, 241}, + {22, 0x03, 241}, + {1, 0x02, 244}, + {22, 0x03, 244}, + }, + + { + {2, 0x02, 211}, + {9, 0x02, 211}, + {23, 0x02, 211}, + {40, 0x03, 211}, + {2, 0x02, 212}, + {9, 0x02, 212}, + {23, 0x02, 212}, + {40, 0x03, 212}, + {2, 0x02, 214}, + {9, 0x02, 214}, + {23, 0x02, 214}, + {40, 0x03, 214}, + {2, 0x02, 221}, + {9, 0x02, 221}, + {23, 0x02, 221}, + {40, 0x03, 221}, + }, + + { + {3, 0x02, 211}, + {6, 0x02, 211}, + {10, 0x02, 211}, + {15, 0x02, 211}, + {24, 0x02, 211}, + {31, 0x02, 211}, + {41, 0x02, 211}, + {56, 0x03, 211}, + {3, 0x02, 212}, + {6, 0x02, 212}, + {10, 0x02, 212}, + {15, 0x02, 212}, + {24, 0x02, 212}, + {31, 0x02, 212}, + {41, 0x02, 212}, + {56, 0x03, 212}, + }, + + { + {3, 0x02, 214}, + {6, 0x02, 214}, + {10, 0x02, 214}, + {15, 0x02, 214}, + {24, 0x02, 214}, + {31, 0x02, 214}, + {41, 0x02, 214}, + {56, 0x03, 214}, + {3, 0x02, 221}, + {6, 0x02, 221}, + {10, 0x02, 221}, + {15, 0x02, 221}, + {24, 0x02, 221}, + {31, 0x02, 221}, + {41, 0x02, 221}, + {56, 0x03, 221}, + }, + + { + {2, 0x02, 222}, + {9, 0x02, 222}, + {23, 0x02, 222}, + {40, 0x03, 222}, + {2, 0x02, 223}, + {9, 0x02, 223}, + {23, 0x02, 223}, + {40, 0x03, 223}, + {2, 0x02, 241}, + {9, 0x02, 241}, + {23, 0x02, 241}, + {40, 0x03, 241}, + {2, 0x02, 244}, + {9, 0x02, 244}, + {23, 0x02, 244}, + {40, 0x03, 244}, + }, + + { + {3, 0x02, 222}, + {6, 0x02, 222}, + {10, 0x02, 222}, + {15, 0x02, 222}, + {24, 0x02, 222}, + {31, 0x02, 222}, + {41, 0x02, 222}, + {56, 0x03, 222}, + {3, 0x02, 223}, + {6, 0x02, 223}, + {10, 0x02, 223}, + {15, 0x02, 223}, + {24, 0x02, 223}, + {31, 0x02, 223}, + {41, 0x02, 223}, + {56, 0x03, 223}, + }, + + { + {3, 0x02, 241}, + {6, 0x02, 241}, + {10, 0x02, 241}, + {15, 0x02, 241}, + {24, 0x02, 241}, + {31, 0x02, 241}, + {41, 0x02, 241}, + {56, 0x03, 241}, + {3, 0x02, 244}, + {6, 0x02, 244}, + {10, 0x02, 244}, + {15, 0x02, 244}, + {24, 0x02, 244}, + {31, 0x02, 244}, + {41, 0x02, 244}, + {56, 0x03, 244}, + }, + + { + {1, 0x02, 245}, + {22, 0x03, 245}, + {1, 0x02, 246}, + {22, 0x03, 246}, + {1, 0x02, 247}, + {22, 0x03, 247}, + {1, 0x02, 248}, + {22, 0x03, 248}, + {1, 0x02, 250}, + {22, 0x03, 250}, + {1, 0x02, 251}, + {22, 0x03, 251}, + {1, 0x02, 252}, + {22, 0x03, 252}, + {1, 0x02, 253}, + {22, 0x03, 253}, + }, + + { + {2, 0x02, 245}, + {9, 0x02, 245}, + {23, 0x02, 245}, + {40, 0x03, 245}, + {2, 0x02, 246}, + {9, 0x02, 246}, + {23, 0x02, 246}, + {40, 0x03, 246}, + {2, 0x02, 247}, + {9, 0x02, 247}, + {23, 0x02, 247}, + {40, 0x03, 247}, + {2, 0x02, 248}, + {9, 0x02, 248}, + {23, 0x02, 248}, + {40, 0x03, 248}, + }, + + { + {3, 0x02, 245}, + {6, 0x02, 245}, + {10, 0x02, 245}, + {15, 0x02, 245}, + {24, 0x02, 245}, + {31, 0x02, 245}, + {41, 0x02, 245}, + {56, 0x03, 245}, + {3, 0x02, 246}, + {6, 0x02, 246}, + {10, 0x02, 246}, + {15, 0x02, 246}, + {24, 0x02, 246}, + {31, 0x02, 246}, + {41, 0x02, 246}, + {56, 0x03, 246}, + }, + + { + {3, 0x02, 247}, + {6, 0x02, 247}, + {10, 0x02, 247}, + {15, 0x02, 247}, + {24, 0x02, 247}, + {31, 0x02, 247}, + {41, 0x02, 247}, + {56, 0x03, 247}, + {3, 0x02, 248}, + {6, 0x02, 248}, + {10, 0x02, 248}, + {15, 0x02, 248}, + {24, 0x02, 248}, + {31, 0x02, 248}, + {41, 0x02, 248}, + {56, 0x03, 248}, + }, + + { + {2, 0x02, 250}, + {9, 0x02, 250}, + {23, 0x02, 250}, + {40, 0x03, 250}, + {2, 0x02, 251}, + {9, 0x02, 251}, + {23, 0x02, 251}, + {40, 0x03, 251}, + {2, 0x02, 252}, + {9, 0x02, 252}, + {23, 0x02, 252}, + {40, 0x03, 252}, + {2, 0x02, 253}, + {9, 0x02, 253}, + {23, 0x02, 253}, + {40, 0x03, 253}, + }, + + { + {3, 0x02, 250}, + {6, 0x02, 250}, + {10, 0x02, 250}, + {15, 0x02, 250}, + {24, 0x02, 250}, + {31, 0x02, 250}, + {41, 0x02, 250}, + {56, 0x03, 250}, + {3, 0x02, 251}, + {6, 0x02, 251}, + {10, 0x02, 251}, + {15, 0x02, 251}, + {24, 0x02, 251}, + {31, 0x02, 251}, + {41, 0x02, 251}, + {56, 0x03, 251}, + }, + + { + {3, 0x02, 252}, + {6, 0x02, 252}, + {10, 0x02, 252}, + {15, 0x02, 252}, + {24, 0x02, 252}, + {31, 0x02, 252}, + {41, 0x02, 252}, + {56, 0x03, 252}, + {3, 0x02, 253}, + {6, 0x02, 253}, + {10, 0x02, 253}, + {15, 0x02, 253}, + {24, 0x02, 253}, + {31, 0x02, 253}, + {41, 0x02, 253}, + {56, 0x03, 253}, + }, + + { + {0, 0x03, 254}, + {227, 0x00, 0}, + {229, 0x00, 0}, + {230, 0x00, 0}, + {233, 0x00, 0}, + {234, 0x00, 0}, + {236, 0x00, 0}, + {237, 0x00, 0}, + {241, 0x00, 0}, + {242, 0x00, 0}, + {244, 0x00, 0}, + {245, 0x00, 0}, + {248, 0x00, 0}, + {249, 0x00, 0}, + {251, 0x00, 0}, + {252, 0x00, 0}, + }, + + { + {1, 0x02, 254}, + {22, 0x03, 254}, + {0, 0x03, 2}, + {0, 0x03, 3}, + {0, 0x03, 4}, + {0, 0x03, 5}, + {0, 0x03, 6}, + {0, 0x03, 7}, + {0, 0x03, 8}, + {0, 0x03, 11}, + {0, 0x03, 12}, + {0, 0x03, 14}, + {0, 0x03, 15}, + {0, 0x03, 16}, + {0, 0x03, 17}, + {0, 0x03, 18}, + }, + + { + {2, 0x02, 254}, + {9, 0x02, 254}, + {23, 0x02, 254}, + {40, 0x03, 254}, + {1, 0x02, 2}, + {22, 0x03, 2}, + {1, 0x02, 3}, + {22, 0x03, 3}, + {1, 0x02, 4}, + {22, 0x03, 4}, + {1, 0x02, 5}, + {22, 0x03, 5}, + {1, 0x02, 6}, + {22, 0x03, 6}, + {1, 0x02, 7}, + {22, 0x03, 7}, + }, + + { + {3, 0x02, 254}, + {6, 0x02, 254}, + {10, 0x02, 254}, + {15, 0x02, 254}, + {24, 0x02, 254}, + {31, 0x02, 254}, + {41, 0x02, 254}, + {56, 0x03, 254}, + {2, 0x02, 2}, + {9, 0x02, 2}, + {23, 0x02, 2}, + {40, 0x03, 2}, + {2, 0x02, 3}, + {9, 0x02, 3}, + {23, 0x02, 3}, + {40, 0x03, 3}, + }, + + { + {3, 0x02, 2}, + {6, 0x02, 2}, + {10, 0x02, 2}, + {15, 0x02, 2}, + {24, 0x02, 2}, + {31, 0x02, 2}, + {41, 0x02, 2}, + {56, 0x03, 2}, + {3, 0x02, 3}, + {6, 0x02, 3}, + {10, 0x02, 3}, + {15, 0x02, 3}, + {24, 0x02, 3}, + {31, 0x02, 3}, + {41, 0x02, 3}, + {56, 0x03, 3}, + }, + + { + {2, 0x02, 4}, + {9, 0x02, 4}, + {23, 0x02, 4}, + {40, 0x03, 4}, + {2, 0x02, 5}, + {9, 0x02, 5}, + {23, 0x02, 5}, + {40, 0x03, 5}, + {2, 0x02, 6}, + {9, 0x02, 6}, + {23, 0x02, 6}, + {40, 0x03, 6}, + {2, 0x02, 7}, + {9, 0x02, 7}, + {23, 0x02, 7}, + {40, 0x03, 7}, + }, + + { + {3, 0x02, 4}, + {6, 0x02, 4}, + {10, 0x02, 4}, + {15, 0x02, 4}, + {24, 0x02, 4}, + {31, 0x02, 4}, + {41, 0x02, 4}, + {56, 0x03, 4}, + {3, 0x02, 5}, + {6, 0x02, 5}, + {10, 0x02, 5}, + {15, 0x02, 5}, + {24, 0x02, 5}, + {31, 0x02, 5}, + {41, 0x02, 5}, + {56, 0x03, 5}, + }, + + { + {3, 0x02, 6}, + {6, 0x02, 6}, + {10, 0x02, 6}, + {15, 0x02, 6}, + {24, 0x02, 6}, + {31, 0x02, 6}, + {41, 0x02, 6}, + {56, 0x03, 6}, + {3, 0x02, 7}, + {6, 0x02, 7}, + {10, 0x02, 7}, + {15, 0x02, 7}, + {24, 0x02, 7}, + {31, 0x02, 7}, + {41, 0x02, 7}, + {56, 0x03, 7}, + }, + + { + {1, 0x02, 8}, + {22, 0x03, 8}, + {1, 0x02, 11}, + {22, 0x03, 11}, + {1, 0x02, 12}, + {22, 0x03, 12}, + {1, 0x02, 14}, + {22, 0x03, 14}, + {1, 0x02, 15}, + {22, 0x03, 15}, + {1, 0x02, 16}, + {22, 0x03, 16}, + {1, 0x02, 17}, + {22, 0x03, 17}, + {1, 0x02, 18}, + {22, 0x03, 18}, + }, + + { + {2, 0x02, 8}, + {9, 0x02, 8}, + {23, 0x02, 8}, + {40, 0x03, 8}, + {2, 0x02, 11}, + {9, 0x02, 11}, + {23, 0x02, 11}, + {40, 0x03, 11}, + {2, 0x02, 12}, + {9, 0x02, 12}, + {23, 0x02, 12}, + {40, 0x03, 12}, + {2, 0x02, 14}, + {9, 0x02, 14}, + {23, 0x02, 14}, + {40, 0x03, 14}, + }, + + { + {3, 0x02, 8}, + {6, 0x02, 8}, + {10, 0x02, 8}, + {15, 0x02, 8}, + {24, 0x02, 8}, + {31, 0x02, 8}, + {41, 0x02, 8}, + {56, 0x03, 8}, + {3, 0x02, 11}, + {6, 0x02, 11}, + {10, 0x02, 11}, + {15, 0x02, 11}, + {24, 0x02, 11}, + {31, 0x02, 11}, + {41, 0x02, 11}, + {56, 0x03, 11}, + }, + + { + {3, 0x02, 12}, + {6, 0x02, 12}, + {10, 0x02, 12}, + {15, 0x02, 12}, + {24, 0x02, 12}, + {31, 0x02, 12}, + {41, 0x02, 12}, + {56, 0x03, 12}, + {3, 0x02, 14}, + {6, 0x02, 14}, + {10, 0x02, 14}, + {15, 0x02, 14}, + {24, 0x02, 14}, + {31, 0x02, 14}, + {41, 0x02, 14}, + {56, 0x03, 14}, + }, + + { + {2, 0x02, 15}, + {9, 0x02, 15}, + {23, 0x02, 15}, + {40, 0x03, 15}, + {2, 0x02, 16}, + {9, 0x02, 16}, + {23, 0x02, 16}, + {40, 0x03, 16}, + {2, 0x02, 17}, + {9, 0x02, 17}, + {23, 0x02, 17}, + {40, 0x03, 17}, + {2, 0x02, 18}, + {9, 0x02, 18}, + {23, 0x02, 18}, + {40, 0x03, 18}, + }, + + { + {3, 0x02, 15}, + {6, 0x02, 15}, + {10, 0x02, 15}, + {15, 0x02, 15}, + {24, 0x02, 15}, + {31, 0x02, 15}, + {41, 0x02, 15}, + {56, 0x03, 15}, + {3, 0x02, 16}, + {6, 0x02, 16}, + {10, 0x02, 16}, + {15, 0x02, 16}, + {24, 0x02, 16}, + {31, 0x02, 16}, + {41, 0x02, 16}, + {56, 0x03, 16}, + }, + + { + {3, 0x02, 17}, + {6, 0x02, 17}, + {10, 0x02, 17}, + {15, 0x02, 17}, + {24, 0x02, 17}, + {31, 0x02, 17}, + {41, 0x02, 17}, + {56, 0x03, 17}, + {3, 0x02, 18}, + {6, 0x02, 18}, + {10, 0x02, 18}, + {15, 0x02, 18}, + {24, 0x02, 18}, + {31, 0x02, 18}, + {41, 0x02, 18}, + {56, 0x03, 18}, + }, + + { + {0, 0x03, 19}, + {0, 0x03, 20}, + {0, 0x03, 21}, + {0, 0x03, 23}, + {0, 0x03, 24}, + {0, 0x03, 25}, + {0, 0x03, 26}, + {0, 0x03, 27}, + {0, 0x03, 28}, + {0, 0x03, 29}, + {0, 0x03, 30}, + {0, 0x03, 31}, + {0, 0x03, 127}, + {0, 0x03, 220}, + {0, 0x03, 249}, + {253, 0x00, 0}, + }, + + { + {1, 0x02, 19}, + {22, 0x03, 19}, + {1, 0x02, 20}, + {22, 0x03, 20}, + {1, 0x02, 21}, + {22, 0x03, 21}, + {1, 0x02, 23}, + {22, 0x03, 23}, + {1, 0x02, 24}, + {22, 0x03, 24}, + {1, 0x02, 25}, + {22, 0x03, 25}, + {1, 0x02, 26}, + {22, 0x03, 26}, + {1, 0x02, 27}, + {22, 0x03, 27}, + }, + + { + {2, 0x02, 19}, + {9, 0x02, 19}, + {23, 0x02, 19}, + {40, 0x03, 19}, + {2, 0x02, 20}, + {9, 0x02, 20}, + {23, 0x02, 20}, + {40, 0x03, 20}, + {2, 0x02, 21}, + {9, 0x02, 21}, + {23, 0x02, 21}, + {40, 0x03, 21}, + {2, 0x02, 23}, + {9, 0x02, 23}, + {23, 0x02, 23}, + {40, 0x03, 23}, + }, + + { + {3, 0x02, 19}, + {6, 0x02, 19}, + {10, 0x02, 19}, + {15, 0x02, 19}, + {24, 0x02, 19}, + {31, 0x02, 19}, + {41, 0x02, 19}, + {56, 0x03, 19}, + {3, 0x02, 20}, + {6, 0x02, 20}, + {10, 0x02, 20}, + {15, 0x02, 20}, + {24, 0x02, 20}, + {31, 0x02, 20}, + {41, 0x02, 20}, + {56, 0x03, 20}, + }, + + { + {3, 0x02, 21}, + {6, 0x02, 21}, + {10, 0x02, 21}, + {15, 0x02, 21}, + {24, 0x02, 21}, + {31, 0x02, 21}, + {41, 0x02, 21}, + {56, 0x03, 21}, + {3, 0x02, 23}, + {6, 0x02, 23}, + {10, 0x02, 23}, + {15, 0x02, 23}, + {24, 0x02, 23}, + {31, 0x02, 23}, + {41, 0x02, 23}, + {56, 0x03, 23}, + }, + + { + {2, 0x02, 24}, + {9, 0x02, 24}, + {23, 0x02, 24}, + {40, 0x03, 24}, + {2, 0x02, 25}, + {9, 0x02, 25}, + {23, 0x02, 25}, + {40, 0x03, 25}, + {2, 0x02, 26}, + {9, 0x02, 26}, + {23, 0x02, 26}, + {40, 0x03, 26}, + {2, 0x02, 27}, + {9, 0x02, 27}, + {23, 0x02, 27}, + {40, 0x03, 27}, + }, + + { + {3, 0x02, 24}, + {6, 0x02, 24}, + {10, 0x02, 24}, + {15, 0x02, 24}, + {24, 0x02, 24}, + {31, 0x02, 24}, + {41, 0x02, 24}, + {56, 0x03, 24}, + {3, 0x02, 25}, + {6, 0x02, 25}, + {10, 0x02, 25}, + {15, 0x02, 25}, + {24, 0x02, 25}, + {31, 0x02, 25}, + {41, 0x02, 25}, + {56, 0x03, 25}, + }, + + { + {3, 0x02, 26}, + {6, 0x02, 26}, + {10, 0x02, 26}, + {15, 0x02, 26}, + {24, 0x02, 26}, + {31, 0x02, 26}, + {41, 0x02, 26}, + {56, 0x03, 26}, + {3, 0x02, 27}, + {6, 0x02, 27}, + {10, 0x02, 27}, + {15, 0x02, 27}, + {24, 0x02, 27}, + {31, 0x02, 27}, + {41, 0x02, 27}, + {56, 0x03, 27}, + }, + + { + {1, 0x02, 28}, + {22, 0x03, 28}, + {1, 0x02, 29}, + {22, 0x03, 29}, + {1, 0x02, 30}, + {22, 0x03, 30}, + {1, 0x02, 31}, + {22, 0x03, 31}, + {1, 0x02, 127}, + {22, 0x03, 127}, + {1, 0x02, 220}, + {22, 0x03, 220}, + {1, 0x02, 249}, + {22, 0x03, 249}, + {254, 0x00, 0}, + {255, 0x00, 0}, + }, + + { + {2, 0x02, 28}, + {9, 0x02, 28}, + {23, 0x02, 28}, + {40, 0x03, 28}, + {2, 0x02, 29}, + {9, 0x02, 29}, + {23, 0x02, 29}, + {40, 0x03, 29}, + {2, 0x02, 30}, + {9, 0x02, 30}, + {23, 0x02, 30}, + {40, 0x03, 30}, + {2, 0x02, 31}, + {9, 0x02, 31}, + {23, 0x02, 31}, + {40, 0x03, 31}, + }, + + { + {3, 0x02, 28}, + {6, 0x02, 28}, + {10, 0x02, 28}, + {15, 0x02, 28}, + {24, 0x02, 28}, + {31, 0x02, 28}, + {41, 0x02, 28}, + {56, 0x03, 28}, + {3, 0x02, 29}, + {6, 0x02, 29}, + {10, 0x02, 29}, + {15, 0x02, 29}, + {24, 0x02, 29}, + {31, 0x02, 29}, + {41, 0x02, 29}, + {56, 0x03, 29}, + }, + + { + {3, 0x02, 30}, + {6, 0x02, 30}, + {10, 0x02, 30}, + {15, 0x02, 30}, + {24, 0x02, 30}, + {31, 0x02, 30}, + {41, 0x02, 30}, + {56, 0x03, 30}, + {3, 0x02, 31}, + {6, 0x02, 31}, + {10, 0x02, 31}, + {15, 0x02, 31}, + {24, 0x02, 31}, + {31, 0x02, 31}, + {41, 0x02, 31}, + {56, 0x03, 31}, + }, + + { + {2, 0x02, 127}, + {9, 0x02, 127}, + {23, 0x02, 127}, + {40, 0x03, 127}, + {2, 0x02, 220}, + {9, 0x02, 220}, + {23, 0x02, 220}, + {40, 0x03, 220}, + {2, 0x02, 249}, + {9, 0x02, 249}, + {23, 0x02, 249}, + {40, 0x03, 249}, + {0, 0x03, 10}, + {0, 0x03, 13}, + {0, 0x03, 22}, + {0, 0x04, 0}, + }, + + { + {3, 0x02, 127}, + {6, 0x02, 127}, + {10, 0x02, 127}, + {15, 0x02, 127}, + {24, 0x02, 127}, + {31, 0x02, 127}, + {41, 0x02, 127}, + {56, 0x03, 127}, + {3, 0x02, 220}, + {6, 0x02, 220}, + {10, 0x02, 220}, + {15, 0x02, 220}, + {24, 0x02, 220}, + {31, 0x02, 220}, + {41, 0x02, 220}, + {56, 0x03, 220}, + }, + + { + {3, 0x02, 249}, + {6, 0x02, 249}, + {10, 0x02, 249}, + {15, 0x02, 249}, + {24, 0x02, 249}, + {31, 0x02, 249}, + {41, 0x02, 249}, + {56, 0x03, 249}, + {1, 0x02, 10}, + {22, 0x03, 10}, + {1, 0x02, 13}, + {22, 0x03, 13}, + {1, 0x02, 22}, + {22, 0x03, 22}, + {0, 0x04, 0}, + {0, 0x04, 0}, + }, + + { + {2, 0x02, 10}, + {9, 0x02, 10}, + {23, 0x02, 10}, + {40, 0x03, 10}, + {2, 0x02, 13}, + {9, 0x02, 13}, + {23, 0x02, 13}, + {40, 0x03, 13}, + {2, 0x02, 22}, + {9, 0x02, 22}, + {23, 0x02, 22}, + {40, 0x03, 22}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + }, + + { + {3, 0x02, 10}, + {6, 0x02, 10}, + {10, 0x02, 10}, + {15, 0x02, 10}, + {24, 0x02, 10}, + {31, 0x02, 10}, + {41, 0x02, 10}, + {56, 0x03, 10}, + {3, 0x02, 13}, + {6, 0x02, 13}, + {10, 0x02, 13}, + {15, 0x02, 13}, + {24, 0x02, 13}, + {31, 0x02, 13}, + {41, 0x02, 13}, + {56, 0x03, 13}, + }, + + { + {3, 0x02, 22}, + {6, 0x02, 22}, + {10, 0x02, 22}, + {15, 0x02, 22}, + {24, 0x02, 22}, + {31, 0x02, 22}, + {41, 0x02, 22}, + {56, 0x03, 22}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + {0, 0x04, 0}, + }, + }; + + static const std::pair staticTable[] { + {":authority", ""}, + {":method", "GET"}, + {":method", "POST"}, + {":path", "/"}, + {":path", "/index.html"}, + {":scheme", "http"}, + {":scheme", "https"}, + {":status", "200"}, + {":status", "204"}, + {":status", "206"}, + {":status", "304"}, + {":status", "400"}, + {":status", "404"}, + {":status", "500"}, + {"accept-charset", ""}, + {"accept-encoding", "gzip, deflate"}, + {"accept-language", ""}, + {"accept-ranges", ""}, + {"accept", ""}, + {"access-control-allow-origin", ""}, + {"age", ""}, + {"allow", ""}, + {"authorization", ""}, + {"cache-control", ""}, + {"content-disposition", ""}, + {"content-encoding", ""}, + {"content-language", ""}, + {"content-length", ""}, + {"content-location", ""}, + {"content-range", ""}, + {"content-type", ""}, + {"cookie", ""}, + {"date", ""}, + {"etag", ""}, + {"expect", ""}, + {"expires", ""}, + {"from", ""}, + {"host", ""}, + {"if-match", ""}, + {"if-modified-since", ""}, + {"if-none-match", ""}, + {"if-range", ""}, + {"if-unmodified-since", ""}, + {"last-modified", ""}, + {"link", ""}, + {"location", ""}, + {"max-forwards", ""}, + {"proxy-authenticate", ""}, + {"proxy-authorization", ""}, + {"range", ""}, + {"referer", ""}, + {"refresh", ""}, + {"retry-after", ""}, + {"server", ""}, + {"set-cookie", ""}, + {"strict-transport-security", ""}, + {"transfer-encoding", ""}, + {"user-agent", ""}, + {"vary", ""}, + {"via", ""}, + {"www-authenticate", ""}, + }; + + static constexpr size_t getStaticTableSize() noexcept + { + return sizeof(staticTable) / sizeof(*staticTable); + } + + static size_t huffmanEncodeLength(const void *dest, const size_t length) noexcept + { + const uint8_t *data = reinterpret_cast(dest); + + size_t n = 0; + + for (size_t i = 0; i < length; ++i) + { + n += huffmanSymbolTable[data[i] ].nbits; + } + + return (n + 7) / 8; + } + + static uint8_t huffmanEncodeSymbol(std::vector &dest, uint8_t rembits, const HuffmanSymbol &sym) + { + uint8_t nbits = sym.nbits; + + for (;;) + { + if (rembits > nbits) + { + dest.back() |= uint8_t(sym.code << (rembits - nbits) ); + rembits -= nbits; + break; + } + + dest.back() |= uint8_t(sym.code >> (nbits - rembits) ); + + nbits -= rembits; + rembits = 8; + + if (0 == nbits) + { + break; + } + + dest.emplace_back(0); + } + + return rembits; + } + + static void encode(std::vector &dest, const void* src, const size_t srcSize) + { + const uint8_t *data = reinterpret_cast(src); + + uint8_t rembits = 8; + + for (size_t i = 0; i < srcSize; ++i) + { + const HuffmanSymbol &sym = huffmanSymbolTable[data[i] ]; + + if (8 == rembits) + { + dest.emplace_back(0); + } + + rembits = huffmanEncodeSymbol(dest, rembits, sym); + } + + if (rembits < 8) + { + const HuffmanSymbol &sym = huffmanSymbolTable[256]; + + dest.back() |= uint8_t(sym.code >> (sym.nbits - rembits) ); + } + } + + enum HuffmanDecode + { + ACCEPT = 0x1, + SYMBOL = 0x2, + FAIL = 0x4 + }; + + static bool decode(std::vector &dest, const void* src, const size_t srcSize) + { + const uint8_t *data = reinterpret_cast(src); + const uint8_t *end = data + srcSize; + + uint8_t state = 0; + bool accept = true; + + for (; data < end; ++data) + { + uint8_t c = *data; + uint8_t x = c >> 4; + + for (auto i = 0; i < 2; ++i) + { + const HuffmanDecodeNode &node = huffmanDecodeTable[state][x]; + + if (node.flags & HuffmanDecode::FAIL) + { + return false; + } + + if (node.flags & HuffmanDecode::SYMBOL) + { + dest.emplace_back(node.symbol); + } + + state = node.state; + accept = (node.flags & HuffmanDecode::ACCEPT); + + x = c & 0xf; + } + } + + return accept; + } + + static void packInteger(std::vector &dest, uint64_t num, const uint8_t prefix) + { + uint64_t k = (1 << prefix) - 1; + + if (num < k) + { + dest.emplace_back(num); + return; + } + + dest.emplace_back(k); + + num -= k; + + for (;;) + { + if (num < 128) + { + dest.emplace_back(num); + break; + } + + dest.emplace_back(0x80 | (num & 0x7f) ); + + num >>= 7; + + if (0 == num) + { + break; + } + } + } + + static void packIndex(std::vector &dest, const size_t index) + { + const size_t head = dest.size(); + + packInteger(dest, index, 7); + + dest[head] |= 0x80; + } + + static std::tuple findHeaderInTable(const std::pair &header, const Http2::DynamicTable &dynamicTable) + { + std::tuple result { + 0, false + }; + + size_t &index = std::get(result); + bool &is_full_match = std::get(result); + + for (size_t i = 0; i < getStaticTableSize(); ++i) + { + auto const &pair = staticTable[i]; + + if (pair.first == header.first) + { + index = i + 1; + + if (pair.second == header.second) + { + is_full_match = true; + + return result; + } + } + else if (0 != index) + { + break; + } + } + + for (size_t i = 0; i < dynamicTable.size(); ++i) + { + auto const &pair = dynamicTable[i]; + + if (pair.first == header.first) + { + index = i + getStaticTableSize() + 1; + + if (pair.second == header.second) + { + is_full_match = true; + + break; + } + } + } + + return result; + } + + static uint8_t packFirstByte(const bool indexing) noexcept + { + if (indexing) + { + return 0x40; + } + + /* if (never_indexing) + { + return 0x10; + }*/ + + return 0; + } + + static void packString(std::vector &dest, const std::string &str) + { + const size_t huffman_length = huffmanEncodeLength(str.data(), str.length() ); + + if (huffman_length < str.length() ) + { + const size_t head = dest.size(); + + packInteger(dest, huffman_length, 7); + encode(dest, str.data(), str.length() ); + + dest[head] |= 0x80; + } + else + { + packInteger(dest, str.length(), 7); + std::copy(str.cbegin(), str.cend(), std::back_inserter(dest) ); + } + } + + static void packFullHeader(std::vector &dest, const std::pair &header, const bool indexing) + { + dest.emplace_back(packFirstByte(indexing) ); + packString(dest, header.first); + packString(dest, header.second); + } + + static void packHeaderValue(std::vector &dest, const size_t keyIndex, const std::pair &header, const bool indexing) + { + const size_t head = dest.size(); + + const uint8_t prefix = indexing ? 6 : 4; + + packInteger(dest, keyIndex, prefix); + + dest[head] |= packFirstByte(indexing); + + packString(dest, header.second); + } + + static bool shouldIndexing(const std::pair &header) + { + /* const std::string &key = header.first; + + if ("content-length" == key || "set-cookie" == key) + { + return true; + }*/ + + return false; + } + + static void packHeader(std::vector &dest, const std::pair &header, Http2::DynamicTable &dynamicTable) + { + size_t index; + bool is_full_match; + + std::tie(index, is_full_match) = findHeaderInTable(header, dynamicTable); + + if (is_full_match) + { + packIndex(dest, index); + + return; + } + + const bool indexing = shouldIndexing(header); + + if (indexing) + { + dynamicTable.addHeader(header); + } + + if (0 == index) + { + packFullHeader(dest, header, indexing); + } + else + { + packHeaderValue(dest, index, header, indexing); + } + } +/* + static void packTableSize(std::vector &dest, const size_t tableSize) + { + const size_t head = dest.size(); + + packInteger(dest, tableSize, 5); + + dest[head] |= 0x20; + } +*/ + void pack(std::vector &dest, const std::vector > &headers, Http2::DynamicTable &dynamicTable) + { + for (auto const &header : headers) + { + packHeader(dest, header, dynamicTable); + } + } + + enum class HuffmanDecodeOpcode + { + NONE, + INDEXED, + NOT_INDEXED, + INDEXED_KEY, + }; + + enum class HuffmanDecodeState + { + OPCODE, + READ_TABLE_SIZE, + READ_INDEX, + CHECK_KEY_LENGTH, + READ_KEY_LENGTH, + READ_KEY_HUFFMAN, + READ_KEY, + CHECK_VALUE_LENGTH, + READ_VALUE_LENGTH, + READ_VALUE_HUFFMAN, + READ_VALUE, + }; + + static size_t getMaxTableIndex(const Http2::IncStream &stream) noexcept + { + return getStaticTableSize() + stream.conn.decoding_dynamic_table.size(); + } + + static const std::pair *getHeaderFromTable(const size_t index, const Http2::IncStream &stream) noexcept + { + if (getStaticTableSize() >= index) + { + return &staticTable[index - 1]; + } + else if (stream.conn.decoding_dynamic_table.size() + getStaticTableSize() >= index) + { + return &stream.conn.decoding_dynamic_table[index - getStaticTableSize() - 1]; + } + + return nullptr; + } + + static const std::pair *unpackIndexed(const size_t index, const Http2::IncStream &stream) noexcept + { + return getHeaderFromTable(index, stream); + } + + static bool checkHuffmanEncoded(const uint8_t c) noexcept + { + return c & (1 << 7); + } + + static std::tuple unpackHuffman(std::vector &dest, const uint8_t *data, const size_t dataSize, const uint64_t left) + { + std::tuple result { + left, false + }; + + if (dataSize < left) + { + std::get(result) = dataSize; + } + + std::get(result) = decode(dest, data, std::get(result) ); + + return result; + } + + static uint64_t unpackString(std::vector &dest, const uint8_t *data, const size_t dataSize, uint64_t left) + { + if (dataSize < left) + { + left = dataSize; + } + + std::copy(data, data + left, std::back_inserter(dest) ); + + return left; + } + + static std::tuple unpackInteger(const uint8_t *data, const size_t dataSize, const uint64_t initial, const uint8_t initialShift, const uint8_t prefix) + { + std::tuple result { + initial, 0, initialShift, true + }; + + uint64_t &num = std::get<0>(result); + uint64_t &nread = std::get<1>(result); + uint8_t &shift = std::get(result); + + uint8_t k = (1 << prefix) - 1; + + if (0 == num) + { + const uint8_t c = data[0]; + + ++nread; + + if (k != (c & k) ) + { + num = c & k; + + return result; + } + + num = k; + + if (nread == dataSize) + { + return result; + } + } + + for (; nread < dataSize; ++nread) + { + const uint8_t c = data[nread]; + + uint32_t add = c & 0x7f; + + if (add > (std::numeric_limits::max() >> shift) ) + { + std::get(result) = false; + + return result; + } + + add <<= shift; + + if (std::numeric_limits::max() - add < num) + { + std::get(result) = false; + + return result; + } + + num += add; + + if (0 == (c & (1 << 7) ) ) + { + break; + } + + shift += 7; + } + + if (nread != dataSize) + { + ++nread; + } + + return result; + } + + class HuffmanDecoder + { + public: + std::vector buf; + + size_t key_index = 0; + size_t key_length = 0; + + HuffmanDecodeOpcode opcode = HuffmanDecodeOpcode::NONE; + HuffmanDecodeState state = HuffmanDecodeState::OPCODE; + + uint64_t left = 0; + uint8_t shift = 0; + + bool index_required = false; + bool never_indexed = false; + bool huffman_encoded = false; + + public: + std::pair unpackFullHeader(Http2::IncStream &stream) + { + std::pair header { + std::string(this->buf.cbegin(), this->buf.cbegin() + this->key_length), + std::string(this->buf.cbegin() + this->key_length, this->buf.cend() ) + }; + + this->buf.clear(); + + if (this->index_required) + { + stream.conn.decoding_dynamic_table.addHeader(header); + } + + return header; + } + + std::pair unpackHeaderValue(Http2::IncStream &stream) + { + auto entry = getHeaderFromTable(this->key_index, stream); + + if (nullptr == entry) + { + return std::pair(); + } + + std::pair header { + entry->first, + std::string(this->buf.cbegin(), this->buf.cend() ) + }; + + this->key_index = 0; + this->buf.clear(); + + if (this->index_required) + { + stream.conn.decoding_dynamic_table.addHeader(header); + } + + return header; + } + }; + + bool unpack(const void *src, const size_t srcSize, Http2::IncStream &stream) + { + const uint8_t *data = reinterpret_cast(src); + + size_t cur = 0; + + HuffmanDecoder dec; + + while (cur < srcSize) + { + switch (dec.state) + { + case HuffmanDecodeState::OPCODE: + { + const uint8_t c = data[cur]; + + if (0x20 == (c & 0xe0) ) + { + dec.opcode = HuffmanDecodeOpcode::INDEXED; + dec.state = HuffmanDecodeState::READ_TABLE_SIZE; + } + else if (c & 0x80) + { + dec.opcode = HuffmanDecodeOpcode::INDEXED; + dec.state = HuffmanDecodeState::READ_INDEX; + } + else + { + if (0 == c || 0x40 == c || 0x10 == c) + { + dec.opcode = HuffmanDecodeOpcode::NOT_INDEXED; + dec.state = HuffmanDecodeState::CHECK_KEY_LENGTH; + + ++cur; + } + else + { + dec.opcode = HuffmanDecodeOpcode::INDEXED_KEY; + dec.state = HuffmanDecodeState::READ_INDEX; + } + + dec.index_required = (c & 0x40); + dec.never_indexed = (c & 0xf0) == 0x10; + } + + dec.left = dec.shift = 0; + + break; + } + + case HuffmanDecodeState::READ_TABLE_SIZE: + { + uint64_t nread; + bool success; + + std::tie(dec.left, nread, dec.shift, success) = unpackInteger(data + cur, srcSize - cur, dec.left, dec.shift, 5); + + cur += nread; + + if (false == success) + { + return false; + } + + if (dec.left > stream.conn.client_settings.header_table_size) + { + // TODO: invalid max table size error code + return false; + } + + stream.conn.decoding_dynamic_table.changeHeaderTableSize(dec.left); + + dec.state = HuffmanDecodeState::OPCODE; + + break; + } + + case HuffmanDecodeState::READ_INDEX: + { + uint8_t prefixlen; + + if (HuffmanDecodeOpcode::INDEXED == dec.opcode) + { + prefixlen = 7; + } + else if (dec.index_required) + { + prefixlen = 6; + } + else + { + prefixlen = 4; + } + + uint64_t nread; + bool success; + + std::tie(dec.left, nread, dec.shift, success) = unpackInteger(data + cur, srcSize - cur, dec.left, dec.shift, prefixlen); + + cur += nread; + + if (false == success || 0 == dec.left || dec.left > getMaxTableIndex(stream) ) + { + return false; + } + + if (HuffmanDecodeOpcode::INDEXED == dec.opcode) + { + stream.incoming_headers.emplace(*unpackIndexed(dec.left, stream) ); + + dec.state = HuffmanDecodeState::OPCODE; + } + else + { + dec.key_index = dec.left; + + dec.state = HuffmanDecodeState::CHECK_VALUE_LENGTH; + } + + break; + } + + case HuffmanDecodeState::CHECK_KEY_LENGTH: + { + dec.huffman_encoded = checkHuffmanEncoded(data[cur]); + dec.state = HuffmanDecodeState::READ_KEY_LENGTH; + dec.left = dec.shift = 0; + break; + } + + case HuffmanDecodeState::READ_KEY_LENGTH: + { + uint64_t nread; + bool success; + + std::tie(dec.left, nread, dec.shift, success) = unpackInteger(data + cur, srcSize - cur, dec.left, dec.shift, 7); + + cur += nread; + + if (false == success) + { + return false; + } + + dec.state = dec.huffman_encoded ? + HuffmanDecodeState::READ_KEY_HUFFMAN : + HuffmanDecodeState::READ_KEY; + + break; + } + + case HuffmanDecodeState::READ_KEY_HUFFMAN: + { + uint64_t nread; + bool success; + + std::tie(nread, success) = unpackHuffman(dec.buf, data + cur, srcSize - cur, dec.left); + + cur += nread; + dec.left -= nread; + + if (false == success || dec.left > 0) + { + return false; + } + + dec.key_length = dec.buf.size(); + + dec.state = HuffmanDecodeState::CHECK_VALUE_LENGTH; + + break; + } + + case HuffmanDecodeState::READ_KEY: + { + const uint64_t nread = unpackString(dec.buf, data + cur, srcSize - cur, dec.left); + + cur += nread; + dec.left -= nread; + + if (dec.left > 0) + { + return false; + } + + dec.key_length = dec.buf.size(); + + dec.state = HuffmanDecodeState::CHECK_VALUE_LENGTH; + + break; + } + + case HuffmanDecodeState::CHECK_VALUE_LENGTH: + { + dec.huffman_encoded = checkHuffmanEncoded(data[cur]); + dec.state = HuffmanDecodeState::READ_VALUE_LENGTH; + dec.left = dec.shift = 0; + break; + } + + case HuffmanDecodeState::READ_VALUE_LENGTH: + { + uint64_t nread; + bool success; + + std::tie(dec.left, nread, dec.shift, success) = unpackInteger(data + cur, srcSize - cur, dec.left, dec.shift, 7); + + cur += nread; + + if (false == success) + { + return false; + } + + if (0 == dec.left) + { + HuffmanDecodeOpcode::NOT_INDEXED == dec.opcode ? + stream.incoming_headers.emplace(dec.unpackFullHeader(stream) ) : + stream.incoming_headers.emplace(dec.unpackHeaderValue(stream) ); + + dec.state = HuffmanDecodeState::OPCODE; + + break; + } + + dec.state = dec.huffman_encoded ? + HuffmanDecodeState::READ_VALUE_HUFFMAN : + HuffmanDecodeState::READ_VALUE; + + break; + } + + case HuffmanDecodeState::READ_VALUE_HUFFMAN: + { + uint64_t nread; + bool success; + + std::tie(nread, success) = unpackHuffman(dec.buf, data + cur, srcSize - cur, dec.left); + + cur += nread; + dec.left -= nread; + + if (false == success || dec.left > 0) + { + return false; + } + + HuffmanDecodeOpcode::NOT_INDEXED == dec.opcode ? + stream.incoming_headers.emplace(dec.unpackFullHeader(stream) ) : + stream.incoming_headers.emplace(dec.unpackHeaderValue(stream) ); + + dec.state = HuffmanDecodeState::OPCODE; + + break; + } + + case HuffmanDecodeState::READ_VALUE: + { + const uint64_t nread = unpackString(dec.buf, data + cur, srcSize - cur, dec.left); + + cur += nread; + dec.left -= nread; + + if (dec.left > 0) + { + return false; + } + + HuffmanDecodeOpcode::NOT_INDEXED == dec.opcode ? + stream.incoming_headers.emplace(dec.unpackFullHeader(stream) ) : + stream.incoming_headers.emplace(dec.unpackHeaderValue(stream) ); + + dec.state = HuffmanDecodeState::OPCODE; + + break; + } + } + } + + return true; + } +}; diff --git a/src/transfer/http2/HPack.h b/src/transfer/http2/HPack.h new file mode 100644 index 0000000..d71375c --- /dev/null +++ b/src/transfer/http2/HPack.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Http2.h" + +#include +#include +#include + +namespace HPack +{ + void pack(std::vector &dest, const std::vector > &headers, Http2::DynamicTable &dynamicTable); + + // TODO: replace IncStream to DynamicTable if possible + bool unpack(const void *src, const size_t srcSize, Http2::IncStream &stream); +}; diff --git a/src/transfer/http2/Http2.cpp b/src/transfer/http2/Http2.cpp new file mode 100644 index 0000000..208eb79 --- /dev/null +++ b/src/transfer/http2/Http2.cpp @@ -0,0 +1,182 @@ + +#include "Http2.h" +#include "../../utils/Utils.h" + +namespace Http2 +{ + bool operator &(const FrameFlag left, const FrameFlag right) noexcept + { + return static_cast(left) & static_cast(right); + } + + FrameFlag operator |(const FrameFlag left, const FrameFlag right) noexcept + { + return static_cast(static_cast(left) | static_cast(right) ); + } + + FrameFlag operator |=(FrameFlag &left, const FrameFlag right) noexcept + { + return static_cast(*reinterpret_cast(&left) |= static_cast(right) ); + } + + ConnectionSettings ConnectionSettings::defaultSettings() noexcept + { + return ConnectionSettings { + 4096, + 1, + 0, + (1 << 16) - 1, // 65535 + 1 << 14, // 16384 + 0 + }; + } + + DynamicTable::DynamicTable() noexcept + : header_table_size(0), max_header_list_size(0), cur_header_list_size(0) + { + + } + + size_t DynamicTable::size() const noexcept + { + return this->list.size(); + } + + DynamicTable::DynamicTable(const uint32_t headerTableSize, const uint32_t maxHeaderListSize, std::deque > &&list) noexcept + : list(std::move(list) ), header_table_size(headerTableSize), max_header_list_size(maxHeaderListSize), cur_header_list_size(0) + { + for (auto const &pair : list) + { + this->cur_header_list_size += pair.first.length() + pair.second.length(); + } + } + + void DynamicTable::addHeader(const std::pair &header) + { + this->cur_header_list_size += header.first.length() + header.second.length(); + + this->list.emplace_front(header); + + while (this->list.size() > this->header_table_size || (0 != this->max_header_list_size && this->cur_header_list_size > this->max_header_list_size) ) + { + auto const &pair = this->list.back(); + + this->cur_header_list_size -= pair.first.length() + pair.second.length(); + + this->list.pop_back(); + } + } + + void DynamicTable::addHeader(std::pair &&header) + { + this->cur_header_list_size += header.first.length() + header.second.length(); + + this->list.emplace_front(std::move(header) ); + + while (this->list.size() > this->header_table_size || (0 != this->max_header_list_size && this->cur_header_list_size > this->max_header_list_size) ) + { + auto const &pair = this->list.back(); + + this->cur_header_list_size -= pair.first.length() + pair.second.length(); + + this->list.pop_back(); + } + } + + void DynamicTable::changeHeaderTableSize(const uint32_t headerTableSize) + { + this->header_table_size = headerTableSize; + + while (this->list.size() > this->header_table_size) + { + auto const &pair = this->list.back(); + + this->cur_header_list_size -= pair.first.length() + pair.second.length(); + + this->list.pop_back(); + } + } + + void DynamicTable::changeMaxHeaderListSize(const uint32_t maxHeaderListSize) + { + this->max_header_list_size = maxHeaderListSize; + + while (0 != this->max_header_list_size && this->cur_header_list_size > this->max_header_list_size) + { + auto const &pair = this->list.back(); + + this->cur_header_list_size -= pair.first.length() + pair.second.length(); + + this->list.pop_back(); + } + } + + const std::pair &DynamicTable::operator[](const size_t index) const noexcept + { + return this->list[index]; + } + + std::pair &DynamicTable::operator[](const size_t index) noexcept + { + return this->list[index]; + } + + const std::deque > &DynamicTable::getList() const noexcept + { + return this->list; + } + + IncStream::IncStream(const uint32_t streamId, ConnectionData &conn) noexcept + : conn(conn), window_size_inc(conn.server_settings.initial_window_size), + window_size_out(conn.client_settings.initial_window_size), stream_id(streamId), + state(StreamState::IDLE), priority(0), reserved(nullptr) + { + + } + + uint8_t *IncStream::setHttp2FrameHeader(uint8_t *addr, const uint32_t frameSize, const Http2::FrameType frameType, const Http2::FrameFlag frameFlags) noexcept + { + Utils::hton24(addr, frameSize); + *(addr + 3) = static_cast(frameType); + *(addr + 4) = static_cast(frameFlags); + *reinterpret_cast(addr + 5) = ::htonl(this->stream_id); + + return (addr + Http2::FRAME_HEADER_SIZE); + } + + void IncStream::close() noexcept + { + this->incoming_headers.clear(); + this->incoming_data.clear(); + this->incoming_files.clear(); + this->reserved = nullptr; + + ++this->conn.sync.completed; + this->conn.sync.event.notify(); + + // this->state = StreamState::CLOSED; + } + + OutStream::OutStream(const uint32_t streamId, const ConnectionSettings &settings, DynamicTable &&dynamic_table) noexcept + : stream_id(streamId), settings(settings), window_size_out(settings.initial_window_size), dynamic_table(std::move(dynamic_table) ) + { + + } + + OutStream::OutStream(const IncStream &stream) noexcept + : stream_id(stream.stream_id), settings(stream.conn.client_settings), + window_size_out(stream.window_size_out), dynamic_table(stream.conn.encoding_dynamic_table) + { + + } + + uint8_t *OutStream::setHttp2FrameHeader(uint8_t *addr, const uint32_t frameSize, const Http2::FrameType frameType, const Http2::FrameFlag frameFlags) noexcept + { + Utils::hton24(addr, frameSize); + *(addr + 3) = static_cast(frameType); + *(addr + 4) = static_cast(frameFlags); + *reinterpret_cast(addr + 5) = ::htonl(this->stream_id); + + return (addr + Http2::FRAME_HEADER_SIZE); + } +}; diff --git a/src/transfer/http2/Http2.h b/src/transfer/http2/Http2.h new file mode 100644 index 0000000..a754b38 --- /dev/null +++ b/src/transfer/http2/Http2.h @@ -0,0 +1,191 @@ +#pragma once + +#include "../../utils/Event.h" +#include "../AppRequest.h" + +#include +#include +#include +#include +#include + +#include + +namespace Http2 +{ + enum class ErrorCode : uint32_t + { + NO_ERROR = 0x0, + PROTOCOL_ERROR, + INTERNAL_ERROR, + FLOW_CONTROL_ERROR, + SETTINGS_TIMEOUT, + STREAM_CLOSED, + FRAME_SIZE_ERROR, + REFUSED_STREAM, + CANCEL, + COMPRESSION_ERROR, + CONNECT_ERROR, + ENHANCE_YOUR_CALM, + INADEQUATE_SECURITY, + HTTP_1_1_REQUIRED + }; + + enum class FrameType : uint8_t + { + DATA = 0x0, + HEADERS, + PRIORITY, + RST_STREAM, + SETTINGS, + PUSH_PROMISE, + PING, + GOAWAY, + WINDOW_UPDATE, + CONTINUATION + }; + + enum class FrameFlag : uint8_t + { + EMPTY = 0x0, + ACK = 0x1, + END_STREAM = 0x1, + END_HEADERS = 0x4, + PADDED = 0x8, + PRIORITY = 0x20 + }; + + bool operator &(const FrameFlag left, const FrameFlag right) noexcept; + FrameFlag operator |(const FrameFlag left, const FrameFlag right) noexcept; + FrameFlag operator |=(FrameFlag &left, const FrameFlag right) noexcept; + + struct FrameMeta + { + uint32_t stream_id; + uint32_t length; + FrameType type; + FrameFlag flags; + }; + + constexpr uint32_t FRAME_HEADER_SIZE = 9; + constexpr uint32_t MAX_WINDOW_UPDATE = uint32_t(1 << 31) - 1; + + enum class ConnectionSetting : uint16_t + { + SETTINGS_HEADER_TABLE_SIZE = 0x1, + SETTINGS_ENABLE_PUSH = 0x2, + SETTINGS_MAX_CONCURRENT_STREAMS = 0x3, + SETTINGS_INITIAL_WINDOW_SIZE = 0x4, + SETTINGS_MAX_FRAME_SIZE = 0x5, + SETTINGS_MAX_HEADER_LIST_SIZE = 0x6 + }; + + struct ConnectionSettings + { + uint32_t header_table_size; + uint32_t enable_push; + uint32_t max_concurrent_streams; + uint32_t initial_window_size; + uint32_t max_frame_size; + uint32_t max_header_list_size; + + static ConnectionSettings defaultSettings() noexcept; + }; + + enum class StreamState : uint8_t + { + IDLE, + RESERVED, + OPEN, + HALF_CLOSED, + CLOSED + }; + + struct ConnectionSync + { + Utils::Event event; + std::mutex mtx; + std::atomic completed {}; + }; + + class DynamicTable + { + private: + std::deque > list; + + uint32_t header_table_size; + uint32_t max_header_list_size; + + uint32_t cur_header_list_size; + + public: + DynamicTable() noexcept; + DynamicTable(const uint32_t headerTableSize, const uint32_t maxHeaderListSize, std::deque > &&list) noexcept; + + size_t size() const noexcept; + + void addHeader(const std::pair &header); + void addHeader(std::pair &&header); + + void changeHeaderTableSize(const uint32_t headerTableSize); + void changeMaxHeaderListSize(const uint32_t maxHeaderListSize); + + const std::pair &operator[](const size_t index) const noexcept; + std::pair &operator[](const size_t index) noexcept; + + const std::deque > &getList() const noexcept; + }; + + struct ConnectionData + { + DynamicTable decoding_dynamic_table; + DynamicTable encoding_dynamic_table; + + ConnectionSettings client_settings; + ConnectionSettings server_settings; + + ConnectionSync sync; + }; + + class IncStream : public Transfer::request_data + { + public: + ConnectionData &conn; + + int32_t window_size_inc; + int32_t window_size_out; + + uint32_t stream_id; + + StreamState state; + uint8_t priority; + + FrameType frame_type; + + void *reserved; + + public: + IncStream(const uint32_t streamId, ConnectionData &conn) noexcept; + + uint8_t *setHttp2FrameHeader(uint8_t *addr, const uint32_t frameSize, const Http2::FrameType frameType, const Http2::FrameFlag frameFlags) noexcept; + + void close() noexcept; + }; + + struct OutStream + { + uint32_t stream_id; + + ConnectionSettings settings; + + int32_t window_size_out; + + DynamicTable dynamic_table; + + public: + OutStream(const uint32_t streamId, const ConnectionSettings &settings, DynamicTable &&dynamic_table) noexcept; + OutStream(const IncStream &stream) noexcept; + + uint8_t *setHttp2FrameHeader(uint8_t *addr, const uint32_t frameSize, const Http2::FrameType frameType, const Http2::FrameFlag frameFlags) noexcept; + }; +}; diff --git a/src/utils/Event.cpp b/src/utils/Event.cpp new file mode 100644 index 0000000..6b23628 --- /dev/null +++ b/src/utils/Event.cpp @@ -0,0 +1,102 @@ + +#include "Event.h" + +namespace Utils +{ + Event::Event(const bool signaled, const bool manually) noexcept + : signaled(signaled), manually(manually) + { + + } + + void Event::wait() + { + if (false == this->signaled.load() ) + { + std::unique_lock lck(this->mtx); + + do + { + this->cv.wait(lck); + } + while (false == this->signaled.load() ); + } + + if (false == this->manually) + { + this->signaled.store(false); + } + } + + bool Event::wait_for(const std::chrono::milliseconds &ms) + { + bool is_timeout = false; + + if (false == this->signaled.load() ) + { + std::unique_lock lck(this->mtx); + + is_timeout = false == this->cv.wait_for(lck, ms, [this] { return this->notifed(); } ); + } + + if (false == this->manually) + { + this->signaled.store(false); + } + + return is_timeout; + } + + bool Event::wait_until(const std::chrono::high_resolution_clock::time_point &tp) + { + bool is_timeout = false; + + if (false == this->signaled.load() ) + { + std::unique_lock lck(this->mtx); + + do + { + if (std::cv_status::timeout == this->cv.wait_until(lck, tp) ) + { + is_timeout = true; + break; + } + } + while (false == this->signaled.load() ); + } + + if (false == this->manually) + { + this->signaled.store(false); + } + + return is_timeout; + } + + void Event::notify() noexcept + { + this->signaled.store(true); + this->cv.notify_all(); + } + + void Event::notify(const size_t threadsCount) noexcept + { + this->signaled.store(true); + + for (size_t i = 0; i < threadsCount; ++i) + { + this->cv.notify_one(); + } + } + + void Event::reset() noexcept + { + this->signaled.store(false); + } + + bool Event::notifed() const noexcept + { + return this->signaled.load(); + } +}; diff --git a/src/utils/Event.h b/src/utils/Event.h new file mode 100644 index 0000000..ddacbe4 --- /dev/null +++ b/src/utils/Event.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +namespace Utils +{ + class Event + { + private: + std::mutex mtx; + std::condition_variable cv; + std::atomic signaled; + bool manually; + + public: + Event(const bool signaled = false, const bool manualy = false) noexcept; + ~Event() noexcept = default; + + public: + void wait(); + bool wait_for(const std::chrono::milliseconds &ms); + bool wait_until(const std::chrono::high_resolution_clock::time_point &tp); + + void notify() noexcept; + void notify(const size_t threadsCount) noexcept; + + void reset() noexcept; + + bool notifed() const noexcept; + }; +}; diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp new file mode 100644 index 0000000..dc06e23 --- /dev/null +++ b/src/utils/Utils.cpp @@ -0,0 +1,841 @@ + +#include "Utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Utils +{ + void toLower(std::string &str) noexcept + { + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + } + + std::string getLowerString(const std::string &str) + { + std::string copy = str; + + toLower(copy); + + return copy; + } + + void trim(std::string &str) + { + static const std::array whitespace { " \t\n\v\f\r" }; + + const size_t last = str.find_last_not_of(whitespace.data() ); + + if (std::string::npos == last) + { + return str.clear(); + } + + str.assign(str.cbegin() + str.find_first_not_of(whitespace.data() ), str.cbegin() + last + 1); + } + + std::string getTrimmedString(const std::string &str) + { + std::string copy = str; + + trim(copy); + + return copy; + } + + std::vector explode(const std::string &str, const char sep) + { + std::vector values; + + for (size_t pos = 0; std::string::npos != pos;) + { + size_t delimiter = str.find(sep, pos); + + std::string value = str.substr(pos, delimiter); + trim(value); + + values.emplace_back(std::move(value) ); + + pos = delimiter; + + if (std::string::npos != pos) + { + ++pos; + } + } + + return values; + } + + std::string encodeHtmlSymbols(const std::string &str) + { + std::string buf; + buf.reserve(str.length() ); + + for (size_t pos = 0; pos < str.length(); ++pos) + { + switch (str[pos]) + { + case '&': buf.append("&"); break; + case '\"': buf.append("""); break; + case '\'': buf.append("'"); break; + case '<': buf.append("<"); break; + case '>': buf.append(">"); break; + default: buf.push_back(str[pos]); break; + } + } + + return buf; + } + + std::string binToHexString(const void *binData, const size_t dataSize) + { + std::string str(dataSize * 2, 0); + + const uint8_t *bin = reinterpret_cast(binData); + + static const std::array hexDigits { "0123456789abcdef" }; + + for (size_t i = dataSize - 1; std::numeric_limits::max() != i; --i) + { + str[i * 2 + 0] = hexDigits[bin[i] >> 4]; + str[i * 2 + 1] = hexDigits[bin[i] & 0x0F]; + } + + return str; + } + + static unsigned char hexStringToBinEncodeSymbol(const char c) noexcept + { + if (c >= '0' && c <= '9') + { + return c - 0x30; + } + else if (c >= 'a' && c <= 'f') + { + return c - 0x57; + } + else if (c >= 'A' && c <= 'F') + { + return c - 0x37; + } + + return 0; + } + + std::string hexStringToBin(const std::string &hexStr) + { + std::string bin(hexStr.length() / 2, 0); + + for (size_t i = 0; i < bin.length(); ++i) + { + const char a = hexStr[i * 2 + 0]; + const char b = hexStr[i * 2 + 1]; + + bin[i] = ( + (hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b) + ); + } + + return bin; + } + + enum Endianness { + INIT = 0, + LITE = 1, + BIGE = 2 + }; + + uint64_t hton64(const uint64_t host64) noexcept + { + static Endianness endian = Endianness::INIT; + + union { + uint64_t ull; + unsigned char c[sizeof(uint64_t)]; + } x; + + if (endian == Endianness::INIT) + { + x.ull = 0x01; + endian = (x.c[7] == 0x01ULL) ? Endianness::BIGE : Endianness::LITE; + } + + if (endian == Endianness::BIGE) + { + return host64; + } + + x.ull = host64; + + unsigned char c; + + c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c; + c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c; + c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c; + c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c; + + return x.ull; + } + + uint64_t ntoh64(const uint64_t net64) noexcept + { + return hton64(net64); + } + + void hton24(void *dest, const uint32_t src) noexcept + { + static Endianness endian = Endianness::INIT; + + union { + uint32_t ui; + uint8_t c[sizeof(uint32_t)]; + } x; + + if (endian == Endianness::INIT) + { + x.ui = 0x01; + endian = (x.c[3] == 0x01) ? Endianness::BIGE : Endianness::LITE; + } + + x.ui = src; + + if (endian == Endianness::BIGE) + { + x.ui <<= 8; + } + else + { + uint8_t c = x.c[0]; + x.c[0] = x.c[2]; + x.c[2] = c; + } + + std::copy(x.c, x.c + 3, reinterpret_cast(dest) ); + } + + uint32_t ntoh24(const void *src24) noexcept + { + static Endianness endian = Endianness::INIT; + + union { + uint32_t ui; + uint8_t c[sizeof(uint32_t)]; + } x; + + if (endian == Endianness::INIT) + { + x.ui = 0x01; + endian = (x.c[3] == 0x01) ? Endianness::BIGE : Endianness::LITE; + } + + if (endian == Endianness::BIGE) + { + return *reinterpret_cast(src24) >> 8; + } + + const uint8_t *addr = reinterpret_cast(src24); + + x.ui = 0; + + x.c[0] = addr[2]; + x.c[1] = addr[1]; + x.c[2] = addr[0]; + + return x.ui;// *reinterpret_cast(x.c); + } + + std::string getUniqueName() + { + size_t time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + + time = hton64(time); + + return binToHexString(&time, sizeof(time) ); + } + + size_t getPackNumberSize(const size_t number) noexcept + { + if (number <= 253) + { + return sizeof(uint8_t); + } + else if (number <= std::numeric_limits::max() ) + { + return sizeof(uint8_t) + sizeof(uint16_t); + } + else if (number <= std::numeric_limits::max() ) + { + return sizeof(uint8_t) + sizeof(uint32_t); + } + + return sizeof(uint8_t) + sizeof(size_t); + } + + size_t getPackStringSize(const std::string &str) noexcept + { + return getPackNumberSize(str.length() ) + str.length(); + } + + uint8_t *packNumber(uint8_t *dest, const size_t number) noexcept + { + if (number <= 252) + { + *dest = number; + + dest += sizeof(uint8_t); + } + else if (number <= std::numeric_limits::max() ) + { + *dest = 253; + + dest += sizeof(uint8_t); + + *reinterpret_cast(dest) = static_cast(number); + + dest += sizeof(uint16_t); + } + else if (number <= std::numeric_limits::max() ) + { + *dest = 254; + + dest += sizeof(uint8_t); + + *reinterpret_cast(dest) = static_cast(number); + + dest += sizeof(uint32_t); + } + else + { + *dest = 255; + + dest += sizeof(uint8_t); + + *reinterpret_cast(dest) = number; + + dest += sizeof(size_t); + } + + return dest; + } + + uint8_t *packString(uint8_t *dest, const std::string &str) noexcept + { + dest = packNumber(dest, str.length() ); + + std::memcpy(dest, str.data(), str.length() ); + + return dest + str.length(); + } + + void packNumber(std::vector &buf, const size_t number) + { + if (number <= 252) + { + buf.emplace_back(number); + } + else if (number <= std::numeric_limits::max() ) + { + buf.emplace_back(253); + + buf.resize(buf.size() + sizeof(uint16_t) ); + + *reinterpret_cast(buf.data() + buf.size() - sizeof(uint16_t) ) = static_cast(number); + } + else if (number <= std::numeric_limits::max() ) + { + buf.emplace_back(254); + + buf.resize(buf.size() + sizeof(uint32_t) ); + + *reinterpret_cast(buf.data() + buf.size() - sizeof(uint32_t) ) = static_cast(number); + } + else + { + buf.emplace_back(255); + + buf.resize(buf.size() + sizeof(size_t) ); + + *reinterpret_cast(buf.data() + buf.size() - sizeof(size_t) ) = number; + } + } + + void packString(std::vector &buf, const std::string &str) + { + packNumber(buf, str.length() ); + + if (str.length() ) + { + std::copy(str.cbegin(), str.cend(), std::back_inserter(buf) ); + } + } + + const uint8_t *unpackNumber(size_t *number, const uint8_t *src) noexcept + { + *number = *src; + + src += sizeof(uint8_t); + + if (*number <= 252) + { + + } + else if (*number == 253) + { + *number = *reinterpret_cast(src); + + src += sizeof(uint16_t); + } + else if (*number == 254) + { + *number = *reinterpret_cast(src); + + src += sizeof(uint32_t); + } + else + { + *number = *reinterpret_cast(src); + + src += sizeof(size_t); + } + + return src; + } + + const uint8_t *unpackString(std::string &str, const uint8_t *src) + { + size_t length; + src = unpackNumber(&length, src); + + str.assign(src, src + length); + + return src + length; + } + + static const std::unordered_map map_days { + {"Mon", 0}, {"Tue", 1}, {"Wed", 2}, {"Thu", 3}, {"Fri", 4}, {"Sat", 5}, {"Sun", 6} + }; + + static const std::unordered_map map_months { + {"Jan", 0}, {"Feb", 1}, {"Mar", 2}, {"Apr", 3}, {"May", 4}, {"Jun", 5}, {"Jul", 6}, {"Aug", 7}, {"Sep", 8}, {"Oct", 9}, {"Nov", 10}, {"Dec", 11} + }; + + static const std::unordered_map map_zones { + {"GMT", 0}, {"UT", 0}, + {"EST", -5 * 3600}, {"EDT", -4 * 3600}, {"CST", -6 * 3600}, {"CDT", -5 * 3600}, {"MST", -7 * 3600}, {"MDT", -6 * 3600}, {"PST", -8 * 3600}, {"PDT", -7 * 3600}, + {"Z", 0}, {"A", -1 * 3600}, {"M", -12 * 3600}, {"N", 1 * 3600}, {"Y", 12 * 3600} + }; + + /** + * Parse RFC 882 (ddd, dd MMM yyyy HH:mm:ss K) + */ + time_t rfc822DatetimeToTimestamp(const std::string &strTime) + { + std::tm tc = {}; + + // Parse RFC 882 (ddd, dd MMM yyyy HH:mm:ss K) + + size_t pos = strTime.find_first_not_of(' '); + size_t delimiter = strTime.find(',', pos); + + if (std::string::npos == delimiter || delimiter - pos != 3) + { + return ~0; + } + + const std::string day = strTime.substr(pos, delimiter - pos); + + auto const it_day = map_days.find(day); + + if (map_days.cend() != it_day) + { + tc.tm_wday = it_day->second; + } + else + { + return ~0; + } + + pos = strTime.find_first_not_of(' ', delimiter + 1); + delimiter = strTime.find_first_of(' ', pos); + + if (std::string::npos == delimiter) + { + return ~0; + } + + tc.tm_mday = std::strtoul(strTime.data() + pos, nullptr, 10); + + pos = strTime.find_first_not_of(' ', delimiter + 1); + delimiter = strTime.find_first_of(' ', pos); + + if (std::string::npos == delimiter || delimiter - pos != 3) + { + return ~0; + } + + const std::string month = strTime.substr(pos, delimiter - pos); + + auto const it_mon = map_months.find(month); + + if (map_months.cend() != it_mon) + { + tc.tm_mon = it_mon->second; + } + else + { + return ~0; + } + + pos = strTime.find_first_not_of(' ', delimiter + 1); + delimiter = strTime.find_first_of(' ', pos); + + if (std::string::npos == delimiter) + { + return ~0; + } + + tc.tm_year = std::strtoul(strTime.data() + pos, nullptr, 10) - 1900; + + pos = strTime.find_first_not_of(' ', delimiter + 1); + delimiter = strTime.find_first_of(':', pos); + + if (std::string::npos == delimiter) + { + return ~0; + } + + tc.tm_hour = std::strtoul(strTime.data() + pos, nullptr, 10); + + pos = strTime.find_first_not_of(' ', delimiter + 1); + delimiter = strTime.find_first_of(':', pos); + + if (std::string::npos == delimiter) + { + return ~0; + } + + tc.tm_min = std::strtoul(strTime.data() + pos, nullptr, 10); + + pos = strTime.find_first_not_of(' ', delimiter + 1); + delimiter = strTime.find_first_of(' ', pos); + + if (std::string::npos == delimiter) + { + return ~0; + } + + tc.tm_sec = std::strtoul(strTime.data() + pos, nullptr, 10); + + pos = strTime.find_first_not_of(' ', delimiter + 1); + delimiter = strTime.find_first_of(' ', pos); + + if (std::string::npos == delimiter) + { + delimiter = strTime.length(); + } + + if (std::string::npos == pos || delimiter - pos > 5) + { + return ~0; + } + + const std::string zone = strTime.substr(pos, delimiter - pos); + + auto const it_zone = map_zones.find(zone); + + int timezone = 0; + + if (map_zones.cend() != it_zone) + { + timezone = it_zone->second; + } + else if (zone.length() == 5 && ('+' == zone.front() || '-' == zone.front() ) ) + { + std::array hours; + std::array minutes; + + zone.copy(hours.data(), 2, 1); + zone.copy(minutes.data(), 2, 3); + + timezone = std::strtoul(hours.data(), nullptr, 10) * 3600; + timezone += std::strtoul(minutes.data(), nullptr, 10) * 60; + + if ('-' == zone.front() ) + { + timezone *= -1; + } + } + else + { + return ~0; + } + + tc.tm_isdst = -1; + + return std::mktime(&tc) - timezone; + } + + static time_t localToGmt(const time_t timestamp) + { + #ifdef WIN32 + std::tm stm = {}; + + ::gmtime_s(&stm, ×tamp); + + return std::mktime(&stm); + #else + std::tm stm = {}; + + ::gmtime_r(×tamp, &stm); + + return std::mktime(&stm); + #endif + } + + /** + * Convert c-string (__DATE__ " " __TIME__) to std::time_t + */ + time_t predefinedDatetimeToTimestamp(const char *strTime) + { + std::tm tc = {}; + + const char *ptrStr = std::strchr(strTime, ' '); + + if (nullptr == ptrStr) + { + return ~0; + } + + const std::string month(strTime, ptrStr); + + auto const it_mon = map_months.find(month); + + if (map_months.cend() != it_mon) + { + tc.tm_mon = it_mon->second; + } + else + { + return ~0; + } + + ++ptrStr; + + strTime = std::strchr(ptrStr, ' '); + + if (nullptr == strTime) + { + return ~0; + } + + tc.tm_mday = std::strtoul(ptrStr, nullptr, 10); + + ++strTime; + + ptrStr = std::strchr(strTime, ' '); + + if (nullptr == ptrStr) + { + return ~0; + } + + tc.tm_year = std::strtoul(strTime, nullptr, 10) - 1900; + + ++ptrStr; + + strTime = std::strchr(ptrStr, ':'); + + if (nullptr == strTime) + { + return ~0; + } + + tc.tm_hour = std::strtoul(ptrStr, nullptr, 10); + + ++strTime; + + ptrStr = std::strchr(strTime, ':'); + + if (nullptr == ptrStr) + { + return ~0; + } + + tc.tm_min = std::strtoul(strTime, nullptr, 10); + + ++ptrStr; + + tc.tm_sec = std::strtoul(ptrStr, nullptr, 10); + + return localToGmt(std::mktime(&tc) ); + } + + /** + * Convert std::time_t to RFC822 std::string + */ + std::string getDatetimeAsString(time_t tTime, const bool isGmtTime) + { + std::array buf; + + if (tTime == ~0) + { + std::time(&tTime); + } + + #ifdef WIN32 + std::tm stm = {}; + + isGmtTime ? + ::localtime_s(&stm, &tTime) : + ::gmtime_s(&stm, &tTime); + + // RFC 822 + auto const len = std::strftime(buf.data(), buf.size(), "%a, %d %b %Y %H:%M:%S GMT", &stm); + #else + std::tm stm = {}; + + isGmtTime ? + ::localtime_r(&tTime, &stm) : + ::gmtime_r(&tTime, &stm); + + // RFC 822 + auto const len = std::strftime(buf.data(), buf.size(), "%a, %d %b %G %H:%M:%S GMT", &stm); + #endif + + return std::string(buf.data(), buf.data() + len); + } + + std::string predefinedDatetimeToRfc822(const char *strTime) + { + const std::time_t time = predefinedDatetimeToTimestamp(strTime); + return getDatetimeAsString(time, false); + } + + size_t getNumberLength(size_t number) noexcept + { + size_t length = 0; + + do + { + ++length; + number /= 10; + } + while (number); + + return length; + } + + bool parseCookies(const std::string &cookieHeader, std::unordered_multimap &cookies) + { + if (cookieHeader.empty() ) + { + return true; + } + + for (size_t cur_pos = 0, next_value; std::string::npos != cur_pos; cur_pos = next_value) + { + next_value = cookieHeader.find(';', cur_pos); + + size_t delimiter = cookieHeader.find('=', cur_pos); + + if (std::string::npos == delimiter || delimiter > next_value) + { + return false; + } + + std::string key = cookieHeader.substr(cur_pos, delimiter - cur_pos); + trim(key); + key = urlDecode(key); + + ++delimiter; + + std::string value = cookieHeader.substr(delimiter, std::string::npos != next_value ? next_value - delimiter : next_value); + trim(value); + value = urlDecode(value); + + cookies.emplace(std::move(key), std::move(value) ); + + if (std::string::npos != next_value) + { + ++next_value; + } + } + + return true; + } + + static inline bool isCharUrlAllowed(const char c) noexcept + { + return c == '-' || c == '_' || c == '.' || c == '~'; + } + + std::string urlEncode(const std::string &str) + { + std::string encoded; + + static const std::array hexDigits { "0123456789ABCDEF" }; + + for (size_t i = 0; i < str.length(); ++i) + { + const unsigned char c = str[i]; + + if (std::isalnum(c) || isCharUrlAllowed(c) ) + { + encoded.push_back(c); + } + else if (' ' == c) + { + encoded.push_back('+'); + } + else + { + const uint8_t a = c >> 4; + const uint8_t b = c & 0x0F; + + encoded.push_back('%'); + encoded.push_back(hexDigits[a]); + encoded.push_back(hexDigits[b]); + } + } + + return encoded; + } + + std::string urlDecode(const std::string &str) + { + std::string decoded; + + for (size_t i = 0; i < str.length(); ++i) + { + unsigned char c = str[i]; + + if ('%' == c) + { + if (i + 2 < str.length() ) + { + const char a = str[++i]; + const char b = str[++i]; + + c = ( + (hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b) + ); + } + } + else if ('+' == c) + { + c = ' '; + } + + decoded.push_back(c); + } + + return decoded; + } +}; diff --git a/src/utils/Utils.h b/src/utils/Utils.h new file mode 100644 index 0000000..5137831 --- /dev/null +++ b/src/utils/Utils.h @@ -0,0 +1,137 @@ +#pragma once + +#include +#include +#include + +namespace Utils +{ + void toLower(std::string &str) noexcept; + std::string getLowerString(const std::string &str); + + void trim(std::string &str); + std::string getTrimmedString(const std::string &str); + + std::vector explode(const std::string &str, const char sep); + + std::string encodeHtmlSymbols(const std::string &str); + + std::string binToHexString(const void *bin, const size_t size); + + std::string hexStringToBin(const std::string &hexStr); + + uint64_t hton64(const uint64_t host64) noexcept; + uint64_t ntoh64(const uint64_t net64) noexcept; + + void hton24(void *dest, const uint32_t host32) noexcept; + uint32_t ntoh24(const void *src24) noexcept; + + std::string getUniqueName(); + + size_t getPackNumberSize(const size_t number) noexcept; + size_t getPackStringSize(const std::string &str) noexcept; + + template + size_t getPackContainerSize(const T &container) noexcept + { + size_t full_size = getPackNumberSize(container.size() ); + + for (auto const &pair : container) + { + full_size += getPackStringSize(pair.first); + full_size += getPackStringSize(pair.second); + } + + return full_size; + } + + uint8_t *packNumber(uint8_t *dest, const size_t number) noexcept; + uint8_t *packString(uint8_t *dest, const std::string &str) noexcept; + + template + uint8_t *packContainer(void *dest, const T &container) noexcept + { + uint8_t *addr = reinterpret_cast(dest); + + addr = packNumber(addr, container.size() ); + + for (auto const &pair : container) + { + addr = packString(addr, pair.first); + addr = packString(addr, pair.second); + } + + return addr; + } + + void packNumber(std::vector &buf, const size_t number); + void packString(std::vector &buf, const std::string &str); + + template + void packContainer(std::vector &buf, const T &container) + { + packNumber(buf, container.size() ); + + for (auto const &pair : container) + { + packString(buf, pair.first); + packString(buf, pair.second); + } + } + + const uint8_t *unpackNumber(size_t *number, const uint8_t *src) noexcept; + const uint8_t *unpackString(std::string &str, const uint8_t *src); + + template + const uint8_t *unpackContainer(T &container, const uint8_t *src) + { + size_t count; + src = unpackNumber(&count, src); + + for (size_t i = 0; i < count; ++i) + { + std::string key; + src = unpackString(key, src); + + std::string value; + src = unpackString(value, src); + + container.emplace(std::move(key), std::move(value) ); + } + + return src; + } + + template + const uint8_t *unpackVector(T &vector, const uint8_t *src) + { + size_t count; + src = unpackNumber(&count, src); + + for (size_t i = 0; i < count; ++i) + { + std::string key; + src = unpackString(key, src); + + std::string value; + src = unpackString(value, src); + + vector.emplace_back(std::move(key), std::move(value) ); + } + + return src; + } + + time_t rfc822DatetimeToTimestamp(const std::string &strTime); + time_t predefinedDatetimeToTimestamp(const char *strTime); + + std::string getDatetimeAsString(time_t tTime = ~0, const bool isGmtTime = false); + std::string predefinedDatetimeToRfc822(const char *strTime); + + size_t getNumberLength(size_t number) noexcept; + + bool parseCookies(const std::string &cookieHeader, std::unordered_multimap &cookies); + + std::string urlEncode(const std::string &str); + std::string urlDecode(const std::string &str); +}; From 8a12878c457ebfca981e9683c08d94c15c023606 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Fri, 31 Mar 2017 17:01:32 +0300 Subject: [PATCH 14/31] Fixed build for Windows platform (after refactor) --- projects/msvs/httpserverapp.vcxproj | 77 +++++++++------ projects/msvs/httpserverapp.vcxproj.filters | 101 ++++++++++++++++---- src/client/protocol/ClientHttp2.cpp | 1 + src/socket/List.cpp | 4 +- src/socket/Socket.cpp | 4 +- src/transfer/http2/Http2.h | 6 +- 6 files changed, 141 insertions(+), 52 deletions(-) diff --git a/projects/msvs/httpserverapp.vcxproj b/projects/msvs/httpserverapp.vcxproj index f50dbce..e540487 100644 --- a/projects/msvs/httpserverapp.vcxproj +++ b/projects/msvs/httpserverapp.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -19,29 +19,50 @@ - + + + + + + + - - - - - - - + + + + + + + + + + + - + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + {D1565609-DDDE-4521-8AD9-0D1AD7D18525} @@ -52,26 +73,26 @@ DynamicLibrary true - v140 + v141 MultiByte DynamicLibrary true - v140 + v141 MultiByte DynamicLibrary false - v140 + v141 true MultiByte DynamicLibrary false - v140 + v141 true MultiByte @@ -124,7 +145,7 @@ NotUsing Level3 Disabled - WIN32;DEBUG;%(PreprocessorDefinitions) + WIN32;NOMINMAX;DEBUG;%(PreprocessorDefinitions) $(IntDir)asm\ $(IntDir)obj\ true @@ -141,7 +162,7 @@ NotUsing Level3 Disabled - WIN32;DEBUG;%(PreprocessorDefinitions) + WIN32;NOMINMAX;DEBUG;%(PreprocessorDefinitions) $(IntDir)asm\ $(IntDir)obj\ true @@ -160,7 +181,7 @@ MaxSpeed true true - WIN32;NDEBUG;%(PreprocessorDefinitions) + WIN32;NOMINMAX;NDEBUG;%(PreprocessorDefinitions) $(IntDir)asm\ $(IntDir)obj\ true @@ -181,7 +202,7 @@ MaxSpeed true true - WIN32;NDEBUG;%(PreprocessorDefinitions) + WIN32;NOMINMAX;NDEBUG;%(PreprocessorDefinitions) $(IntDir)asm\ $(IntDir)obj\ true diff --git a/projects/msvs/httpserverapp.vcxproj.filters b/projects/msvs/httpserverapp.vcxproj.filters index ba8f20d..13bcd41 100644 --- a/projects/msvs/httpserverapp.vcxproj.filters +++ b/projects/msvs/httpserverapp.vcxproj.filters @@ -15,69 +15,132 @@ - + Source Files Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + Source Files - + Header Files Header Files - + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files diff --git a/src/client/protocol/ClientHttp2.cpp b/src/client/protocol/ClientHttp2.cpp index 29caa18..05785c0 100644 --- a/src/client/protocol/ClientHttp2.cpp +++ b/src/client/protocol/ClientHttp2.cpp @@ -3,6 +3,7 @@ #include "../../transfer/http2/HPack.h" +#include #include namespace HttpClient diff --git a/src/socket/List.cpp b/src/socket/List.cpp index 2d07b23..997de8a 100644 --- a/src/socket/List.cpp +++ b/src/socket/List.cpp @@ -268,7 +268,7 @@ namespace Socket struct ::sockaddr_in client_addr = {}; socklen_t client_addr_len = sizeof(client_addr); - client_socket = ::accept(event.fd, static_cast(&client_addr), &client_addr_len); + client_socket = ::accept(event.fd, reinterpret_cast<::sockaddr *>(&client_addr), &client_addr_len); if (~0 != client_socket) { @@ -302,7 +302,7 @@ namespace Socket struct ::sockaddr_in client_addr = {}; socklen_t client_addr_len = sizeof(client_addr); - client_socket = ::accept(event.data.fd, reinterpret_cast(&client_addr), &client_addr_len); + client_socket = ::accept(event.data.fd, reinterpret_cast<::sockaddr *>(&client_addr), &client_addr_len); if (~0 != client_socket) { diff --git a/src/socket/Socket.cpp b/src/socket/Socket.cpp index d9b9043..ad9e744 100644 --- a/src/socket/Socket.cpp +++ b/src/socket/Socket.cpp @@ -270,7 +270,7 @@ namespace Socket long Socket::recv(void *buf, const size_t length) const noexcept { #ifdef WIN32 - return ::recv(this->socket_handle, buf, static_cast(length), 0); + return ::recv(this->socket_handle, reinterpret_cast(buf), static_cast(length), 0); #elif POSIX return ::recv(this->socket_handle, buf, length, 0); #else @@ -295,7 +295,7 @@ namespace Socket if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLRDNORM) { - recv_len = this->recv(this->socket_handle, buf, static_cast(length), 0); + recv_len = ::recv(this->socket_handle, reinterpret_cast(buf), static_cast(length), 0); } #elif POSIX struct ::pollfd event = { diff --git a/src/transfer/http2/Http2.h b/src/transfer/http2/Http2.h index a754b38..c6d02d0 100644 --- a/src/transfer/http2/Http2.h +++ b/src/transfer/http2/Http2.h @@ -9,7 +9,11 @@ #include #include -#include +#ifdef WIN32 + #undef NO_ERROR +#elif POSIX + #include +#endif namespace Http2 { From 0b6ff7ee354eb8ef8ffed4ef92510d323b3cabfa Mon Sep 17 00:00:00 2001 From: awwit Date: Wed, 5 Apr 2017 00:46:36 +0300 Subject: [PATCH 15/31] Fixed bugs in the HTTP/2 protocol --- src/Init.cpp | 29 +++++++++++- src/Init.h | 2 + src/Main.cpp | 2 +- src/client/protocol/ClientHttp2.cpp | 69 ++++++++++++++++------------- src/socket/AdapterTls.cpp | 25 ++++++++--- src/socket/List.cpp | 4 +- src/socket/Socket.cpp | 23 ++++++++++ src/socket/Socket.h | 2 + src/system/System.cpp | 12 ++--- src/transfer/http2/Http2.cpp | 28 ++++++++++-- src/transfer/http2/Http2.h | 12 ++++- src/utils/Utils.cpp | 39 +++++++++++++--- src/utils/Utils.h | 3 ++ 13 files changed, 193 insertions(+), 57 deletions(-) diff --git a/src/Init.cpp b/src/Init.cpp index fb95657..1e5f07d 100644 --- a/src/Init.cpp +++ b/src/Init.cpp @@ -28,6 +28,18 @@ void destroySocketAdapter(Socket::Adapter *adapter) } } +std::string getClearPath(const std::string &path) +{ + const size_t pos = path.find_first_of("?#"); + + if (std::string::npos == pos) + { + return path; + } + + return std::string(path.cbegin(), path.cbegin() + pos); +} + static void getIncomingVars(std::unordered_multimap ¶ms, const std::string &uri) { const size_t start = uri.find('?'); @@ -37,10 +49,22 @@ static void getIncomingVars(std::unordered_multimap &p return; } + const size_t finish = uri.find('#'); + + if (finish < start) + { + return; + } + for (size_t var_pos = start + 1, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) { var_end = uri.find('&', var_pos); + if (var_end > finish) + { + var_end = std::string::npos; + } + size_t delimiter = uri.find('=', var_pos); if (delimiter >= var_end) @@ -140,13 +164,16 @@ bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *p std::deque > dynamic_table; src = Utils::unpackVector(dynamic_table, src); + std::mutex *mtx = nullptr; + src = Utils::unpackPointer(reinterpret_cast(&mtx), src); + src = Utils::unpackContainer(headers, src); src = Utils::unpackContainer(data, src); src = Utils::unpackFilesIncoming(files, src); getIncomingVars(params, path); - Http2::OutStream *stream = new Http2::OutStream(stream_id, settings, Http2::DynamicTable(settings.header_table_size, settings.max_header_list_size, std::move(dynamic_table) ) ); + Http2::OutStream *stream = new Http2::OutStream(stream_id, settings, Http2::DynamicTable(settings.header_table_size, settings.max_header_list_size, std::move(dynamic_table) ), mtx); prot = new HttpClient::ClientHttp2(socket_adapter, stream); diff --git a/src/Init.h b/src/Init.h index 3d068e3..8d23d61 100644 --- a/src/Init.h +++ b/src/Init.h @@ -8,6 +8,8 @@ Socket::Adapter *createSocketAdapter(Transfer::app_request *request, void *addr); void destroySocketAdapter(Socket::Adapter *adapter); +std::string getClearPath(const std::string &path); + bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *procResponse, const Transfer::app_request *request, Socket::Adapter *socket_adapter); void cleanProtocolData(HttpClient::Response *response); diff --git a/src/Main.cpp b/src/Main.cpp index 232dd44..65e77aa 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -27,7 +27,7 @@ DLLEXPORT int application_call(Transfer::app_request *request, Transfer::app_res return EXIT_FAILURE; } - const std::string absolute_path = proc_request.document_root + proc_request.path; + const std::string absolute_path = proc_request.document_root + getClearPath(proc_request.path); int result = EXIT_SUCCESS; diff --git a/src/client/protocol/ClientHttp2.cpp b/src/client/protocol/ClientHttp2.cpp index 05785c0..f3f2fd8 100644 --- a/src/client/protocol/ClientHttp2.cpp +++ b/src/client/protocol/ClientHttp2.cpp @@ -42,26 +42,26 @@ namespace HttpClient { std::vector buf; buf.reserve(4096); + buf.resize(Http2::FRAME_HEADER_SIZE + sizeof(uint8_t) ); headers.emplace(headers.begin(), ":status", std::to_string(static_cast(status) ) ); HPack::pack(buf, headers, this->stream->dynamic_table); - uint32_t data_size = buf.size(); + uint32_t data_size = buf.size() - Http2::FRAME_HEADER_SIZE - sizeof(uint8_t); const uint8_t padding = getPaddingSize(data_size); const uint16_t padding_size = padding + sizeof(uint8_t); - if (padding_size) + if (data_size + padding_size > this->stream->settings.max_frame_size) { - if (data_size + padding_size > this->stream->settings.max_frame_size) - { - data_size = this->stream->settings.max_frame_size - padding_size; - } + data_size = this->stream->settings.max_frame_size - padding_size; } const size_t frame_size = data_size + padding_size; + buf.resize(frame_size + Http2::FRAME_HEADER_SIZE); + Http2::FrameFlag flags = Http2::FrameFlag::END_HEADERS; if (endStream) @@ -69,23 +69,27 @@ namespace HttpClient flags |= Http2::FrameFlag::END_STREAM; } - if (padding_size) - { - flags |= Http2::FrameFlag::PADDED; + flags |= Http2::FrameFlag::PADDED; - buf.insert(buf.begin(), sizeof(uint8_t), padding); + buf[Http2::FRAME_HEADER_SIZE] = padding; - if (padding) - { - buf.insert(buf.end(), padding, 0); - } + if (padding) + { + std::fill(buf.end() - padding, buf.end(), 0); } - buf.insert(buf.begin(), Http2::FRAME_HEADER_SIZE, 0); - this->stream->setHttp2FrameHeader(reinterpret_cast(buf.data() ), frame_size, Http2::FrameType::HEADERS, flags); - return this->sock->nonblock_send(buf.data(), buf.size(), timeout) > 0; + this->stream->lock(); + + auto const is_sended = this->sock->nonblock_send(buf.data(), buf.size(), timeout) > 0; + + if (endStream || false == is_sended) + { + this->stream->unlock(); + } + + return is_sended; } void ClientHttp2::sendWindowUpdate(const uint32_t size, const std::chrono::milliseconds &timeout) const @@ -111,23 +115,20 @@ namespace HttpClient while (total < size) { - buf.resize(0); - size_t data_size = (size - total < this->stream->settings.max_frame_size) ? size - total : this->stream->settings.max_frame_size; const uint8_t padding = getPaddingSize(data_size); const uint16_t padding_size = padding + sizeof(uint8_t); - if (padding_size) + if (data_size + padding_size > this->stream->settings.max_frame_size) { - if (data_size + padding_size > this->stream->settings.max_frame_size) - { - data_size = this->stream->settings.max_frame_size - padding_size; - } + data_size = this->stream->settings.max_frame_size - padding_size; } const size_t frame_size = data_size + padding_size; + buf.resize(frame_size + Http2::FRAME_HEADER_SIZE); + if (static_cast(this->stream->window_size_out - this->stream->settings.max_frame_size) <= 0) { size_t update_size = this->stream->settings.initial_window_size + (size - total) - this->stream->window_size_out; @@ -149,30 +150,33 @@ namespace HttpClient flags |= Http2::FrameFlag::END_STREAM; } + size_t cur = Http2::FRAME_HEADER_SIZE; + if (padding_size) { flags |= Http2::FrameFlag::PADDED; - buf.insert(buf.begin(), sizeof(uint8_t), padding); - } + buf[cur] = padding; - buf.insert(buf.begin(), Http2::FRAME_HEADER_SIZE, 0); + ++cur; + } const Http2::FrameType frame_type = Http2::FrameType::DATA; this->stream->setHttp2FrameHeader(buf.data(), frame_size, frame_type, flags); - std::copy(data, data + data_size, std::back_inserter(buf) ); + std::copy(data, data + data_size, buf.begin() + cur); if (padding) { - buf.insert(buf.end(), padding, 0); + std::fill(buf.end() - padding, buf.end(), 0); } long sended = this->sock->nonblock_send(buf.data(), buf.size(), timeout); if (sended <= 0) { + total = 0; break; } @@ -182,6 +186,11 @@ namespace HttpClient total += data_size; } - return total; + if (total == 0 || endStream) + { + this->stream->unlock(); + } + + return static_cast(total); } }; diff --git a/src/socket/AdapterTls.cpp b/src/socket/AdapterTls.cpp index 2c88aec..65de7f5 100644 --- a/src/socket/AdapterTls.cpp +++ b/src/socket/AdapterTls.cpp @@ -63,25 +63,36 @@ namespace Socket long AdapterTls::nonblock_send_all(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { - size_t record_size = ::gnutls_record_get_max_size(this->session); + // size_t record_size = ::gnutls_record_get_max_size(this->session); + size_t record_size = length; if (0 == record_size) { return -1; } + Socket sock(this->get_handle() ); + + // ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); + size_t total = 0; while (total < length) { - ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); - if (record_size > length - total) { record_size = length - total; } - const long send_size = ::gnutls_record_send(this->session, reinterpret_cast(buf) + total, record_size); + // const long send_size = ::gnutls_record_send(this->session, reinterpret_cast(buf) + total, record_size); + + long send_size = 0; + + do + { + sock.nonblock_send_sync(); + } + while (GNUTLS_E_AGAIN == (send_size = ::gnutls_record_send(this->session, reinterpret_cast(buf) + total, record_size) ) ); if (send_size < 0) { @@ -111,7 +122,11 @@ namespace Socket long AdapterTls::nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { - ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); + // ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); + + Socket sock(this->get_handle() ); + sock.nonblock_recv_sync(); + return ::gnutls_record_recv(this->session, buf, length); } diff --git a/src/socket/List.cpp b/src/socket/List.cpp index 997de8a..8df0b9a 100644 --- a/src/socket/List.cpp +++ b/src/socket/List.cpp @@ -265,7 +265,7 @@ namespace Socket do { - struct ::sockaddr_in client_addr = {}; + ::sockaddr_in client_addr {}; socklen_t client_addr_len = sizeof(client_addr); client_socket = ::accept(event.fd, reinterpret_cast<::sockaddr *>(&client_addr), &client_addr_len); @@ -299,7 +299,7 @@ namespace Socket do { - struct ::sockaddr_in client_addr = {}; + ::sockaddr_in client_addr {}; socklen_t client_addr_len = sizeof(client_addr); client_socket = ::accept(event.data.fd, reinterpret_cast<::sockaddr *>(&client_addr), &client_addr_len); diff --git a/src/socket/Socket.cpp b/src/socket/Socket.cpp index ad9e744..d2200bb 100644 --- a/src/socket/Socket.cpp +++ b/src/socket/Socket.cpp @@ -314,6 +314,29 @@ namespace Socket return recv_len; } + void Socket::nonblock_recv_sync() const noexcept + { + #ifdef WIN32 + WSAPOLLFD event = { + this->socket_handle, + POLLRDNORM | POLLRDBAND, + 0 + }; + + ::WSAPoll(&event, 1, ~0); + #elif POSIX + struct ::pollfd event = { + this->socket_handle, + POLLIN, + 0 + }; + + ::poll(&event, 1, ~0); + #else + #error "Undefine platform" + #endif + } + static long send_all(const System::native_socket_type socket_handle, const void *data, const size_t length) noexcept { size_t total = 0; diff --git a/src/socket/Socket.h b/src/socket/Socket.h index 26f40a5..dbefb54 100644 --- a/src/socket/Socket.h +++ b/src/socket/Socket.h @@ -51,6 +51,8 @@ namespace Socket long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept; long nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept; + void nonblock_recv_sync() const noexcept; + long send(const std::string &buf) const noexcept; long send(const void *buf, const size_t length) const noexcept; diff --git a/src/system/System.cpp b/src/system/System.cpp index b32f51c..16714d2 100644 --- a/src/system/System.cpp +++ b/src/system/System.cpp @@ -228,7 +228,7 @@ namespace System ::FileTimeToSystemTime(&ftWrite, &stUtc); - struct ::tm tm_time { + std::tm tm_time { stUtc.wSecond, stUtc.wMinute, stUtc.wHour, @@ -240,11 +240,11 @@ namespace System -1 }; - *fileTime = ::mktime(&tm_time); + *fileTime = std::mktime(&tm_time); return true; #elif POSIX - struct ::stat attrib; + struct ::stat attrib {}; if (-1 == ::stat(filePath.c_str(), &attrib) ) { @@ -253,11 +253,11 @@ namespace System *fileSize = attrib.st_size; - struct ::tm clock = {}; + std::tm clock {}; ::gmtime_r(&(attrib.st_mtime), &clock); - *fileTime = ::mktime(&clock); + *fileTime = std::mktime(&clock); return true; #else @@ -284,7 +284,7 @@ namespace System memory_name.erase(memory_name.begin() + pos, memory_name.end() ); } - ::TCHAR buf[MAX_PATH + 1] = {}; + ::TCHAR buf[MAX_PATH + 1] {}; ::GetFullPathName(memory_name.c_str(), MAX_PATH, buf, nullptr); #ifdef UNICODE diff --git a/src/transfer/http2/Http2.cpp b/src/transfer/http2/Http2.cpp index 208eb79..93280ba 100644 --- a/src/transfer/http2/Http2.cpp +++ b/src/transfer/http2/Http2.cpp @@ -144,6 +144,16 @@ namespace Http2 return (addr + Http2::FRAME_HEADER_SIZE); } + void IncStream::lock() + { + this->conn.sync.mtx.lock(); + } + + void IncStream::unlock() noexcept + { + this->conn.sync.mtx.unlock(); + } + void IncStream::close() noexcept { this->incoming_headers.clear(); @@ -157,15 +167,15 @@ namespace Http2 // this->state = StreamState::CLOSED; } - OutStream::OutStream(const uint32_t streamId, const ConnectionSettings &settings, DynamicTable &&dynamic_table) noexcept - : stream_id(streamId), settings(settings), window_size_out(settings.initial_window_size), dynamic_table(std::move(dynamic_table) ) + OutStream::OutStream(const uint32_t streamId, const ConnectionSettings &settings, DynamicTable &&dynamic_table, std::mutex *mtx) noexcept + : stream_id(streamId), settings(settings), window_size_out(settings.initial_window_size), dynamic_table(std::move(dynamic_table) ), mtx(mtx) { } - OutStream::OutStream(const IncStream &stream) noexcept + OutStream::OutStream(const IncStream &stream) : stream_id(stream.stream_id), settings(stream.conn.client_settings), - window_size_out(stream.window_size_out), dynamic_table(stream.conn.encoding_dynamic_table) + window_size_out(stream.window_size_out), dynamic_table(stream.conn.encoding_dynamic_table), mtx(&stream.conn.sync.mtx) { } @@ -179,4 +189,14 @@ namespace Http2 return (addr + Http2::FRAME_HEADER_SIZE); } + + void OutStream::lock() + { + this->mtx->lock(); + } + + void OutStream::unlock() noexcept + { + this->mtx->unlock(); + } }; diff --git a/src/transfer/http2/Http2.h b/src/transfer/http2/Http2.h index c6d02d0..6647fee 100644 --- a/src/transfer/http2/Http2.h +++ b/src/transfer/http2/Http2.h @@ -173,6 +173,9 @@ namespace Http2 uint8_t *setHttp2FrameHeader(uint8_t *addr, const uint32_t frameSize, const Http2::FrameType frameType, const Http2::FrameFlag frameFlags) noexcept; + void lock(); + void unlock() noexcept; + void close() noexcept; }; @@ -186,10 +189,15 @@ namespace Http2 DynamicTable dynamic_table; + std::mutex *mtx; + public: - OutStream(const uint32_t streamId, const ConnectionSettings &settings, DynamicTable &&dynamic_table) noexcept; - OutStream(const IncStream &stream) noexcept; + OutStream(const uint32_t streamId, const ConnectionSettings &settings, DynamicTable &&dynamic_table, std::mutex *mtx) noexcept; + OutStream(const IncStream &stream); uint8_t *setHttp2FrameHeader(uint8_t *addr, const uint32_t frameSize, const Http2::FrameType frameType, const Http2::FrameFlag frameFlags) noexcept; + + void lock(); + void unlock() noexcept; }; }; diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index dc06e23..1c9813a 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -283,6 +283,13 @@ namespace Utils return getPackNumberSize(str.length() ) + str.length(); } + uint8_t *packPointer(uint8_t *dest, void *pointer) noexcept + { + *reinterpret_cast(dest) = pointer; + + return dest + sizeof(void *); + } + uint8_t *packNumber(uint8_t *dest, const size_t number) noexcept { if (number <= 252) @@ -334,6 +341,13 @@ namespace Utils return dest + str.length(); } + void packPointer(std::vector &buf, void *pointer) + { + buf.resize(buf.size() + sizeof(void *) ); + uint8_t *dest = reinterpret_cast(buf.data() + buf.size() - sizeof(void *) ); + *reinterpret_cast(dest) = pointer; + } + void packNumber(std::vector &buf, const size_t number) { if (number <= 252) @@ -376,6 +390,13 @@ namespace Utils } } + const uint8_t *unpackPointer(void **pointer, const uint8_t *src) noexcept + { + *pointer = *reinterpret_cast(const_cast(static_cast(src) ) ); + + return src + sizeof(void *); + } + const uint8_t *unpackNumber(size_t *number, const uint8_t *src) noexcept { *number = *src; @@ -437,7 +458,7 @@ namespace Utils */ time_t rfc822DatetimeToTimestamp(const std::string &strTime) { - std::tm tc = {}; + std::tm tc {}; // Parse RFC 882 (ddd, dd MMM yyyy HH:mm:ss K) @@ -585,13 +606,13 @@ namespace Utils static time_t localToGmt(const time_t timestamp) { #ifdef WIN32 - std::tm stm = {}; + std::tm stm {}; ::gmtime_s(&stm, ×tamp); return std::mktime(&stm); #else - std::tm stm = {}; + std::tm stm {}; ::gmtime_r(×tamp, &stm); @@ -604,7 +625,7 @@ namespace Utils */ time_t predefinedDatetimeToTimestamp(const char *strTime) { - std::tm tc = {}; + std::tm tc {}; const char *ptrStr = std::strchr(strTime, ' '); @@ -628,6 +649,12 @@ namespace Utils ++ptrStr; + // Fix for MS __DATE__ + if (' ' == *ptrStr) + { + ++ptrStr; + } + strTime = std::strchr(ptrStr, ' '); if (nullptr == strTime) @@ -690,7 +717,7 @@ namespace Utils } #ifdef WIN32 - std::tm stm = {}; + std::tm stm {}; isGmtTime ? ::localtime_s(&stm, &tTime) : @@ -699,7 +726,7 @@ namespace Utils // RFC 822 auto const len = std::strftime(buf.data(), buf.size(), "%a, %d %b %Y %H:%M:%S GMT", &stm); #else - std::tm stm = {}; + std::tm stm {}; isGmtTime ? ::localtime_r(&tTime, &stm) : diff --git a/src/utils/Utils.h b/src/utils/Utils.h index 5137831..47236c8 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -45,6 +45,7 @@ namespace Utils return full_size; } + uint8_t *packPointer(uint8_t *dest, void *pointer) noexcept; uint8_t *packNumber(uint8_t *dest, const size_t number) noexcept; uint8_t *packString(uint8_t *dest, const std::string &str) noexcept; @@ -64,6 +65,7 @@ namespace Utils return addr; } + void packPointer(std::vector &buf, void *pointer); void packNumber(std::vector &buf, const size_t number); void packString(std::vector &buf, const std::string &str); @@ -79,6 +81,7 @@ namespace Utils } } + const uint8_t *unpackPointer(void **pointer, const uint8_t *src) noexcept; const uint8_t *unpackNumber(size_t *number, const uint8_t *src) noexcept; const uint8_t *unpackString(std::string &str, const uint8_t *src); From 081e310b964967312c6830fdc1213f96910230d3 Mon Sep 17 00:00:00 2001 From: awwit Date: Wed, 5 Apr 2017 16:50:58 +0300 Subject: [PATCH 16/31] Optimization of synchronization when sending HTTP/2 frames Added code for the WebSocket protocol --- projects/qt-creator/httpserverapp.qbs | 2 + src/application/Test.cpp | 9 +- src/client/protocol/ClientHttp2.cpp | 28 ++-- src/client/protocol/WebSocket.cpp | 196 ++++++++++++++++++++++++++ src/client/protocol/WebSocket.h | 30 ++++ 5 files changed, 243 insertions(+), 22 deletions(-) create mode 100644 src/client/protocol/WebSocket.cpp create mode 100644 src/client/protocol/WebSocket.h diff --git a/projects/qt-creator/httpserverapp.qbs b/projects/qt-creator/httpserverapp.qbs index f919cab..e12b20e 100644 --- a/projects/qt-creator/httpserverapp.qbs +++ b/projects/qt-creator/httpserverapp.qbs @@ -32,6 +32,8 @@ Project { "../../src/client/protocol/ClientHttp2.h", "../../src/client/protocol/ClientProtocol.cpp", "../../src/client/protocol/ClientProtocol.h", + "../../src/client/protocol/WebSocket.cpp", + "../../src/client/protocol/WebSocket.h", "../../src/utils/Event.cpp", "../../src/utils/Event.h", "../../src/transfer/FileIncoming.cpp", diff --git a/src/application/Test.cpp b/src/application/Test.cpp index 7fea204..d503da5 100644 --- a/src/application/Test.cpp +++ b/src/application/Test.cpp @@ -135,11 +135,12 @@ namespace Application const std::chrono::milliseconds timeout(5000); - response.sendHeaders(additional, timeout, s.empty() ); - - if (false == s.empty() ) + if (response.sendHeaders(additional, timeout, s.empty() ) ) { - response.sendData(s.data(), s.size(), timeout, true); + if (false == s.empty() ) + { + response.sendData(s.data(), s.size(), timeout, true); + } } return EXIT_SUCCESS; diff --git a/src/client/protocol/ClientHttp2.cpp b/src/client/protocol/ClientHttp2.cpp index f3f2fd8..ac91aae 100644 --- a/src/client/protocol/ClientHttp2.cpp +++ b/src/client/protocol/ClientHttp2.cpp @@ -80,16 +80,9 @@ namespace HttpClient this->stream->setHttp2FrameHeader(reinterpret_cast(buf.data() ), frame_size, Http2::FrameType::HEADERS, flags); - this->stream->lock(); + const std::unique_lock lock(*this->stream->mtx); - auto const is_sended = this->sock->nonblock_send(buf.data(), buf.size(), timeout) > 0; - - if (endStream || false == is_sended) - { - this->stream->unlock(); - } - - return is_sended; + return this->sock->nonblock_send(buf.data(), buf.size(), timeout) > 0; } void ClientHttp2::sendWindowUpdate(const uint32_t size, const std::chrono::milliseconds &timeout) const @@ -101,6 +94,8 @@ namespace HttpClient *reinterpret_cast(addr) = ::htonl(size); + const std::unique_lock lock(*this->stream->mtx); + this->sock->nonblock_send(buf.data(), buf.size(), timeout); } @@ -161,9 +156,7 @@ namespace HttpClient ++cur; } - const Http2::FrameType frame_type = Http2::FrameType::DATA; - - this->stream->setHttp2FrameHeader(buf.data(), frame_size, frame_type, flags); + this->stream->setHttp2FrameHeader(buf.data(), frame_size, Http2::FrameType::DATA, flags); std::copy(data, data + data_size, buf.begin() + cur); @@ -172,7 +165,11 @@ namespace HttpClient std::fill(buf.end() - padding, buf.end(), 0); } - long sended = this->sock->nonblock_send(buf.data(), buf.size(), timeout); + this->stream->lock(); + + const long sended = this->sock->nonblock_send(buf.data(), buf.size(), timeout); + + this->stream->unlock(); if (sended <= 0) { @@ -186,11 +183,6 @@ namespace HttpClient total += data_size; } - if (total == 0 || endStream) - { - this->stream->unlock(); - } - return static_cast(total); } }; diff --git a/src/client/protocol/WebSocket.cpp b/src/client/protocol/WebSocket.cpp new file mode 100644 index 0000000..cc09ae2 --- /dev/null +++ b/src/client/protocol/WebSocket.cpp @@ -0,0 +1,196 @@ + +#include "WebSocket.h" + +#include "../../utils/Utils.h" +#include "../../socket/Socket.h" + +#ifdef POSIX + #include +#endif + +namespace HttpClient +{ + WebSocket::WebSocket(const WebSocket &obj) noexcept : sock(obj.sock) + { + + } + + WebSocket::WebSocket(Socket::Adapter *adapter) noexcept : sock(adapter) + { + + } + + std::vector WebSocket::packDataToMessageFrame(const void *data, const size_t size) + { + std::vector frame; + + if (0 == size) + { + return frame; + } + + constexpr size_t header_max_size = 14; + frame.reserve(size + header_max_size); + frame.resize(header_max_size); + + frame[0] = 0x81; + + size_t cur_pos = sizeof(uint8_t) * 2; + + if (size <= 125) + { + frame[1] = size; + } + else if (size <= 65536) + { + frame[1] = 126; + + *reinterpret_cast(&frame[2]) = htons(size); + + cur_pos += sizeof(uint16_t); + } + else // More + { + frame[1] = 127; + + *reinterpret_cast(&frame[2]) = Utils::hton64(size); + + cur_pos += sizeof(uint64_t); + } + + frame.erase(frame.cbegin() + cur_pos, frame.cend() ); + + frame.insert(frame.cend(), reinterpret_cast(data), reinterpret_cast(data) + size); + + return frame; + } + + Socket::Adapter *WebSocket::getSocket() noexcept + { + return this->sock; + } + + const Socket::Adapter *WebSocket::getSocket() const noexcept + { + return this->sock; + } + + long WebSocket::nonblock_recv(std::vector &frame, const std::chrono::milliseconds &timeout) const + { + std::vector buf(4096); + + const long recv_size = this->sock->nonblock_recv(buf, timeout); + + if (recv_size <= 0) + { + return recv_size; + } + + // See @link: http://tools.ietf.org/html/rfc6455#page-28 + + const uint8_t info_frame = buf[0]; + + if ( (info_frame & 0x08) == 0x08) // opcode 0x08 — close connection + { + return -1; + } + + uint8_t info_size = buf[1]; + + const bool is_mask_set = info_size & uint8_t(1 << 7); + + info_size &= ~uint8_t(1 << 7); // Unset first bit + + size_t cur_pos = sizeof(uint8_t) * 2; + + uint64_t frame_size; + + if (info_size <= 125) + { + frame_size = info_size; + } + else if (info_size == 126) + { + frame_size = ntohs(*reinterpret_cast(&buf[cur_pos]) ); + + cur_pos += sizeof(uint16_t); + } + else // if (info_size == 127) + { + frame_size = Utils::ntoh64(*reinterpret_cast(&buf[cur_pos]) ); + + cur_pos += sizeof(uint64_t); + } + + if (frame_size > (buf.size() - cur_pos) ) + { + return -1; // Close connection + } + + uint32_t mask; + + if (is_mask_set) + { + mask = *reinterpret_cast(&buf[cur_pos]); + + cur_pos += sizeof(uint32_t); + } + + const uint8_t align = (recv_size - cur_pos) % sizeof(uint32_t); + + frame.reserve(recv_size - cur_pos + align); + + frame.assign(buf.cbegin() + cur_pos, buf.cbegin() + recv_size); + + if (is_mask_set) + { + if (align) + { + frame.insert(frame.cend(), align, 0); + } + + uint32_t *addr = reinterpret_cast(frame.data() ); + + for (size_t i = 0; i < frame.size() / sizeof(uint32_t); ++i) + { + addr[i] ^= mask; + } + + if (align) + { + frame.erase(frame.cend() - align, frame.cend() ); + } + } + + return recv_size - cur_pos; + } + + long WebSocket::nonblock_send(const void *data, const size_t length, const std::chrono::milliseconds &timeout) const + { + const std::vector frame = WebSocket::packDataToMessageFrame(data, length); + + if (frame.empty() ) + { + return 0; + } + + return this->sock->nonblock_send(frame.data(), frame.size(), timeout); + } + + long WebSocket::nonblock_send(const std::string &str, const std::chrono::milliseconds &timeout) const + { + const std::vector frame = WebSocket::packDataToMessageFrame(str.data(), str.length() ); + + if (frame.empty() ) + { + return 0; + } + + return this->sock->nonblock_send(frame.data(), frame.size(), timeout); + } + + void WebSocket::close() noexcept + { + this->sock->close(); + } +}; diff --git a/src/client/protocol/WebSocket.h b/src/client/protocol/WebSocket.h new file mode 100644 index 0000000..937f9f1 --- /dev/null +++ b/src/client/protocol/WebSocket.h @@ -0,0 +1,30 @@ +#pragma once + +#include "../../socket/Adapter.h" + +namespace HttpClient +{ + class WebSocket + { + private: + Socket::Adapter *sock; + + public: + static std::vector packDataToMessageFrame(const void *data, const size_t size); + + public: + WebSocket() = delete; + WebSocket(const WebSocket &obj) noexcept; + WebSocket(Socket::Adapter *adapter) noexcept; + + Socket::Adapter *getSocket() noexcept; + const Socket::Adapter *getSocket() const noexcept; + + long nonblock_recv(std::vector &frame, const std::chrono::milliseconds &timeout) const; + + long nonblock_send(const void *data, const size_t length, const std::chrono::milliseconds &timeout) const; + long nonblock_send(const std::string &str, const std::chrono::milliseconds &timeout) const; + + void close() noexcept; + }; +}; From de7c68e7b0385692ea88fff633dfbfdf06a98756 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Wed, 5 Apr 2017 17:11:31 +0300 Subject: [PATCH 17/31] Updated project for VS --- projects/msvs/httpserverapp.vcxproj | 2 ++ projects/msvs/httpserverapp.vcxproj.filters | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/projects/msvs/httpserverapp.vcxproj b/projects/msvs/httpserverapp.vcxproj index e540487..7994785 100644 --- a/projects/msvs/httpserverapp.vcxproj +++ b/projects/msvs/httpserverapp.vcxproj @@ -23,6 +23,7 @@ + @@ -44,6 +45,7 @@ + diff --git a/projects/msvs/httpserverapp.vcxproj.filters b/projects/msvs/httpserverapp.vcxproj.filters index 13bcd41..f082fe2 100644 --- a/projects/msvs/httpserverapp.vcxproj.filters +++ b/projects/msvs/httpserverapp.vcxproj.filters @@ -72,6 +72,9 @@ Source Files + + Source Files + @@ -143,5 +146,8 @@ Header Files + + Header Files + \ No newline at end of file From 871d06362df47e96f794d2c10a95df5a20f1864e Mon Sep 17 00:00:00 2001 From: awwit Date: Wed, 12 Apr 2017 22:18:13 +0300 Subject: [PATCH 18/31] The path to the application directory is passed to the initialization function --- src/Init.cpp | 2 +- src/Init.h | 2 +- src/Main.cpp | 10 +++++----- src/Main.h | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Init.cpp b/src/Init.cpp index 1e5f07d..2b1d353 100644 --- a/src/Init.cpp +++ b/src/Init.cpp @@ -211,7 +211,7 @@ bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *p return success; } -void cleanProtocolData(HttpClient::Response *response) +void freeProtocolData(HttpClient::Response *response) { if (response) { diff --git a/src/Init.h b/src/Init.h index 8d23d61..8c85e8b 100644 --- a/src/Init.h +++ b/src/Init.h @@ -11,6 +11,6 @@ void destroySocketAdapter(Socket::Adapter *adapter); std::string getClearPath(const std::string &path); bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *procResponse, const Transfer::app_request *request, Socket::Adapter *socket_adapter); -void cleanProtocolData(HttpClient::Response *response); +void freeProtocolData(HttpClient::Response *response); bool isSwitchingProtocols(const HttpClient::Request &request, HttpClient::Response &response); diff --git a/src/Main.cpp b/src/Main.cpp index 65e77aa..2024468 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -6,12 +6,12 @@ #include "utils/Utils.h" -DLLEXPORT bool application_init() +EXPORT bool application_init(const char *root) { return true; } -DLLEXPORT int application_call(Transfer::app_request *request, Transfer::app_response *response) +EXPORT int application_call(Transfer::app_request *request, Transfer::app_response *response) { // Allocate memory on the stack uint8_t addr[sizeof(Socket::AdapterTls)]; @@ -61,12 +61,12 @@ DLLEXPORT int application_call(Transfer::app_request *request, Transfer::app_res Utils::packContainer(reinterpret_cast(response->response_data), proc_response.headers); } - cleanProtocolData(&proc_response); + freeProtocolData(&proc_response); return result; } -DLLEXPORT void application_clear(void *response_data, size_t response_size) +EXPORT void application_clear(void *response_data, size_t response_size) { if (response_data && response_size) { @@ -74,7 +74,7 @@ DLLEXPORT void application_clear(void *response_data, size_t response_size) } } -DLLEXPORT void application_final() +EXPORT void application_final(const char *root) { } diff --git a/src/Main.h b/src/Main.h index e8eb26d..62de164 100644 --- a/src/Main.h +++ b/src/Main.h @@ -1,7 +1,7 @@ #pragma once #ifdef WIN32 - #define DLLEXPORT extern "C" __declspec(dllexport) + #define EXPORT extern "C" __declspec(dllexport) #else - #define DLLEXPORT extern "C" + #define EXPORT extern "C" #endif From 4754f75f863a2b4dfcd287c9d24745b8d457cc91 Mon Sep 17 00:00:00 2001 From: awwit Date: Sun, 7 May 2017 16:16:57 +0300 Subject: [PATCH 19/31] Added build variant using Makefile --- Makefile | 34 ++++++++++++++++++++++++++++++++++ README.md | 8 ++++++++ src/Main.h | 2 +- 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2451e56 --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +RM = rm -rf +MKDIR = mkdir -p + +#CXX = g++ +CXXFLAGS += -fPIC -std=c++14 -c -Wall -O2 +LDFLAGS = -shared -ldl -lpthread -lgnutls + +DEFS = POSIX +DEFINES = $(patsubst %, -D%, $(DEFS) ) + +SOURCEDIR = ./src +BUILDDIR = ./build +OBJDIR = $(BUILDDIR)/obj + +SOURCES = $(shell find $(SOURCEDIR) -type f -name '*.cpp') +OBJECTS = $(patsubst $(SOURCEDIR)/%.cpp, $(OBJDIR)/%.o, $(SOURCES) ) + +EXECUTABLE = $(BUILDDIR)/httpserverapp.so + +.PHONY: all clean +all: $(BUILDDIR) $(EXECUTABLE) + +$(BUILDDIR): + $(MKDIR) $@ + +$(EXECUTABLE): $(OBJECTS) + $(CXX) $(LDFLAGS) $(OBJECTS) -o $@ + +$(OBJECTS) : $(OBJDIR)/%.o : $(SOURCEDIR)/%.cpp + @$(MKDIR) $(dir $@) + $(CXX) $(DEFINES) $(CXXFLAGS) $< -o $@ + +clean: + $(RM) $(OBJDIR) $(EXECUTABLE) diff --git a/README.md b/README.md index 074e3e8..bd7312e 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,14 @@ Windows: `ws2_32.lib`, `libgnutls.dll.a` Linux: +```sh +git clone https://github.com/awwit/httpserverapp.git +cd httpserverapp +make +``` + +or + ```sh git clone https://github.com/awwit/httpserverapp.git cd httpserverapp diff --git a/src/Main.h b/src/Main.h index 62de164..ba712da 100644 --- a/src/Main.h +++ b/src/Main.h @@ -1,6 +1,6 @@ #pragma once -#ifdef WIN32 +#ifdef _MSC_VER #define EXPORT extern "C" __declspec(dllexport) #else #define EXPORT extern "C" From 946e0dcda5b448cf87e583bb5502cf0d451495d3 Mon Sep 17 00:00:00 2001 From: awwit Date: Wed, 2 Aug 2017 15:40:38 +0300 Subject: [PATCH 20/31] Fixed bug in function Utils::explode Decode url before file search --- src/Init.cpp | 4 ++-- src/utils/Utils.cpp | 6 +++--- src/utils/Utils.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Init.cpp b/src/Init.cpp index 2b1d353..6cd85d2 100644 --- a/src/Init.cpp +++ b/src/Init.cpp @@ -34,10 +34,10 @@ std::string getClearPath(const std::string &path) if (std::string::npos == pos) { - return path; + return Utils::urlDecode(path); } - return std::string(path.cbegin(), path.cbegin() + pos); + return Utils::urlDecode(path.substr(0, pos) ); } static void getIncomingVars(std::unordered_multimap ¶ms, const std::string &uri) diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index 1c9813a..9ef440e 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -55,9 +55,9 @@ namespace Utils for (size_t pos = 0; std::string::npos != pos;) { - size_t delimiter = str.find(sep, pos); + const size_t delimiter = str.find(sep, pos); - std::string value = str.substr(pos, delimiter); + std::string value = str.substr(pos, delimiter - pos); trim(value); values.emplace_back(std::move(value) ); @@ -865,4 +865,4 @@ namespace Utils return decoded; } -}; +} diff --git a/src/utils/Utils.h b/src/utils/Utils.h index 47236c8..9dce37a 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -137,4 +137,4 @@ namespace Utils std::string urlEncode(const std::string &str); std::string urlDecode(const std::string &str); -}; +} From 834abbb84a43740e54ddc3fe8f2eabfe89ad1bae Mon Sep 17 00:00:00 2001 From: awwit Date: Sat, 11 Nov 2017 16:46:34 +0300 Subject: [PATCH 21/31] Parsing cookies for HTTP/2 protocol. Code styling --- projects/qt-creator/httpserverapp.qbs | 24 +- projects/qt-creator/httpserverapp.qbs.user | 246 +++++++++++++++++ src/Init.cpp | 104 ++++--- src/Init.h | 4 +- src/Main.cpp | 9 +- src/application/Test.cpp | 2 +- src/application/Test.h | 6 +- src/{client => server}/Request.cpp | 29 +- src/{client => server}/Request.h | 2 +- src/{client => server}/Response.cpp | 8 +- src/{client => server}/Response.h | 2 +- .../protocol/ClientHttp1.cpp | 13 +- src/{client => server}/protocol/ClientHttp1.h | 2 +- .../protocol/ClientHttp2.cpp | 40 +-- src/{client => server}/protocol/ClientHttp2.h | 2 +- .../protocol/ClientProtocol.cpp | 13 +- .../protocol/ClientProtocol.h | 2 +- src/{client => server}/protocol/WebSocket.cpp | 77 ++---- src/{client => server}/protocol/WebSocket.h | 2 +- src/socket/Adapter.cpp | 14 +- src/socket/Adapter.h | 2 +- src/socket/AdapterDefault.cpp | 25 +- src/socket/AdapterDefault.h | 2 +- src/socket/AdapterTls.cpp | 43 +-- src/socket/AdapterTls.h | 2 +- src/socket/Socket.cpp | 112 +++----- src/socket/Socket.h | 10 +- src/system/System.cpp | 53 ++-- src/system/System.h | 2 +- src/transfer/AppRequest.h | 2 +- src/transfer/AppResponse.h | 2 +- src/transfer/FileIncoming.cpp | 28 +- src/transfer/FileIncoming.h | 4 +- src/transfer/HttpStatusCode.h | 2 +- src/transfer/ProtocolVariant.h | 2 +- src/transfer/http2/HPack.cpp | 220 +++++---------- src/transfer/http2/HPack.h | 2 +- src/transfer/http2/Http2.cpp | 44 +-- src/transfer/http2/Http2.h | 2 +- src/utils/Event.cpp | 44 +-- src/utils/Event.h | 2 +- src/utils/Utils.cpp | 256 ++++++------------ src/utils/Utils.h | 15 +- 43 files changed, 681 insertions(+), 796 deletions(-) create mode 100644 projects/qt-creator/httpserverapp.qbs.user rename src/{client => server}/Request.cpp (60%) rename src/{client => server}/Request.h (99%) rename src/{client => server}/Response.cpp (91%) rename src/{client => server}/Response.h (99%) rename src/{client => server}/protocol/ClientHttp1.cpp (91%) rename src/{client => server}/protocol/ClientHttp1.h (99%) rename src/{client => server}/protocol/ClientHttp2.cpp (92%) rename src/{client => server}/protocol/ClientHttp2.h (99%) rename src/{client => server}/protocol/ClientProtocol.cpp (59%) rename src/{client => server}/protocol/ClientProtocol.h (99%) rename src/{client => server}/protocol/WebSocket.cpp (80%) rename src/{client => server}/protocol/WebSocket.h (99%) diff --git a/projects/qt-creator/httpserverapp.qbs b/projects/qt-creator/httpserverapp.qbs index e12b20e..c7761f0 100644 --- a/projects/qt-creator/httpserverapp.qbs +++ b/projects/qt-creator/httpserverapp.qbs @@ -26,14 +26,14 @@ Project { "../../src/Init.h", "../../src/application/Test.cpp", "../../src/application/Test.h", - "../../src/client/protocol/ClientHttp1.cpp", - "../../src/client/protocol/ClientHttp1.h", - "../../src/client/protocol/ClientHttp2.cpp", - "../../src/client/protocol/ClientHttp2.h", - "../../src/client/protocol/ClientProtocol.cpp", - "../../src/client/protocol/ClientProtocol.h", - "../../src/client/protocol/WebSocket.cpp", - "../../src/client/protocol/WebSocket.h", + "../../src/server/protocol/ClientHttp1.cpp", + "../../src/server/protocol/ClientHttp1.h", + "../../src/server/protocol/ClientHttp2.cpp", + "../../src/server/protocol/ClientHttp2.h", + "../../src/server/protocol/ClientProtocol.cpp", + "../../src/server/protocol/ClientProtocol.h", + "../../src/server/protocol/WebSocket.cpp", + "../../src/server/protocol/WebSocket.h", "../../src/utils/Event.cpp", "../../src/utils/Event.h", "../../src/transfer/FileIncoming.cpp", @@ -45,10 +45,10 @@ Project { "../../src/transfer/HttpStatusCode.h", "../../src/Main.cpp", "../../src/Main.h", - "../../src/client/Request.cpp", - "../../src/client/Request.h", - "../../src/client/Response.cpp", - "../../src/client/Response.h", + "../../src/server/Request.cpp", + "../../src/server/Request.h", + "../../src/server/Response.cpp", + "../../src/server/Response.h", "../../src/transfer/ProtocolVariant.h", "../../src/transfer/AppRequest.h", "../../src/transfer/AppResponse.h", diff --git a/projects/qt-creator/httpserverapp.qbs.user b/projects/qt-creator/httpserverapp.qbs.user new file mode 100644 index 0000000..b2d2345 --- /dev/null +++ b/projects/qt-creator/httpserverapp.qbs.user @@ -0,0 +1,246 @@ + + + + + + EnvironmentId + {7b83e9f0-0fbd-4603-9f7e-8190cca7f8ed} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + false + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {0713182c-f672-4013-b877-de4e79ba7bda} + 0 + 0 + 0 + + /media/projects/httpserverapp/build + + + true + + Qbs (сборка) + Qbs.BuildStep + false + + debug + qtc_Desktop_d1177e0c + false + + false + false + true + 4 + false + false + + 1 + Сборка + + ProjectExplorer.BuildSteps.Build + + + + true + + Qbs (очистка) + Qbs.CleanStep + false + false + + 1 + Очистка + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Отладка + + Qbs.QbsBuildConfiguration + + + /media/projects/httpserverapp/build + + + true + + Qbs (сборка) + Qbs.BuildStep + false + + release + qtc_Desktop_d1177e0c + + false + false + true + 4 + false + false + + 1 + Сборка + + ProjectExplorer.BuildSteps.Build + + + + true + + Qbs (очистка) + Qbs.CleanStep + false + false + + 1 + Очистка + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Выпуск + + Qbs.QbsBuildConfiguration + + 2 + + + 0 + Установка + + ProjectExplorer.BuildSteps.Deploy + + 1 + Локальная установка + Установка с Qbs + Qbs.Deploy + + 1 + + + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + + %{buildDir} + Custom Executable + + ProjectExplorer.CustomExecutableRunConfiguration + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/src/Init.cpp b/src/Init.cpp index 6cd85d2..5a1a27c 100644 --- a/src/Init.cpp +++ b/src/Init.cpp @@ -7,13 +7,15 @@ #include "transfer/http2/Http2.h" #include "utils/Utils.h" -#include "client/protocol/ClientHttp1.h" -#include "client/protocol/ClientHttp2.h" +#include "server/protocol/ClientHttp1.h" +#include "server/protocol/ClientHttp2.h" + +#include +#include Socket::Adapter *createSocketAdapter(Transfer::app_request *request, void *addr) { - if (request->tls_session) - { + if (request->tls_session) { return new (addr) Socket::AdapterTls(request->tls_session); } @@ -22,37 +24,48 @@ Socket::Adapter *createSocketAdapter(Transfer::app_request *request, void *addr) void destroySocketAdapter(Socket::Adapter *adapter) { - if (adapter) - { + if (adapter) { adapter->~Adapter(); } } +std::string utf8ToLocal(const std::string &u8str) +{ + std::locale loc(""); + + std::wstring_convert > conv; + std::wstring wstr = conv.from_bytes(u8str); + + std::string str(wstr.size(), 0); + std::use_facet >(loc).narrow(wstr.data(), wstr.data() + wstr.size(), '?', &str.front() ); + + return str; +} + std::string getClearPath(const std::string &path) { const size_t pos = path.find_first_of("?#"); - if (std::string::npos == pos) - { - return Utils::urlDecode(path); - } + const std::string clean = Utils::urlDecode(std::string::npos == pos ? path : path.substr(0, pos) ); - return Utils::urlDecode(path.substr(0, pos) ); +#ifdef WIN32 + return utf8ToLocal(clean); +#else + return clean; +#endif } static void getIncomingVars(std::unordered_multimap ¶ms, const std::string &uri) { const size_t start = uri.find('?'); - if (std::string::npos == start) - { + if (std::string::npos == start) { return; } const size_t finish = uri.find('#'); - if (finish < start) - { + if (finish < start) { return; } @@ -60,8 +73,7 @@ static void getIncomingVars(std::unordered_multimap &p { var_end = uri.find('&', var_pos); - if (var_end > finish) - { + if (var_end > finish) { var_end = std::string::npos; } @@ -121,8 +133,7 @@ bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *p auto const it_cookie = headers.find("cookie"); - if (headers.cend() != it_cookie) - { + if (headers.cend() != it_cookie) { Utils::parseCookies(it_cookie->second, cookies); } @@ -171,6 +182,12 @@ bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *p src = Utils::unpackContainer(data, src); src = Utils::unpackFilesIncoming(files, src); + auto const it_cookie = headers.find("cookie"); + + if (headers.cend() != it_cookie) { + Utils::parseCookies(it_cookie->second, cookies); + } + getIncomingVars(params, path); Http2::OutStream *stream = new Http2::OutStream(stream_id, settings, Http2::DynamicTable(settings.header_table_size, settings.max_header_list_size, std::move(dynamic_table) ), mtx); @@ -180,8 +197,7 @@ bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *p break; } - default: - { + default: { success = false; break; } @@ -213,30 +229,45 @@ bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *p void freeProtocolData(HttpClient::Response *response) { - if (response) - { + if (response) { delete response->prot; } } bool isSwitchingProtocols(const HttpClient::Request &request, HttpClient::Response &response) { - if (request.prot->getSocket()->get_tls_session() != 0) - { + // Check for https is not set + if (request.prot->getSocket()->get_tls_session() != 0) { return false; } + // Check for upgrade to https + /*auto const it_upgrade_insecure = request.headers.find("upgrade-insecure-requests"); + + if (request.headers.cend() != it_upgrade_insecure) { + if (it_upgrade_insecure->second == "1") { + response.status = Http::StatusCode::MOVED_TEMPORARILY; + response.headers["location"] = "https://" + request.host + request.path; + response.headers["strict-transport-security"] = "max-age=86400"; + + const std::string headers = "HTTP/1.1 307 Moved Temporarily\r\nLocation: https://" + request.host + request.path + "\r\nStrict-Transport-Security: max-age=86400\r\n\r\n"; + + response.prot->getSocket()->nonblock_send(headers, std::chrono::milliseconds(5000) ); + + return true; + } + }*/ + + // Check if switch protocol to h2c auto const it_upgrade = request.headers.find("upgrade"); - if (request.headers.cend() == it_upgrade) - { + if (request.headers.cend() == it_upgrade) { return false; } auto const it_connection = request.headers.find("connection"); - if (request.headers.cend() == it_connection) - { + if (request.headers.cend() == it_connection) { return false; } @@ -244,33 +275,28 @@ bool isSwitchingProtocols(const HttpClient::Request &request, HttpClient::Respon bool is_upgrade = false; - for (auto &item : list) - { + for (auto &item : list) { Utils::toLower(item); - if ("upgrade" == item) - { + if ("upgrade" == item) { is_upgrade = true; break; } } - if (false == is_upgrade) - { + if (false == is_upgrade) { return false; } const std::string &upgrade = it_upgrade->second; - if ("h2c" != upgrade) - { + if ("h2c" != upgrade) { return false; } auto const it_settings = request.headers.find("http2-settings"); - if (request.headers.cend() == it_settings) - { + if (request.headers.cend() == it_settings) { return false; } diff --git a/src/Init.h b/src/Init.h index 8c85e8b..e5e56af 100644 --- a/src/Init.h +++ b/src/Init.h @@ -1,7 +1,7 @@ #pragma once -#include "client/Request.h" -#include "client/Response.h" +#include "server/Request.h" +#include "server/Response.h" #include "transfer/AppRequest.h" #include "transfer/AppResponse.h" diff --git a/src/Main.cpp b/src/Main.cpp index 2024468..c649f9e 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -22,8 +22,7 @@ EXPORT int application_call(Transfer::app_request *request, Transfer::app_respon HttpClient::Request proc_request; HttpClient::Response proc_response; - if (false == initServerObjects(&proc_request, &proc_response, request, socket_adapter) ) - { + if (false == initServerObjects(&proc_request, &proc_response, request, socket_adapter) == false) { return EXIT_FAILURE; } @@ -54,8 +53,7 @@ EXPORT int application_call(Transfer::app_request *request, Transfer::app_respon destroySocketAdapter(socket_adapter); - if (proc_response.headers.size() ) - { + if (proc_response.headers.size() ) { response->data_size = Utils::getPackContainerSize(proc_response.headers); response->response_data = new uint8_t[response->data_size]; Utils::packContainer(reinterpret_cast(response->response_data), proc_response.headers); @@ -68,8 +66,7 @@ EXPORT int application_call(Transfer::app_request *request, Transfer::app_respon EXPORT void application_clear(void *response_data, size_t response_size) { - if (response_data && response_size) - { + if (response_data && response_size) { delete[] reinterpret_cast(response_data); } } diff --git a/src/application/Test.cpp b/src/application/Test.cpp index d503da5..bf92bd3 100644 --- a/src/application/Test.cpp +++ b/src/application/Test.cpp @@ -145,4 +145,4 @@ namespace Application return EXIT_SUCCESS; } -}; +} diff --git a/src/application/Test.h b/src/application/Test.h index 66764ce..84b5260 100644 --- a/src/application/Test.h +++ b/src/application/Test.h @@ -1,9 +1,9 @@ #pragma once -#include "../client/Request.h" -#include "../client/Response.h" +#include "../server/Request.h" +#include "../server/Response.h" namespace Application { bool test(HttpClient::Request &, HttpClient::Response &); -}; +} diff --git a/src/client/Request.cpp b/src/server/Request.cpp similarity index 60% rename from src/client/Request.cpp rename to src/server/Request.cpp index c6686fc..4ce001c 100644 --- a/src/client/Request.cpp +++ b/src/server/Request.cpp @@ -3,23 +3,18 @@ namespace HttpClient { - std::string Request::getHeader(const std::string &key) const - { + std::string Request::getHeader(const std::string &key) const { auto it = headers.find(key); - - return headers.end() != it ? it->second : ""; + return headers.end() != it ? it->second : std::string(); } - bool Request::isDataExists(const std::string &key) const - { + bool Request::isDataExists(const std::string &key) const { return data.cend() != data.find(key); } - std::string Request::getDataAsString(const std::string &key) const - { + std::string Request::getDataAsString(const std::string &key) const { auto it = data.find(key); - - return data.end() != it ? it->second : ""; + return data.end() != it ? it->second : std::string(); } std::vector Request::getDataAsArray(const std::string &key) const @@ -28,16 +23,14 @@ namespace HttpClient size_t count = data.count(key); - if (count) - { + if (count) { auto range = data.equal_range(key); arr.resize(count); size_t i = 0; - for (auto it = range.first; it != range.second; ++it) - { + for (auto it = range.first; it != range.second; ++it) { arr[i++] = it->second; } } @@ -45,10 +38,8 @@ namespace HttpClient return arr; } - std::string Request::getCookieAsString(const std::string &cookieName) const - { + std::string Request::getCookieAsString(const std::string &cookieName) const { auto it = cookies.find(cookieName); - - return cookies.end() != it ? it->second : ""; + return cookies.end() != it ? it->second : std::string(); } -}; +} diff --git a/src/client/Request.h b/src/server/Request.h similarity index 99% rename from src/client/Request.h rename to src/server/Request.h index cc74368..b0a4b78 100644 --- a/src/client/Request.h +++ b/src/server/Request.h @@ -47,4 +47,4 @@ namespace HttpClient std::string getCookieAsString(const std::string &cookieName) const; }; -}; +} diff --git a/src/client/Response.cpp b/src/server/Response.cpp similarity index 91% rename from src/client/Response.cpp rename to src/server/Response.cpp index 2af748a..0be1609 100644 --- a/src/client/Response.cpp +++ b/src/server/Response.cpp @@ -7,8 +7,7 @@ namespace HttpClient { - void Response::setStatusCode(const Http::StatusCode status) - { + void Response::setStatusCode(const Http::StatusCode status) { this->status = status; } @@ -22,8 +21,7 @@ namespace HttpClient return this->prot->sendHeaders(this->status, headers, timeout, endStream); } - long Response::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const - { + long Response::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const { return this->prot->sendData(src, size, timeout, endStream); } -}; +} diff --git a/src/client/Response.h b/src/server/Response.h similarity index 99% rename from src/client/Response.h rename to src/server/Response.h index 73b3343..966e455 100644 --- a/src/client/Response.h +++ b/src/server/Response.h @@ -22,4 +22,4 @@ namespace HttpClient bool sendHeaders(const std::vector > &additional, const std::chrono::milliseconds &timeout, const bool endStream = true); long sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream = true) const; }; -}; +} diff --git a/src/client/protocol/ClientHttp1.cpp b/src/server/protocol/ClientHttp1.cpp similarity index 91% rename from src/client/protocol/ClientHttp1.cpp rename to src/server/protocol/ClientHttp1.cpp index cfa923b..fab4276 100644 --- a/src/client/protocol/ClientHttp1.cpp +++ b/src/server/protocol/ClientHttp1.cpp @@ -3,17 +3,13 @@ namespace HttpClient { - ClientHttp1::ClientHttp1(Socket::Adapter *sock) : ClientProtocol(sock) - { - - } + ClientHttp1::ClientHttp1(Socket::Adapter *sock) : ClientProtocol(sock) {} bool ClientHttp1::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const { std::string out = "HTTP/1.1 " + std::to_string(static_cast(status) ) + "\r\n"; - for (auto const &h : headers) - { + for (auto const &h : headers) { out += h.first + ": " + h.second + "\r\n"; } @@ -22,8 +18,7 @@ namespace HttpClient return this->sock->nonblock_send(out, timeout) > 0; } - long ClientHttp1::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const - { + long ClientHttp1::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const { return this->sock->nonblock_send(src, size, timeout); } -}; +} diff --git a/src/client/protocol/ClientHttp1.h b/src/server/protocol/ClientHttp1.h similarity index 99% rename from src/client/protocol/ClientHttp1.h rename to src/server/protocol/ClientHttp1.h index 556d231..ed32d81 100644 --- a/src/client/protocol/ClientHttp1.h +++ b/src/server/protocol/ClientHttp1.h @@ -12,4 +12,4 @@ namespace HttpClient virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; virtual long sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; }; -}; +} diff --git a/src/client/protocol/ClientHttp2.cpp b/src/server/protocol/ClientHttp2.cpp similarity index 92% rename from src/client/protocol/ClientHttp2.cpp rename to src/server/protocol/ClientHttp2.cpp index ac91aae..beeca42 100644 --- a/src/client/protocol/ClientHttp2.cpp +++ b/src/server/protocol/ClientHttp2.cpp @@ -14,15 +14,13 @@ namespace HttpClient } - ClientHttp2::~ClientHttp2() noexcept - { + ClientHttp2::~ClientHttp2() noexcept { delete this->stream; } static uint8_t getPaddingSize(const size_t dataSize) { - if (0 == dataSize) - { + if (0 == dataSize) { return 0; } @@ -30,8 +28,7 @@ namespace HttpClient uint8_t padding = rd(); - while (dataSize <= padding) - { + while (dataSize <= padding) { padding /= 2; } @@ -53,8 +50,7 @@ namespace HttpClient const uint8_t padding = getPaddingSize(data_size); const uint16_t padding_size = padding + sizeof(uint8_t); - if (data_size + padding_size > this->stream->settings.max_frame_size) - { + if (data_size + padding_size > this->stream->settings.max_frame_size) { data_size = this->stream->settings.max_frame_size - padding_size; } @@ -64,8 +60,7 @@ namespace HttpClient Http2::FrameFlag flags = Http2::FrameFlag::END_HEADERS; - if (endStream) - { + if (endStream) { flags |= Http2::FrameFlag::END_STREAM; } @@ -73,8 +68,7 @@ namespace HttpClient buf[Http2::FRAME_HEADER_SIZE] = padding; - if (padding) - { + if (padding) { std::fill(buf.end() - padding, buf.end(), 0); } @@ -115,8 +109,7 @@ namespace HttpClient const uint8_t padding = getPaddingSize(data_size); const uint16_t padding_size = padding + sizeof(uint8_t); - if (data_size + padding_size > this->stream->settings.max_frame_size) - { + if (data_size + padding_size > this->stream->settings.max_frame_size) { data_size = this->stream->settings.max_frame_size - padding_size; } @@ -128,8 +121,7 @@ namespace HttpClient { size_t update_size = this->stream->settings.initial_window_size + (size - total) - this->stream->window_size_out; - if (update_size > Http2::MAX_WINDOW_UPDATE) - { + if (update_size > Http2::MAX_WINDOW_UPDATE) { update_size = Http2::MAX_WINDOW_UPDATE; } @@ -140,19 +132,15 @@ namespace HttpClient Http2::FrameFlag flags = Http2::FrameFlag::EMPTY; - if (endStream && (total + data_size >= size) ) - { + if (endStream && (total + data_size >= size) ) { flags |= Http2::FrameFlag::END_STREAM; } size_t cur = Http2::FRAME_HEADER_SIZE; - if (padding_size) - { + if (padding_size) { flags |= Http2::FrameFlag::PADDED; - buf[cur] = padding; - ++cur; } @@ -160,8 +148,7 @@ namespace HttpClient std::copy(data, data + data_size, buf.begin() + cur); - if (padding) - { + if (padding) { std::fill(buf.end() - padding, buf.end(), 0); } @@ -171,8 +158,7 @@ namespace HttpClient this->stream->unlock(); - if (sended <= 0) - { + if (sended <= 0) { total = 0; break; } @@ -185,4 +171,4 @@ namespace HttpClient return static_cast(total); } -}; +} diff --git a/src/client/protocol/ClientHttp2.h b/src/server/protocol/ClientHttp2.h similarity index 99% rename from src/client/protocol/ClientHttp2.h rename to src/server/protocol/ClientHttp2.h index 9aedbca..78170a8 100644 --- a/src/client/protocol/ClientHttp2.h +++ b/src/server/protocol/ClientHttp2.h @@ -20,4 +20,4 @@ namespace HttpClient virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; virtual long sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; }; -}; +} diff --git a/src/client/protocol/ClientProtocol.cpp b/src/server/protocol/ClientProtocol.cpp similarity index 59% rename from src/client/protocol/ClientProtocol.cpp rename to src/server/protocol/ClientProtocol.cpp index ca759f1..3aff100 100644 --- a/src/client/protocol/ClientProtocol.cpp +++ b/src/server/protocol/ClientProtocol.cpp @@ -3,18 +3,13 @@ namespace HttpClient { - ClientProtocol::ClientProtocol(Socket::Adapter *sock) : sock(sock) - { + ClientProtocol::ClientProtocol(Socket::Adapter *sock) : sock(sock) {} - } - - Socket::Adapter *ClientProtocol::getSocket() noexcept - { + Socket::Adapter *ClientProtocol::getSocket() noexcept { return this->sock; } - void ClientProtocol::close() noexcept - { + void ClientProtocol::close() noexcept { this->sock->close(); } -}; +} diff --git a/src/client/protocol/ClientProtocol.h b/src/server/protocol/ClientProtocol.h similarity index 99% rename from src/client/protocol/ClientProtocol.h rename to src/server/protocol/ClientProtocol.h index 58ad9f2..9bdcd45 100644 --- a/src/client/protocol/ClientProtocol.h +++ b/src/server/protocol/ClientProtocol.h @@ -21,4 +21,4 @@ namespace HttpClient virtual void close() noexcept; }; -}; +} diff --git a/src/client/protocol/WebSocket.cpp b/src/server/protocol/WebSocket.cpp similarity index 80% rename from src/client/protocol/WebSocket.cpp rename to src/server/protocol/WebSocket.cpp index cc09ae2..f80fac4 100644 --- a/src/client/protocol/WebSocket.cpp +++ b/src/server/protocol/WebSocket.cpp @@ -10,22 +10,15 @@ namespace HttpClient { - WebSocket::WebSocket(const WebSocket &obj) noexcept : sock(obj.sock) - { - - } + WebSocket::WebSocket(const WebSocket &obj) noexcept : sock(obj.sock) {} - WebSocket::WebSocket(Socket::Adapter *adapter) noexcept : sock(adapter) - { - - } + WebSocket::WebSocket(Socket::Adapter *adapter) noexcept : sock(adapter) {} std::vector WebSocket::packDataToMessageFrame(const void *data, const size_t size) { std::vector frame; - if (0 == size) - { + if (0 == size) { return frame; } @@ -37,20 +30,16 @@ namespace HttpClient size_t cur_pos = sizeof(uint8_t) * 2; - if (size <= 125) - { + if (size <= 125) { frame[1] = size; } - else if (size <= 65536) - { + else if (size <= 65536) { frame[1] = 126; *reinterpret_cast(&frame[2]) = htons(size); cur_pos += sizeof(uint16_t); - } - else // More - { + } else { // More frame[1] = 127; *reinterpret_cast(&frame[2]) = Utils::hton64(size); @@ -65,13 +54,11 @@ namespace HttpClient return frame; } - Socket::Adapter *WebSocket::getSocket() noexcept - { + Socket::Adapter *WebSocket::getSocket() noexcept { return this->sock; } - const Socket::Adapter *WebSocket::getSocket() const noexcept - { + const Socket::Adapter *WebSocket::getSocket() const noexcept { return this->sock; } @@ -81,8 +68,7 @@ namespace HttpClient const long recv_size = this->sock->nonblock_recv(buf, timeout); - if (recv_size <= 0) - { + if (recv_size <= 0) { return recv_size; } @@ -90,8 +76,7 @@ namespace HttpClient const uint8_t info_frame = buf[0]; - if ( (info_frame & 0x08) == 0x08) // opcode 0x08 — close connection - { + if ( (info_frame & 0x08) == 0x08) { // opcode 0x08 — close connection return -1; } @@ -105,34 +90,25 @@ namespace HttpClient uint64_t frame_size; - if (info_size <= 125) - { + if (info_size <= 125) { frame_size = info_size; } - else if (info_size == 126) - { + else if (info_size == 126) { frame_size = ntohs(*reinterpret_cast(&buf[cur_pos]) ); - cur_pos += sizeof(uint16_t); - } - else // if (info_size == 127) - { + } else { // if (info_size == 127) frame_size = Utils::ntoh64(*reinterpret_cast(&buf[cur_pos]) ); - cur_pos += sizeof(uint64_t); } - if (frame_size > (buf.size() - cur_pos) ) - { + if (frame_size > (buf.size() - cur_pos) ) { return -1; // Close connection } uint32_t mask; - if (is_mask_set) - { + if (is_mask_set) { mask = *reinterpret_cast(&buf[cur_pos]); - cur_pos += sizeof(uint32_t); } @@ -142,22 +118,18 @@ namespace HttpClient frame.assign(buf.cbegin() + cur_pos, buf.cbegin() + recv_size); - if (is_mask_set) - { - if (align) - { + if (is_mask_set) { + if (align) { frame.insert(frame.cend(), align, 0); } uint32_t *addr = reinterpret_cast(frame.data() ); - for (size_t i = 0; i < frame.size() / sizeof(uint32_t); ++i) - { + for (size_t i = 0; i < frame.size() / sizeof(uint32_t); ++i) { addr[i] ^= mask; } - if (align) - { + if (align) { frame.erase(frame.cend() - align, frame.cend() ); } } @@ -169,8 +141,7 @@ namespace HttpClient { const std::vector frame = WebSocket::packDataToMessageFrame(data, length); - if (frame.empty() ) - { + if (frame.empty() ) { return 0; } @@ -181,16 +152,14 @@ namespace HttpClient { const std::vector frame = WebSocket::packDataToMessageFrame(str.data(), str.length() ); - if (frame.empty() ) - { + if (frame.empty() ) { return 0; } return this->sock->nonblock_send(frame.data(), frame.size(), timeout); } - void WebSocket::close() noexcept - { + void WebSocket::close() noexcept { this->sock->close(); } -}; +} diff --git a/src/client/protocol/WebSocket.h b/src/server/protocol/WebSocket.h similarity index 99% rename from src/client/protocol/WebSocket.h rename to src/server/protocol/WebSocket.h index 937f9f1..ad1a672 100644 --- a/src/client/protocol/WebSocket.h +++ b/src/server/protocol/WebSocket.h @@ -27,4 +27,4 @@ namespace HttpClient void close() noexcept; }; -}; +} diff --git a/src/socket/Adapter.cpp b/src/socket/Adapter.cpp index d0524b0..0c50bc3 100644 --- a/src/socket/Adapter.cpp +++ b/src/socket/Adapter.cpp @@ -3,23 +3,19 @@ namespace Socket { - long Adapter::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept - { + long Adapter::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept { return this->nonblock_recv(buf.data(), buf.size(), timeout); } - long Adapter::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const noexcept - { + long Adapter::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const noexcept { return this->nonblock_send(buf.data(), buf.length(), timeout); } - bool Adapter::operator ==(const Adapter &obj) const noexcept - { + bool Adapter::operator ==(const Adapter &obj) const noexcept { return this->get_handle() == obj.get_handle(); } - bool Adapter::operator !=(const Adapter &obj) const noexcept - { + bool Adapter::operator !=(const Adapter &obj) const noexcept { return this->get_handle() != obj.get_handle(); } -}; +} diff --git a/src/socket/Adapter.h b/src/socket/Adapter.h index 554714f..35b3964 100644 --- a/src/socket/Adapter.h +++ b/src/socket/Adapter.h @@ -30,4 +30,4 @@ namespace Socket bool operator ==(const Adapter &obj) const noexcept; bool operator !=(const Adapter &obj) const noexcept; }; -}; +} diff --git a/src/socket/AdapterDefault.cpp b/src/socket/AdapterDefault.cpp index d71d6a2..1f2fe36 100644 --- a/src/socket/AdapterDefault.cpp +++ b/src/socket/AdapterDefault.cpp @@ -3,42 +3,33 @@ namespace Socket { - AdapterDefault::AdapterDefault(const Socket &_sock) noexcept : sock(_sock) - { + AdapterDefault::AdapterDefault(const Socket &_sock) noexcept : sock(_sock) {} - } - - System::native_socket_type AdapterDefault::get_handle() const noexcept - { + System::native_socket_type AdapterDefault::get_handle() const noexcept { return sock.get_handle(); } - ::gnutls_session_t AdapterDefault::get_tls_session() const noexcept - { + ::gnutls_session_t AdapterDefault::get_tls_session() const noexcept { return 0; } - Adapter *AdapterDefault::copy() const noexcept - { + Adapter *AdapterDefault::copy() const noexcept { return new AdapterDefault(this->sock); } - long AdapterDefault::nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept - { + long AdapterDefault::nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { return sock.nonblock_recv(buf, length, timeout); } - long AdapterDefault::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept - { + long AdapterDefault::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { return sock.nonblock_send(buf, length, timeout); } - void AdapterDefault::close() noexcept - { + void AdapterDefault::close() noexcept { // Wait for send all data to client sock.nonblock_send_sync(); sock.shutdown(); sock.close(); } -}; +} diff --git a/src/socket/AdapterDefault.h b/src/socket/AdapterDefault.h index 0008fa9..d743783 100644 --- a/src/socket/AdapterDefault.h +++ b/src/socket/AdapterDefault.h @@ -23,4 +23,4 @@ namespace Socket virtual void close() noexcept override; }; -}; +} diff --git a/src/socket/AdapterTls.cpp b/src/socket/AdapterTls.cpp index 65de7f5..11bda7d 100644 --- a/src/socket/AdapterTls.cpp +++ b/src/socket/AdapterTls.cpp @@ -33,23 +33,18 @@ namespace Socket ::gnutls_alpn_set_protocols(this->session, protocols, sizeof(protocols) / sizeof(::gnutls_datum_t), 0); } - AdapterTls::AdapterTls(const ::gnutls_session_t session) noexcept : session(session) - { - - } + AdapterTls::AdapterTls(const ::gnutls_session_t session) noexcept : session(session) {} bool AdapterTls::handshake() noexcept { int ret; - do - { + do { ret = ::gnutls_handshake(this->session); } while (ret < 0 && ::gnutls_error_is_fatal(ret) == 0); - if (ret < 0) - { + if (ret < 0) { Socket sock(this->get_handle() ); sock.close(); @@ -66,8 +61,7 @@ namespace Socket // size_t record_size = ::gnutls_record_get_max_size(this->session); size_t record_size = length; - if (0 == record_size) - { + if (0 == record_size) { return -1; } @@ -77,10 +71,8 @@ namespace Socket size_t total = 0; - while (total < length) - { - if (record_size > length - total) - { + while (total < length) { + if (record_size > length - total) { record_size = length - total; } @@ -88,14 +80,12 @@ namespace Socket long send_size = 0; - do - { + do { sock.nonblock_send_sync(); } while (GNUTLS_E_AGAIN == (send_size = ::gnutls_record_send(this->session, reinterpret_cast(buf) + total, record_size) ) ); - if (send_size < 0) - { + if (send_size < 0) { return send_size; } @@ -105,18 +95,15 @@ namespace Socket return static_cast(total); } - System::native_socket_type AdapterTls::get_handle() const noexcept - { + System::native_socket_type AdapterTls::get_handle() const noexcept { return static_cast(::gnutls_transport_get_int(this->session) ); } - ::gnutls_session_t AdapterTls::get_tls_session() const noexcept - { + ::gnutls_session_t AdapterTls::get_tls_session() const noexcept { return this->session; } - Adapter *AdapterTls::copy() const noexcept - { + Adapter *AdapterTls::copy() const noexcept { return new AdapterTls(this->session); } @@ -130,13 +117,11 @@ namespace Socket return ::gnutls_record_recv(this->session, buf, length); } - long AdapterTls::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept - { + long AdapterTls::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { return this->nonblock_send_all(buf, length, timeout); } - void AdapterTls::close() noexcept - { + void AdapterTls::close() noexcept { Socket sock(this->get_handle() ); // Wait for send all data to client @@ -148,4 +133,4 @@ namespace Socket ::gnutls_deinit(this->session); } -}; +} diff --git a/src/socket/AdapterTls.h b/src/socket/AdapterTls.h index 5751b7e..27bad11 100644 --- a/src/socket/AdapterTls.h +++ b/src/socket/AdapterTls.h @@ -27,4 +27,4 @@ namespace Socket virtual void close() noexcept override; }; -}; +} diff --git a/src/socket/Socket.cpp b/src/socket/Socket.cpp index d2200bb..684cc37 100644 --- a/src/socket/Socket.cpp +++ b/src/socket/Socket.cpp @@ -48,32 +48,19 @@ namespace Socket #endif } - Socket::Socket() noexcept : socket_handle(~0) - { - - } + Socket::Socket() noexcept : socket_handle(~0) {} - Socket::Socket(const System::native_socket_type fd) noexcept : socket_handle(fd) - { - - } + Socket::Socket(const System::native_socket_type fd) noexcept : socket_handle(fd) {} - Socket::Socket(const Socket &obj) noexcept : socket_handle(obj.socket_handle) - { - - } + Socket::Socket(const Socket &obj) noexcept : socket_handle(obj.socket_handle) {} - Socket::Socket(Socket &&obj) noexcept : socket_handle(obj.socket_handle) - { + Socket::Socket(Socket &&obj) noexcept : socket_handle(obj.socket_handle) { obj.socket_handle = ~0; } - bool Socket::open() noexcept - { + bool Socket::open() noexcept { this->close(); - this->socket_handle = ::socket(AF_INET, SOCK_STREAM, 0); - return this->is_open(); } @@ -89,10 +76,8 @@ namespace Socket #error "Undefine platform" #endif - if (0 == result) - { + if (0 == result) { this->socket_handle = ~0; - return true; } } @@ -111,8 +96,7 @@ namespace Socket #endif } - System::native_socket_type Socket::get_handle() const noexcept - { + System::native_socket_type Socket::get_handle() const noexcept { return this->socket_handle; } @@ -128,8 +112,7 @@ namespace Socket return 0 == ::bind(this->socket_handle, reinterpret_cast(&sock_addr), sizeof(sockaddr_in) ); } - bool Socket::listen() const noexcept - { + bool Socket::listen() const noexcept { return 0 == ::listen(this->socket_handle, SOMAXCONN); } @@ -155,8 +138,7 @@ namespace Socket 0 }; - if (1 == ::WSAPoll(&event, 1, ~0) && event.revents & POLLRDNORM) - { + if (1 == ::WSAPoll(&event, 1, ~0) && event.revents & POLLRDNORM) { client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #elif POSIX @@ -166,8 +148,7 @@ namespace Socket 0 }; - if (1 == ::poll(&event, 1, ~0) && event.revents & POLLIN) - { + if (1 == ::poll(&event, 1, ~0) && event.revents & POLLIN) { client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #else @@ -186,8 +167,7 @@ namespace Socket 0 }; - if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLRDNORM) - { + if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLRDNORM) { client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #elif POSIX @@ -197,8 +177,7 @@ namespace Socket 0 }; - if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLIN) - { + if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLIN) { client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); } #else @@ -262,8 +241,7 @@ namespace Socket #endif } - long Socket::recv(std::vector &buf) const noexcept - { + long Socket::recv(std::vector &buf) const noexcept { return this->recv(buf.data(), buf.size() ); } @@ -278,8 +256,7 @@ namespace Socket #endif } - long Socket::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept - { + long Socket::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept { return this->nonblock_recv(buf.data(), buf.size(), timeout); } @@ -293,8 +270,7 @@ namespace Socket 0 }; - if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLRDNORM) - { + if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLRDNORM) { recv_len = ::recv(this->socket_handle, reinterpret_cast(buf), static_cast(length), 0); } #elif POSIX @@ -304,8 +280,7 @@ namespace Socket 0 }; - if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLIN) - { + if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLIN) { recv_len = ::recv(this->socket_handle, buf, length, 0); } #else @@ -341,12 +316,10 @@ namespace Socket { size_t total = 0; - while (total < length) - { + while (total < length) { const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, length - total, 0); - if (send_size < 0) - { + if (send_size < 0) { return send_size; } @@ -356,13 +329,11 @@ namespace Socket return static_cast(total); } - long Socket::send(const std::string &buf) const noexcept - { + long Socket::send(const std::string &buf) const noexcept { return this->send(buf.data(), buf.length() ); } - long Socket::send(const void *buf, const size_t length) const noexcept - { + long Socket::send(const void *buf, const size_t length) const noexcept { return send_all(this->socket_handle, buf, length); } @@ -377,21 +348,16 @@ namespace Socket 0 }; - while (total < length) - { - if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLWRNORM) - { + while (total < length) { + if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLWRNORM) { const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, static_cast(length - total), 0); - if (send_size < 0) - { + if (send_size < 0) { return send_size; } total += send_size; - } - else - { + } else { return -1; } } @@ -403,21 +369,16 @@ namespace Socket 0 }; - while (total < length) - { - if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLOUT) - { + while (total < length) { + if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLOUT) { const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, length - total, 0); - if (send_size < 0) - { + if (send_size < 0) { return send_size; } total += send_size; - } - else - { + } else { return -1; } } @@ -428,13 +389,11 @@ namespace Socket return static_cast(total); } - long Socket::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const noexcept - { + long Socket::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const noexcept { return this->nonblock_send(buf.data(), buf.length(), timeout); } - long Socket::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept - { + long Socket::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { return nonblock_send_all(this->socket_handle, buf, length, timeout); } @@ -461,19 +420,16 @@ namespace Socket #endif } - Socket &Socket::operator=(const Socket &obj) noexcept - { + Socket &Socket::operator=(const Socket &obj) noexcept { this->socket_handle = obj.socket_handle; return *this; } - bool Socket::operator ==(const Socket &obj) const noexcept - { + bool Socket::operator ==(const Socket &obj) const noexcept { return this->socket_handle == obj.socket_handle; } - bool Socket::operator !=(const Socket &obj) const noexcept - { + bool Socket::operator !=(const Socket &obj) const noexcept { return this->socket_handle != obj.socket_handle; } -}; +} diff --git a/src/socket/Socket.h b/src/socket/Socket.h index dbefb54..0952e23 100644 --- a/src/socket/Socket.h +++ b/src/socket/Socket.h @@ -66,16 +66,14 @@ namespace Socket bool operator ==(const Socket &obj) const noexcept; bool operator !=(const Socket &obj) const noexcept; }; -}; +} namespace std { // Hash for Socket - template<> struct hash - { - std::size_t operator()(const Socket::Socket &obj) const noexcept - { + template<> struct hash { + std::size_t operator()(const Socket::Socket &obj) const noexcept { return std::hash{}(obj.get_handle() ); } }; -}; +} diff --git a/src/system/System.cpp b/src/system/System.cpp index 16714d2..9dcaeb7 100644 --- a/src/system/System.cpp +++ b/src/system/System.cpp @@ -40,10 +40,8 @@ namespace System ::GetClassName(hWnd, class_name.data(), static_cast(class_name.size() - 1) ); - if (0 == ::_tcscmp(class_name.data(), myWndClassName) ) - { + if (0 == ::_tcscmp(class_name.data(), myWndClassName) ) { ed.hWnd = hWnd; - return false; } } @@ -100,8 +98,7 @@ namespace System ::EnumWindows(EnumProc, reinterpret_cast<::LPARAM>(&ed) ); - if (0 == ed.hWnd) - { + if (0 == ed.hWnd) { return false; } @@ -140,15 +137,13 @@ namespace System #elif POSIX const char *buf = ::getenv("TMPDIR"); - if (nullptr == buf) - { + if (nullptr == buf) { return std::string("/tmp/"); } std::string str(buf); - if ('/' != str.back() ) - { + if (str.back() != '/') { str.push_back('/'); } @@ -170,8 +165,7 @@ namespace System const ::DWORD attrib = ::GetFileAttributes(file_name.c_str() ); - if (INVALID_FILE_ATTRIBUTES == attrib) - { + if (INVALID_FILE_ATTRIBUTES == attrib) { return false; } @@ -179,8 +173,7 @@ namespace System #elif POSIX struct ::stat attrib; - if (-1 == ::stat(fileName.c_str(), &attrib) ) - { + if (-1 == ::stat(fileName.c_str(), &attrib) ) { return false; } @@ -202,13 +195,11 @@ namespace System const ::HANDLE hFile = ::CreateFile(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); - if (INVALID_HANDLE_VALUE == hFile) - { + if (INVALID_HANDLE_VALUE == hFile) { return false; } - if (false == ::GetFileSizeEx(hFile, reinterpret_cast<::PLARGE_INTEGER>(fileSize) ) ) - { + if (::GetFileSizeEx(hFile, reinterpret_cast<::PLARGE_INTEGER>(fileSize) ) == false) { ::CloseHandle(hFile); return false; } @@ -219,8 +210,7 @@ namespace System ::CloseHandle(hFile); - if (false == result) - { + if (false == result) { return false; } @@ -246,15 +236,14 @@ namespace System #elif POSIX struct ::stat attrib {}; - if (-1 == ::stat(filePath.c_str(), &attrib) ) - { + if (-1 == ::stat(filePath.c_str(), &attrib) ) { return false; } *fileSize = attrib.st_size; std::tm clock {}; - + ::gmtime_r(&(attrib.st_mtime), &clock); *fileTime = std::mktime(&clock); @@ -279,8 +268,7 @@ namespace System const size_t pos = memory_name.rfind(file_ext); - if (pos == memory_name.length() - file_ext.length() ) - { + if (pos == memory_name.length() - file_ext.length() ) { memory_name.erase(memory_name.begin() + pos, memory_name.end() ); } @@ -293,23 +281,18 @@ namespace System memName = buf; #endif - for (size_t i = 1; i < memName.length(); ++i) - { - if ('/' == memName[i] || '\\' == memName[i]) - { + for (size_t i = 1; i < memName.length(); ++i) { + if ('/' == memName[i] || '\\' == memName[i]) { memName[i] = '-'; } } #elif POSIX - if ('/' != memName.front() ) - { + if (memName.front() != '/') { memName = '/' + memName; } - for (size_t i = 1; i < memName.length(); ++i) - { - if ('/' == memName[i] || '\\' == memName[i]) - { + for (size_t i = 1; i < memName.length(); ++i) { + if ('/' == memName[i] || '\\' == memName[i]) { memName[i] = '-'; } } @@ -317,4 +300,4 @@ namespace System #error "Undefine platform" #endif } -}; +} diff --git a/src/system/System.h b/src/system/System.h index 1ce46d2..3b5b1bc 100644 --- a/src/system/System.h +++ b/src/system/System.h @@ -69,4 +69,4 @@ namespace System bool getFileSizeAndTimeGmt(const std::string &filePath, size_t *fileSize, time_t *fileTime); void filterSharedMemoryName(std::string &memName); -}; +} diff --git a/src/transfer/AppRequest.h b/src/transfer/AppRequest.h index 5676b34..b345a51 100644 --- a/src/transfer/AppRequest.h +++ b/src/transfer/AppRequest.h @@ -20,4 +20,4 @@ namespace Transfer const ::gnutls_session_t tls_session; const void * const request_data; }; -}; +} diff --git a/src/transfer/AppResponse.h b/src/transfer/AppResponse.h index 80937dd..51ff300 100644 --- a/src/transfer/AppResponse.h +++ b/src/transfer/AppResponse.h @@ -10,4 +10,4 @@ namespace Transfer void *response_data; size_t data_size; }; -}; +} diff --git a/src/transfer/FileIncoming.cpp b/src/transfer/FileIncoming.cpp index 58188fc..ed2c49f 100644 --- a/src/transfer/FileIncoming.cpp +++ b/src/transfer/FileIncoming.cpp @@ -27,37 +27,29 @@ namespace Transfer obj.file_size = 0; } - const std::string &FileIncoming::getTmpName() const noexcept - { + const std::string &FileIncoming::getTmpName() const noexcept { return this->file_tmp_name; } - const std::string &FileIncoming::getName() const noexcept - { + const std::string &FileIncoming::getName() const noexcept { return this->file_name; } - const std::string &FileIncoming::getType() const noexcept - { + const std::string &FileIncoming::getType() const noexcept { return this->file_type; } - size_t FileIncoming::getSize() const noexcept - { + size_t FileIncoming::getSize() const noexcept { return this->file_size; } - bool FileIncoming::isExists() const noexcept - { + bool FileIncoming::isExists() const noexcept { std::ifstream file(this->file_tmp_name, std::ifstream::binary); - const bool is_exists = file.good(); - file.close(); - return is_exists; } -}; +} namespace Utils { @@ -65,8 +57,7 @@ namespace Utils { packNumber(buf, map.size() ); - for (auto it = map.cbegin(); map.cend() != it; ++it) - { + for (auto it = map.cbegin(); map.cend() != it; ++it) { packString(buf, it->first); const Transfer::FileIncoming &file = it->second; @@ -83,8 +74,7 @@ namespace Utils size_t count; src = unpackNumber(&count, src); - for (size_t i = 0; i < count; ++i) - { + for (size_t i = 0; i < count; ++i) { std::string key; src = unpackString(key, src); @@ -105,4 +95,4 @@ namespace Utils return src; } -}; +} diff --git a/src/transfer/FileIncoming.h b/src/transfer/FileIncoming.h index 0d853eb..2568b73 100644 --- a/src/transfer/FileIncoming.h +++ b/src/transfer/FileIncoming.h @@ -31,10 +31,10 @@ namespace Transfer bool isExists() const noexcept; }; -}; +} namespace Utils { void packFilesIncoming(std::vector &buf, const std::unordered_multimap &map); const uint8_t *unpackFilesIncoming(std::unordered_multimap &map, const uint8_t *src); -}; +} diff --git a/src/transfer/HttpStatusCode.h b/src/transfer/HttpStatusCode.h index 169326a..a560814 100644 --- a/src/transfer/HttpStatusCode.h +++ b/src/transfer/HttpStatusCode.h @@ -49,4 +49,4 @@ namespace Http GATEWAY_TIMEOUT = 504, HTTP_VERSION_NOT_SUPPORTED = 505, }; -}; +} diff --git a/src/transfer/ProtocolVariant.h b/src/transfer/ProtocolVariant.h index 11954bf..fca95ef 100644 --- a/src/transfer/ProtocolVariant.h +++ b/src/transfer/ProtocolVariant.h @@ -8,4 +8,4 @@ namespace Transfer HTTP_1, HTTP_2 }; -}; +} diff --git a/src/transfer/http2/HPack.cpp b/src/transfer/http2/HPack.cpp index 60889d2..7075b2f 100644 --- a/src/transfer/http2/HPack.cpp +++ b/src/transfer/http2/HPack.cpp @@ -5214,8 +5214,7 @@ namespace HPack {"www-authenticate", ""}, }; - static constexpr size_t getStaticTableSize() noexcept - { + static constexpr size_t getStaticTableSize() noexcept { return sizeof(staticTable) / sizeof(*staticTable); } @@ -5225,8 +5224,7 @@ namespace HPack size_t n = 0; - for (size_t i = 0; i < length; ++i) - { + for (size_t i = 0; i < length; ++i) { n += huffmanSymbolTable[data[i] ].nbits; } @@ -5237,10 +5235,8 @@ namespace HPack { uint8_t nbits = sym.nbits; - for (;;) - { - if (rembits > nbits) - { + for (;;) { + if (rembits > nbits) { dest.back() |= uint8_t(sym.code << (rembits - nbits) ); rembits -= nbits; break; @@ -5251,8 +5247,7 @@ namespace HPack nbits -= rembits; rembits = 8; - if (0 == nbits) - { + if (0 == nbits) { break; } @@ -5268,22 +5263,18 @@ namespace HPack uint8_t rembits = 8; - for (size_t i = 0; i < srcSize; ++i) - { + for (size_t i = 0; i < srcSize; ++i) { const HuffmanSymbol &sym = huffmanSymbolTable[data[i] ]; - if (8 == rembits) - { + if (8 == rembits) { dest.emplace_back(0); } rembits = huffmanEncodeSymbol(dest, rembits, sym); } - if (rembits < 8) - { + if (rembits < 8) { const HuffmanSymbol &sym = huffmanSymbolTable[256]; - dest.back() |= uint8_t(sym.code >> (sym.nbits - rembits) ); } } @@ -5312,13 +5303,11 @@ namespace HPack { const HuffmanDecodeNode &node = huffmanDecodeTable[state][x]; - if (node.flags & HuffmanDecode::FAIL) - { + if (node.flags & HuffmanDecode::FAIL) { return false; } - if (node.flags & HuffmanDecode::SYMBOL) - { + if (node.flags & HuffmanDecode::SYMBOL) { dest.emplace_back(node.symbol); } @@ -5336,8 +5325,7 @@ namespace HPack { uint64_t k = (1 << prefix) - 1; - if (num < k) - { + if (num < k) { dest.emplace_back(num); return; } @@ -5346,10 +5334,8 @@ namespace HPack num -= k; - for (;;) - { - if (num < 128) - { + for (;;) { + if (num < 128) { dest.emplace_back(num); break; } @@ -5358,19 +5344,15 @@ namespace HPack num >>= 7; - if (0 == num) - { + if (0 == num) { break; } } } - static void packIndex(std::vector &dest, const size_t index) - { + static void packIndex(std::vector &dest, const size_t index) { const size_t head = dest.size(); - packInteger(dest, index, 7); - dest[head] |= 0x80; } @@ -5383,39 +5365,30 @@ namespace HPack size_t &index = std::get(result); bool &is_full_match = std::get(result); - for (size_t i = 0; i < getStaticTableSize(); ++i) - { + for (size_t i = 0; i < getStaticTableSize(); ++i) { auto const &pair = staticTable[i]; - if (pair.first == header.first) - { + if (pair.first == header.first) { index = i + 1; - if (pair.second == header.second) - { + if (pair.second == header.second) { is_full_match = true; - return result; } } - else if (0 != index) - { + else if (0 != index) { break; } } - for (size_t i = 0; i < dynamicTable.size(); ++i) - { + for (size_t i = 0; i < dynamicTable.size(); ++i) { auto const &pair = dynamicTable[i]; - if (pair.first == header.first) - { + if (pair.first == header.first) { index = i + getStaticTableSize() + 1; - if (pair.second == header.second) - { + if (pair.second == header.second) { is_full_match = true; - break; } } @@ -5426,13 +5399,11 @@ namespace HPack static uint8_t packFirstByte(const bool indexing) noexcept { - if (indexing) - { + if (indexing) { return 0x40; } - /* if (never_indexing) - { + /* if (never_indexing) { return 0x10; }*/ @@ -5443,17 +5414,14 @@ namespace HPack { const size_t huffman_length = huffmanEncodeLength(str.data(), str.length() ); - if (huffman_length < str.length() ) - { + if (huffman_length < str.length() ) { const size_t head = dest.size(); packInteger(dest, huffman_length, 7); encode(dest, str.data(), str.length() ); dest[head] |= 0x80; - } - else - { + } else { packInteger(dest, str.length(), 7); std::copy(str.cbegin(), str.cend(), std::back_inserter(dest) ); } @@ -5483,8 +5451,7 @@ namespace HPack { /* const std::string &key = header.first; - if ("content-length" == key || "set-cookie" == key) - { + if ("content-length" == key || "set-cookie" == key) { return true; }*/ @@ -5498,26 +5465,20 @@ namespace HPack std::tie(index, is_full_match) = findHeaderInTable(header, dynamicTable); - if (is_full_match) - { + if (is_full_match) { packIndex(dest, index); - return; } const bool indexing = shouldIndexing(header); - if (indexing) - { + if (indexing) { dynamicTable.addHeader(header); } - if (0 == index) - { + if (0 == index) { packFullHeader(dest, header, indexing); - } - else - { + } else { packHeaderValue(dest, index, header, indexing); } } @@ -5533,8 +5494,7 @@ namespace HPack */ void pack(std::vector &dest, const std::vector > &headers, Http2::DynamicTable &dynamicTable) { - for (auto const &header : headers) - { + for (auto const &header : headers) { packHeader(dest, header, dynamicTable); } } @@ -5562,32 +5522,27 @@ namespace HPack READ_VALUE, }; - static size_t getMaxTableIndex(const Http2::IncStream &stream) noexcept - { + static size_t getMaxTableIndex(const Http2::IncStream &stream) noexcept { return getStaticTableSize() + stream.conn.decoding_dynamic_table.size(); } static const std::pair *getHeaderFromTable(const size_t index, const Http2::IncStream &stream) noexcept { - if (getStaticTableSize() >= index) - { + if (getStaticTableSize() >= index) { return &staticTable[index - 1]; } - else if (stream.conn.decoding_dynamic_table.size() + getStaticTableSize() >= index) - { + else if (stream.conn.decoding_dynamic_table.size() + getStaticTableSize() >= index) { return &stream.conn.decoding_dynamic_table[index - getStaticTableSize() - 1]; } return nullptr; } - static const std::pair *unpackIndexed(const size_t index, const Http2::IncStream &stream) noexcept - { + static const std::pair *unpackIndexed(const size_t index, const Http2::IncStream &stream) noexcept { return getHeaderFromTable(index, stream); } - static bool checkHuffmanEncoded(const uint8_t c) noexcept - { + static bool checkHuffmanEncoded(const uint8_t c) noexcept { return c & (1 << 7); } @@ -5597,8 +5552,7 @@ namespace HPack left, false }; - if (dataSize < left) - { + if (dataSize < left) { std::get(result) = dataSize; } @@ -5609,8 +5563,7 @@ namespace HPack static uint64_t unpackString(std::vector &dest, const uint8_t *data, const size_t dataSize, uint64_t left) { - if (dataSize < left) - { + if (dataSize < left) { left = dataSize; } @@ -5637,17 +5590,14 @@ namespace HPack ++nread; - if (k != (c & k) ) - { + if (k != (c & k) ) { num = c & k; - return result; } num = k; - if (nread == dataSize) - { + if (nread == dataSize) { return result; } } @@ -5658,34 +5608,28 @@ namespace HPack uint32_t add = c & 0x7f; - if (add > (std::numeric_limits::max() >> shift) ) - { + if (add > (std::numeric_limits::max() >> shift) ) { std::get(result) = false; - return result; } add <<= shift; - if (std::numeric_limits::max() - add < num) - { + if (std::numeric_limits::max() - add < num) { std::get(result) = false; - return result; } num += add; - if (0 == (c & (1 << 7) ) ) - { + if (0 == (c & (1 << 7) ) ) { break; } shift += 7; } - if (nread != dataSize) - { + if (nread != dataSize) { ++nread; } @@ -5720,8 +5664,7 @@ namespace HPack this->buf.clear(); - if (this->index_required) - { + if (this->index_required) { stream.conn.decoding_dynamic_table.addHeader(header); } @@ -5732,8 +5675,7 @@ namespace HPack { auto entry = getHeaderFromTable(this->key_index, stream); - if (nullptr == entry) - { + if (nullptr == entry) { return std::pair(); } @@ -5745,8 +5687,7 @@ namespace HPack this->key_index = 0; this->buf.clear(); - if (this->index_required) - { + if (this->index_required) { stream.conn.decoding_dynamic_table.addHeader(header); } @@ -5770,27 +5711,20 @@ namespace HPack { const uint8_t c = data[cur]; - if (0x20 == (c & 0xe0) ) - { + if (0x20 == (c & 0xe0) ) { dec.opcode = HuffmanDecodeOpcode::INDEXED; dec.state = HuffmanDecodeState::READ_TABLE_SIZE; } - else if (c & 0x80) - { + else if (c & 0x80) { dec.opcode = HuffmanDecodeOpcode::INDEXED; dec.state = HuffmanDecodeState::READ_INDEX; - } - else - { - if (0 == c || 0x40 == c || 0x10 == c) - { + } else { + if (0 == c || 0x40 == c || 0x10 == c) { dec.opcode = HuffmanDecodeOpcode::NOT_INDEXED; dec.state = HuffmanDecodeState::CHECK_KEY_LENGTH; ++cur; - } - else - { + } else { dec.opcode = HuffmanDecodeOpcode::INDEXED_KEY; dec.state = HuffmanDecodeState::READ_INDEX; } @@ -5813,13 +5747,11 @@ namespace HPack cur += nread; - if (false == success) - { + if (false == success) { return false; } - if (dec.left > stream.conn.client_settings.header_table_size) - { + if (dec.left > stream.conn.client_settings.header_table_size) { // TODO: invalid max table size error code return false; } @@ -5835,16 +5767,12 @@ namespace HPack { uint8_t prefixlen; - if (HuffmanDecodeOpcode::INDEXED == dec.opcode) - { + if (HuffmanDecodeOpcode::INDEXED == dec.opcode) { prefixlen = 7; } - else if (dec.index_required) - { + else if (dec.index_required) { prefixlen = 6; - } - else - { + } else { prefixlen = 4; } @@ -5855,21 +5783,15 @@ namespace HPack cur += nread; - if (false == success || 0 == dec.left || dec.left > getMaxTableIndex(stream) ) - { + if (false == success || 0 == dec.left || dec.left > getMaxTableIndex(stream) ) { return false; } - if (HuffmanDecodeOpcode::INDEXED == dec.opcode) - { + if (HuffmanDecodeOpcode::INDEXED == dec.opcode) { stream.incoming_headers.emplace(*unpackIndexed(dec.left, stream) ); - dec.state = HuffmanDecodeState::OPCODE; - } - else - { + } else { dec.key_index = dec.left; - dec.state = HuffmanDecodeState::CHECK_VALUE_LENGTH; } @@ -5893,8 +5815,7 @@ namespace HPack cur += nread; - if (false == success) - { + if (false == success) { return false; } @@ -5915,8 +5836,7 @@ namespace HPack cur += nread; dec.left -= nread; - if (false == success || dec.left > 0) - { + if (false == success || dec.left > 0) { return false; } @@ -5934,8 +5854,7 @@ namespace HPack cur += nread; dec.left -= nread; - if (dec.left > 0) - { + if (dec.left > 0) { return false; } @@ -5963,8 +5882,7 @@ namespace HPack cur += nread; - if (false == success) - { + if (false == success) { return false; } @@ -5996,8 +5914,7 @@ namespace HPack cur += nread; dec.left -= nread; - if (false == success || dec.left > 0) - { + if (false == success || dec.left > 0) { return false; } @@ -6017,8 +5934,7 @@ namespace HPack cur += nread; dec.left -= nread; - if (dec.left > 0) - { + if (dec.left > 0) { return false; } @@ -6035,4 +5951,4 @@ namespace HPack return true; } -}; +} diff --git a/src/transfer/http2/HPack.h b/src/transfer/http2/HPack.h index d71375c..b467a15 100644 --- a/src/transfer/http2/HPack.h +++ b/src/transfer/http2/HPack.h @@ -12,4 +12,4 @@ namespace HPack // TODO: replace IncStream to DynamicTable if possible bool unpack(const void *src, const size_t srcSize, Http2::IncStream &stream); -}; +} diff --git a/src/transfer/http2/Http2.cpp b/src/transfer/http2/Http2.cpp index 93280ba..ed7b963 100644 --- a/src/transfer/http2/Http2.cpp +++ b/src/transfer/http2/Http2.cpp @@ -4,23 +4,19 @@ namespace Http2 { - bool operator &(const FrameFlag left, const FrameFlag right) noexcept - { + bool operator &(const FrameFlag left, const FrameFlag right) noexcept { return static_cast(left) & static_cast(right); } - FrameFlag operator |(const FrameFlag left, const FrameFlag right) noexcept - { + FrameFlag operator |(const FrameFlag left, const FrameFlag right) noexcept { return static_cast(static_cast(left) | static_cast(right) ); } - FrameFlag operator |=(FrameFlag &left, const FrameFlag right) noexcept - { + FrameFlag operator |=(FrameFlag &left, const FrameFlag right) noexcept { return static_cast(*reinterpret_cast(&left) |= static_cast(right) ); } - ConnectionSettings ConnectionSettings::defaultSettings() noexcept - { + ConnectionSettings ConnectionSettings::defaultSettings() noexcept { return ConnectionSettings { 4096, 1, @@ -37,16 +33,14 @@ namespace Http2 } - size_t DynamicTable::size() const noexcept - { + size_t DynamicTable::size() const noexcept { return this->list.size(); } DynamicTable::DynamicTable(const uint32_t headerTableSize, const uint32_t maxHeaderListSize, std::deque > &&list) noexcept : list(std::move(list) ), header_table_size(headerTableSize), max_header_list_size(maxHeaderListSize), cur_header_list_size(0) { - for (auto const &pair : list) - { + for (auto const &pair : list) { this->cur_header_list_size += pair.first.length() + pair.second.length(); } } @@ -87,8 +81,7 @@ namespace Http2 { this->header_table_size = headerTableSize; - while (this->list.size() > this->header_table_size) - { + while (this->list.size() > this->header_table_size) { auto const &pair = this->list.back(); this->cur_header_list_size -= pair.first.length() + pair.second.length(); @@ -111,18 +104,15 @@ namespace Http2 } } - const std::pair &DynamicTable::operator[](const size_t index) const noexcept - { + const std::pair &DynamicTable::operator[](const size_t index) const noexcept { return this->list[index]; } - std::pair &DynamicTable::operator[](const size_t index) noexcept - { + std::pair &DynamicTable::operator[](const size_t index) noexcept { return this->list[index]; } - const std::deque > &DynamicTable::getList() const noexcept - { + const std::deque > &DynamicTable::getList() const noexcept { return this->list; } @@ -144,13 +134,11 @@ namespace Http2 return (addr + Http2::FRAME_HEADER_SIZE); } - void IncStream::lock() - { + void IncStream::lock() { this->conn.sync.mtx.lock(); } - void IncStream::unlock() noexcept - { + void IncStream::unlock() noexcept { this->conn.sync.mtx.unlock(); } @@ -190,13 +178,11 @@ namespace Http2 return (addr + Http2::FRAME_HEADER_SIZE); } - void OutStream::lock() - { + void OutStream::lock() { this->mtx->lock(); } - void OutStream::unlock() noexcept - { + void OutStream::unlock() noexcept { this->mtx->unlock(); } -}; +} diff --git a/src/transfer/http2/Http2.h b/src/transfer/http2/Http2.h index 6647fee..12b6d65 100644 --- a/src/transfer/http2/Http2.h +++ b/src/transfer/http2/Http2.h @@ -200,4 +200,4 @@ namespace Http2 void lock(); void unlock() noexcept; }; -}; +} diff --git a/src/utils/Event.cpp b/src/utils/Event.cpp index 6b23628..a427bcf 100644 --- a/src/utils/Event.cpp +++ b/src/utils/Event.cpp @@ -11,19 +11,16 @@ namespace Utils void Event::wait() { - if (false == this->signaled.load() ) - { + if (this->signaled.load() == false) { std::unique_lock lck(this->mtx); - do - { + do { this->cv.wait(lck); } while (false == this->signaled.load() ); } - if (false == this->manually) - { + if (false == this->manually) { this->signaled.store(false); } } @@ -32,15 +29,13 @@ namespace Utils { bool is_timeout = false; - if (false == this->signaled.load() ) - { + if (this->signaled.load() == false) { std::unique_lock lck(this->mtx); is_timeout = false == this->cv.wait_for(lck, ms, [this] { return this->notifed(); } ); } - if (false == this->manually) - { + if (false == this->manually) { this->signaled.store(false); } @@ -51,14 +46,11 @@ namespace Utils { bool is_timeout = false; - if (false == this->signaled.load() ) - { + if (false == this->signaled.load() == false) { std::unique_lock lck(this->mtx); - do - { - if (std::cv_status::timeout == this->cv.wait_until(lck, tp) ) - { + do { + if (std::cv_status::timeout == this->cv.wait_until(lck, tp) ) { is_timeout = true; break; } @@ -66,37 +58,31 @@ namespace Utils while (false == this->signaled.load() ); } - if (false == this->manually) - { + if (false == this->manually) { this->signaled.store(false); } return is_timeout; } - void Event::notify() noexcept - { + void Event::notify() noexcept { this->signaled.store(true); this->cv.notify_all(); } - void Event::notify(const size_t threadsCount) noexcept - { + void Event::notify(const size_t threadsCount) noexcept { this->signaled.store(true); - for (size_t i = 0; i < threadsCount; ++i) - { + for (size_t i = 0; i < threadsCount; ++i) { this->cv.notify_one(); } } - void Event::reset() noexcept - { + void Event::reset() noexcept { this->signaled.store(false); } - bool Event::notifed() const noexcept - { + bool Event::notifed() const noexcept { return this->signaled.load(); } -}; +} diff --git a/src/utils/Event.h b/src/utils/Event.h index ddacbe4..b9d20ad 100644 --- a/src/utils/Event.h +++ b/src/utils/Event.h @@ -30,4 +30,4 @@ namespace Utils bool notifed() const noexcept; }; -}; +} diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index 9ef440e..77d8242 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -12,17 +12,13 @@ namespace Utils { - void toLower(std::string &str) noexcept - { + void toLower(std::string &str) noexcept { std::transform(str.begin(), str.end(), str.begin(), ::tolower); } - std::string getLowerString(const std::string &str) - { + std::string getLowerString(const std::string &str) { std::string copy = str; - toLower(copy); - return copy; } @@ -32,20 +28,16 @@ namespace Utils const size_t last = str.find_last_not_of(whitespace.data() ); - if (std::string::npos == last) - { + if (std::string::npos == last) { return str.clear(); } str.assign(str.cbegin() + str.find_first_not_of(whitespace.data() ), str.cbegin() + last + 1); } - std::string getTrimmedString(const std::string &str) - { + std::string getTrimmedString(const std::string &str) { std::string copy = str; - trim(copy); - return copy; } @@ -64,8 +56,7 @@ namespace Utils pos = delimiter; - if (std::string::npos != pos) - { + if (std::string::npos != pos) { ++pos; } } @@ -78,8 +69,7 @@ namespace Utils std::string buf; buf.reserve(str.length() ); - for (size_t pos = 0; pos < str.length(); ++pos) - { + for (size_t pos = 0; pos < str.length(); ++pos) { switch (str[pos]) { case '&': buf.append("&"); break; @@ -102,8 +92,7 @@ namespace Utils static const std::array hexDigits { "0123456789abcdef" }; - for (size_t i = dataSize - 1; std::numeric_limits::max() != i; --i) - { + for (size_t i = dataSize - 1; std::numeric_limits::max() != i; --i) { str[i * 2 + 0] = hexDigits[bin[i] >> 4]; str[i * 2 + 1] = hexDigits[bin[i] & 0x0F]; } @@ -113,16 +102,13 @@ namespace Utils static unsigned char hexStringToBinEncodeSymbol(const char c) noexcept { - if (c >= '0' && c <= '9') - { + if (c >= '0' && c <= '9') { return c - 0x30; } - else if (c >= 'a' && c <= 'f') - { + else if (c >= 'a' && c <= 'f') { return c - 0x57; } - else if (c >= 'A' && c <= 'F') - { + else if (c >= 'A' && c <= 'F') { return c - 0x37; } @@ -133,8 +119,7 @@ namespace Utils { std::string bin(hexStr.length() / 2, 0); - for (size_t i = 0; i < bin.length(); ++i) - { + for (size_t i = 0; i < bin.length(); ++i) { const char a = hexStr[i * 2 + 0]; const char b = hexStr[i * 2 + 1]; @@ -161,14 +146,12 @@ namespace Utils unsigned char c[sizeof(uint64_t)]; } x; - if (endian == Endianness::INIT) - { + if (endian == Endianness::INIT) { x.ull = 0x01; endian = (x.c[7] == 0x01ULL) ? Endianness::BIGE : Endianness::LITE; } - if (endian == Endianness::BIGE) - { + if (endian == Endianness::BIGE) { return host64; } @@ -184,8 +167,7 @@ namespace Utils return x.ull; } - uint64_t ntoh64(const uint64_t net64) noexcept - { + uint64_t ntoh64(const uint64_t net64) noexcept { return hton64(net64); } @@ -198,20 +180,16 @@ namespace Utils uint8_t c[sizeof(uint32_t)]; } x; - if (endian == Endianness::INIT) - { + if (endian == Endianness::INIT) { x.ui = 0x01; endian = (x.c[3] == 0x01) ? Endianness::BIGE : Endianness::LITE; } x.ui = src; - if (endian == Endianness::BIGE) - { + if (endian == Endianness::BIGE) { x.ui <<= 8; - } - else - { + } else { uint8_t c = x.c[0]; x.c[0] = x.c[2]; x.c[2] = c; @@ -229,14 +207,12 @@ namespace Utils uint8_t c[sizeof(uint32_t)]; } x; - if (endian == Endianness::INIT) - { + if (endian == Endianness::INIT) { x.ui = 0x01; endian = (x.c[3] == 0x01) ? Endianness::BIGE : Endianness::LITE; } - if (endian == Endianness::BIGE) - { + if (endian == Endianness::BIGE) { return *reinterpret_cast(src24) >> 8; } @@ -251,55 +227,44 @@ namespace Utils return x.ui;// *reinterpret_cast(x.c); } - std::string getUniqueName() - { + std::string getUniqueName() { size_t time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); - time = hton64(time); - return binToHexString(&time, sizeof(time) ); } size_t getPackNumberSize(const size_t number) noexcept { - if (number <= 253) - { + if (number <= 253) { return sizeof(uint8_t); } - else if (number <= std::numeric_limits::max() ) - { + else if (number <= std::numeric_limits::max() ) { return sizeof(uint8_t) + sizeof(uint16_t); } - else if (number <= std::numeric_limits::max() ) - { + else if (number <= std::numeric_limits::max() ) { return sizeof(uint8_t) + sizeof(uint32_t); } return sizeof(uint8_t) + sizeof(size_t); } - size_t getPackStringSize(const std::string &str) noexcept - { + size_t getPackStringSize(const std::string &str) noexcept { return getPackNumberSize(str.length() ) + str.length(); } - uint8_t *packPointer(uint8_t *dest, void *pointer) noexcept - { + uint8_t *packPointer(uint8_t *dest, void *pointer) noexcept { *reinterpret_cast(dest) = pointer; - return dest + sizeof(void *); } uint8_t *packNumber(uint8_t *dest, const size_t number) noexcept { - if (number <= 252) - { + if (number <= 252) { *dest = number; dest += sizeof(uint8_t); } - else if (number <= std::numeric_limits::max() ) - { + else if (number <= std::numeric_limits::max() ) { *dest = 253; dest += sizeof(uint8_t); @@ -308,8 +273,7 @@ namespace Utils dest += sizeof(uint16_t); } - else if (number <= std::numeric_limits::max() ) - { + else if (number <= std::numeric_limits::max() ) { *dest = 254; dest += sizeof(uint8_t); @@ -317,9 +281,7 @@ namespace Utils *reinterpret_cast(dest) = static_cast(number); dest += sizeof(uint32_t); - } - else - { + } else { *dest = 255; dest += sizeof(uint8_t); @@ -332,17 +294,13 @@ namespace Utils return dest; } - uint8_t *packString(uint8_t *dest, const std::string &str) noexcept - { + uint8_t *packString(uint8_t *dest, const std::string &str) noexcept { dest = packNumber(dest, str.length() ); - std::memcpy(dest, str.data(), str.length() ); - return dest + str.length(); } - void packPointer(std::vector &buf, void *pointer) - { + void packPointer(std::vector &buf, void *pointer) { buf.resize(buf.size() + sizeof(void *) ); uint8_t *dest = reinterpret_cast(buf.data() + buf.size() - sizeof(void *) ); *reinterpret_cast(dest) = pointer; @@ -350,28 +308,23 @@ namespace Utils void packNumber(std::vector &buf, const size_t number) { - if (number <= 252) - { + if (number <= 252) { buf.emplace_back(number); } - else if (number <= std::numeric_limits::max() ) - { + else if (number <= std::numeric_limits::max() ) { buf.emplace_back(253); buf.resize(buf.size() + sizeof(uint16_t) ); *reinterpret_cast(buf.data() + buf.size() - sizeof(uint16_t) ) = static_cast(number); } - else if (number <= std::numeric_limits::max() ) - { + else if (number <= std::numeric_limits::max() ) { buf.emplace_back(254); buf.resize(buf.size() + sizeof(uint32_t) ); *reinterpret_cast(buf.data() + buf.size() - sizeof(uint32_t) ) = static_cast(number); - } - else - { + } else { buf.emplace_back(255); buf.resize(buf.size() + sizeof(size_t) ); @@ -384,16 +337,13 @@ namespace Utils { packNumber(buf, str.length() ); - if (str.length() ) - { + if (str.length() ) { std::copy(str.cbegin(), str.cend(), std::back_inserter(buf) ); } } - const uint8_t *unpackPointer(void **pointer, const uint8_t *src) noexcept - { + const uint8_t *unpackPointer(void **pointer, const uint8_t *src) noexcept { *pointer = *reinterpret_cast(const_cast(static_cast(src) ) ); - return src + sizeof(void *); } @@ -403,26 +353,18 @@ namespace Utils src += sizeof(uint8_t); - if (*number <= 252) - { + if (*number <= 252) { } - else if (*number == 253) - { + else if (*number == 253) { *number = *reinterpret_cast(src); - src += sizeof(uint16_t); } - else if (*number == 254) - { + else if (*number == 254) { *number = *reinterpret_cast(src); - src += sizeof(uint32_t); - } - else - { + } else { *number = *reinterpret_cast(src); - src += sizeof(size_t); } @@ -465,8 +407,7 @@ namespace Utils size_t pos = strTime.find_first_not_of(' '); size_t delimiter = strTime.find(',', pos); - if (std::string::npos == delimiter || delimiter - pos != 3) - { + if (std::string::npos == delimiter || delimiter - pos != 3) { return ~0; } @@ -474,20 +415,16 @@ namespace Utils auto const it_day = map_days.find(day); - if (map_days.cend() != it_day) - { + if (map_days.cend() != it_day) { tc.tm_wday = it_day->second; - } - else - { + } else { return ~0; } pos = strTime.find_first_not_of(' ', delimiter + 1); delimiter = strTime.find_first_of(' ', pos); - if (std::string::npos == delimiter) - { + if (std::string::npos == delimiter) { return ~0; } @@ -496,8 +433,7 @@ namespace Utils pos = strTime.find_first_not_of(' ', delimiter + 1); delimiter = strTime.find_first_of(' ', pos); - if (std::string::npos == delimiter || delimiter - pos != 3) - { + if (std::string::npos == delimiter || delimiter - pos != 3) { return ~0; } @@ -505,20 +441,16 @@ namespace Utils auto const it_mon = map_months.find(month); - if (map_months.cend() != it_mon) - { + if (map_months.cend() != it_mon) { tc.tm_mon = it_mon->second; - } - else - { + } else { return ~0; } pos = strTime.find_first_not_of(' ', delimiter + 1); delimiter = strTime.find_first_of(' ', pos); - if (std::string::npos == delimiter) - { + if (std::string::npos == delimiter) { return ~0; } @@ -527,8 +459,7 @@ namespace Utils pos = strTime.find_first_not_of(' ', delimiter + 1); delimiter = strTime.find_first_of(':', pos); - if (std::string::npos == delimiter) - { + if (std::string::npos == delimiter) { return ~0; } @@ -537,8 +468,7 @@ namespace Utils pos = strTime.find_first_not_of(' ', delimiter + 1); delimiter = strTime.find_first_of(':', pos); - if (std::string::npos == delimiter) - { + if (std::string::npos == delimiter) { return ~0; } @@ -547,8 +477,7 @@ namespace Utils pos = strTime.find_first_not_of(' ', delimiter + 1); delimiter = strTime.find_first_of(' ', pos); - if (std::string::npos == delimiter) - { + if (std::string::npos == delimiter) { return ~0; } @@ -557,13 +486,11 @@ namespace Utils pos = strTime.find_first_not_of(' ', delimiter + 1); delimiter = strTime.find_first_of(' ', pos); - if (std::string::npos == delimiter) - { + if (std::string::npos == delimiter) { delimiter = strTime.length(); } - if (std::string::npos == pos || delimiter - pos > 5) - { + if (std::string::npos == pos || delimiter - pos > 5) { return ~0; } @@ -573,8 +500,7 @@ namespace Utils int timezone = 0; - if (map_zones.cend() != it_zone) - { + if (map_zones.cend() != it_zone) { timezone = it_zone->second; } else if (zone.length() == 5 && ('+' == zone.front() || '-' == zone.front() ) ) @@ -588,13 +514,10 @@ namespace Utils timezone = std::strtoul(hours.data(), nullptr, 10) * 3600; timezone += std::strtoul(minutes.data(), nullptr, 10) * 60; - if ('-' == zone.front() ) - { + if (zone.front() == '-') { timezone *= -1; } - } - else - { + } else { return ~0; } @@ -629,8 +552,7 @@ namespace Utils const char *ptrStr = std::strchr(strTime, ' '); - if (nullptr == ptrStr) - { + if (nullptr == ptrStr) { return ~0; } @@ -638,27 +560,22 @@ namespace Utils auto const it_mon = map_months.find(month); - if (map_months.cend() != it_mon) - { + if (map_months.cend() != it_mon) { tc.tm_mon = it_mon->second; - } - else - { + } else { return ~0; } ++ptrStr; // Fix for MS __DATE__ - if (' ' == *ptrStr) - { + if (' ' == *ptrStr) { ++ptrStr; } strTime = std::strchr(ptrStr, ' '); - if (nullptr == strTime) - { + if (nullptr == strTime) { return ~0; } @@ -668,8 +585,7 @@ namespace Utils ptrStr = std::strchr(strTime, ' '); - if (nullptr == ptrStr) - { + if (nullptr == ptrStr) { return ~0; } @@ -679,8 +595,7 @@ namespace Utils strTime = std::strchr(ptrStr, ':'); - if (nullptr == strTime) - { + if (nullptr == strTime) { return ~0; } @@ -690,8 +605,7 @@ namespace Utils ptrStr = std::strchr(strTime, ':'); - if (nullptr == ptrStr) - { + if (nullptr == ptrStr) { return ~0; } @@ -711,8 +625,7 @@ namespace Utils { std::array buf; - if (tTime == ~0) - { + if (tTime == ~0) { std::time(&tTime); } @@ -739,8 +652,7 @@ namespace Utils return std::string(buf.data(), buf.data() + len); } - std::string predefinedDatetimeToRfc822(const char *strTime) - { + std::string predefinedDatetimeToRfc822(const char *strTime) { const std::time_t time = predefinedDatetimeToTimestamp(strTime); return getDatetimeAsString(time, false); } @@ -749,8 +661,7 @@ namespace Utils { size_t length = 0; - do - { + do { ++length; number /= 10; } @@ -761,8 +672,7 @@ namespace Utils bool parseCookies(const std::string &cookieHeader, std::unordered_multimap &cookies) { - if (cookieHeader.empty() ) - { + if (cookieHeader.empty() ) { return true; } @@ -772,8 +682,7 @@ namespace Utils size_t delimiter = cookieHeader.find('=', cur_pos); - if (std::string::npos == delimiter || delimiter > next_value) - { + if (std::string::npos == delimiter || delimiter > next_value) { return false; } @@ -789,8 +698,7 @@ namespace Utils cookies.emplace(std::move(key), std::move(value) ); - if (std::string::npos != next_value) - { + if (std::string::npos != next_value) { ++next_value; } } @@ -798,8 +706,7 @@ namespace Utils return true; } - static inline bool isCharUrlAllowed(const char c) noexcept - { + static inline bool isCharUrlAllowed(const char c) noexcept { return c == '-' || c == '_' || c == '.' || c == '~'; } @@ -813,16 +720,12 @@ namespace Utils { const unsigned char c = str[i]; - if (std::isalnum(c) || isCharUrlAllowed(c) ) - { + if (std::isalnum(c) || isCharUrlAllowed(c) ) { encoded.push_back(c); } - else if (' ' == c) - { + else if (' ' == c) { encoded.push_back('+'); - } - else - { + } else { const uint8_t a = c >> 4; const uint8_t b = c & 0x0F; @@ -843,10 +746,8 @@ namespace Utils { unsigned char c = str[i]; - if ('%' == c) - { - if (i + 2 < str.length() ) - { + if ('%' == c) { + if (i + 2 < str.length() ) { const char a = str[++i]; const char b = str[++i]; @@ -855,8 +756,7 @@ namespace Utils ); } } - else if ('+' == c) - { + else if ('+' == c) { c = ' '; } diff --git a/src/utils/Utils.h b/src/utils/Utils.h index 9dce37a..340c6eb 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -36,8 +36,7 @@ namespace Utils { size_t full_size = getPackNumberSize(container.size() ); - for (auto const &pair : container) - { + for (auto const &pair : container) { full_size += getPackStringSize(pair.first); full_size += getPackStringSize(pair.second); } @@ -56,8 +55,7 @@ namespace Utils addr = packNumber(addr, container.size() ); - for (auto const &pair : container) - { + for (auto const &pair : container) { addr = packString(addr, pair.first); addr = packString(addr, pair.second); } @@ -74,8 +72,7 @@ namespace Utils { packNumber(buf, container.size() ); - for (auto const &pair : container) - { + for (auto const &pair : container) { packString(buf, pair.first); packString(buf, pair.second); } @@ -91,8 +88,7 @@ namespace Utils size_t count; src = unpackNumber(&count, src); - for (size_t i = 0; i < count; ++i) - { + for (size_t i = 0; i < count; ++i) { std::string key; src = unpackString(key, src); @@ -111,8 +107,7 @@ namespace Utils size_t count; src = unpackNumber(&count, src); - for (size_t i = 0; i < count; ++i) - { + for (size_t i = 0; i < count; ++i) { std::string key; src = unpackString(key, src); From 0b86e20c252955df83c7a04203c0b1511e70225a Mon Sep 17 00:00:00 2001 From: awwit Date: Sat, 11 Nov 2017 17:05:16 +0300 Subject: [PATCH 22/31] Removed dual comparison --- src/utils/Event.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/Event.cpp b/src/utils/Event.cpp index a427bcf..35771ba 100644 --- a/src/utils/Event.cpp +++ b/src/utils/Event.cpp @@ -46,7 +46,7 @@ namespace Utils { bool is_timeout = false; - if (false == this->signaled.load() == false) { + if (this->signaled.load() == false) { std::unique_lock lck(this->mtx); do { From d23825802febe981333f4f74dfbae18f9afd93ff Mon Sep 17 00:00:00 2001 From: awwit Date: Sat, 11 Nov 2017 19:50:46 +0300 Subject: [PATCH 23/31] Fixed bug in HTTP: interrupt receiving data --- projects/qt-creator/httpserverapp.qbs.user | 4 +++- src/socket/AdapterTls.cpp | 11 +++++++++-- src/socket/Socket.cpp | 8 ++++---- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/projects/qt-creator/httpserverapp.qbs.user b/projects/qt-creator/httpserverapp.qbs.user index b2d2345..0ec54d0 100644 --- a/projects/qt-creator/httpserverapp.qbs.user +++ b/projects/qt-creator/httpserverapp.qbs.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -111,6 +111,7 @@ Отладка Qbs.QbsBuildConfiguration + qtc_Desktop_d1177e0c-debug /media/projects/httpserverapp/build @@ -157,6 +158,7 @@ Выпуск Qbs.QbsBuildConfiguration + qtc_Desktop_d1177e0c-release 2 diff --git a/src/socket/AdapterTls.cpp b/src/socket/AdapterTls.cpp index 11bda7d..afd4ca2 100644 --- a/src/socket/AdapterTls.cpp +++ b/src/socket/AdapterTls.cpp @@ -112,9 +112,16 @@ namespace Socket // ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); Socket sock(this->get_handle() ); - sock.nonblock_recv_sync(); - return ::gnutls_record_recv(this->session, buf, length); + long result; + + do { + sock.nonblock_recv_sync(); + result = ::gnutls_record_recv(this->session, buf, length); + } + while (result == GNUTLS_E_AGAIN || result == GNUTLS_E_INTERRUPTED); + + return result; } long AdapterTls::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { diff --git a/src/socket/Socket.cpp b/src/socket/Socket.cpp index 684cc37..f787e31 100644 --- a/src/socket/Socket.cpp +++ b/src/socket/Socket.cpp @@ -294,7 +294,7 @@ namespace Socket #ifdef WIN32 WSAPOLLFD event = { this->socket_handle, - POLLRDNORM | POLLRDBAND, + POLLIN, 0 }; @@ -344,12 +344,12 @@ namespace Socket #ifdef WIN32 WSAPOLLFD event = { socket_handle, - POLLWRNORM, + POLLOUT, 0 }; while (total < length) { - if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLWRNORM) { + if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLOUT) { const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, static_cast(length - total), 0); if (send_size < 0) { @@ -402,7 +402,7 @@ namespace Socket #ifdef WIN32 WSAPOLLFD event = { this->socket_handle, - POLLWRNORM, + POLLOUT, 0 }; From 0aed3ce385e5925bbcb6f02a84bea46ff871699b Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Sun, 12 Nov 2017 01:57:56 +0300 Subject: [PATCH 24/31] Fixed project for MSVS. Renamed classes and namespace of protocol --- projects/msvs/httpserverapp.vcxproj | 22 ++--- projects/msvs/httpserverapp.vcxproj.filters | 30 +++--- projects/msvs/httpserverapp.vcxproj.user | 3 + src/Init.cpp | 20 ++-- src/Init.h | 6 +- src/Main.cpp | 11 +-- src/application/Test.cpp | 8 +- src/application/Test.h | 2 +- src/server/Request.cpp | 32 ++++++- src/server/Request.h | 14 ++- src/server/Response.cpp | 2 +- src/server/Response.h | 8 +- src/server/protocol/ClientProtocol.cpp | 15 --- .../{ClientHttp1.cpp => ServerHttp1.cpp} | 10 +- .../protocol/{ClientHttp1.h => ServerHttp1.h} | 8 +- .../{ClientHttp2.cpp => ServerHttp2.cpp} | 16 ++-- .../protocol/{ClientHttp2.h => ServerHttp2.h} | 10 +- src/server/protocol/ServerProtocol.cpp | 15 +++ .../{ClientProtocol.h => ServerProtocol.h} | 8 +- src/socket/List.cpp | 91 +++++++------------ src/socket/List.h | 4 +- src/transfer/FileIncoming.h | 8 +- src/utils/Event.cpp | 4 +- 23 files changed, 173 insertions(+), 174 deletions(-) delete mode 100644 src/server/protocol/ClientProtocol.cpp rename src/server/protocol/{ClientHttp1.cpp => ServerHttp1.cpp} (68%) rename src/server/protocol/{ClientHttp1.h => ServerHttp1.h} (74%) rename src/server/protocol/{ClientHttp2.cpp => ServerHttp2.cpp} (91%) rename src/server/protocol/{ClientHttp2.h => ServerHttp2.h} (74%) create mode 100644 src/server/protocol/ServerProtocol.cpp rename src/server/protocol/{ClientProtocol.h => ServerProtocol.h} (81%) diff --git a/projects/msvs/httpserverapp.vcxproj b/projects/msvs/httpserverapp.vcxproj index 7994785..cec4a76 100644 --- a/projects/msvs/httpserverapp.vcxproj +++ b/projects/msvs/httpserverapp.vcxproj @@ -20,14 +20,13 @@ - - - - - - + + + + + @@ -42,14 +41,13 @@ - - - - - - + + + + + diff --git a/projects/msvs/httpserverapp.vcxproj.filters b/projects/msvs/httpserverapp.vcxproj.filters index f082fe2..1e4277e 100644 --- a/projects/msvs/httpserverapp.vcxproj.filters +++ b/projects/msvs/httpserverapp.vcxproj.filters @@ -54,25 +54,22 @@ Source Files - - Source Files - - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files @@ -128,25 +125,22 @@ Header Files - - Header Files - - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files diff --git a/projects/msvs/httpserverapp.vcxproj.user b/projects/msvs/httpserverapp.vcxproj.user index deabe1c..223f65b 100644 --- a/projects/msvs/httpserverapp.vcxproj.user +++ b/projects/msvs/httpserverapp.vcxproj.user @@ -12,4 +12,7 @@ $(ProjectDir) WindowsLocalDebugger + + true + \ No newline at end of file diff --git a/src/Init.cpp b/src/Init.cpp index 5a1a27c..6331f07 100644 --- a/src/Init.cpp +++ b/src/Init.cpp @@ -7,8 +7,8 @@ #include "transfer/http2/Http2.h" #include "utils/Utils.h" -#include "server/protocol/ClientHttp1.h" -#include "server/protocol/ClientHttp2.h" +#include "server/protocol/ServerHttp1.h" +#include "server/protocol/ServerHttp2.h" #include #include @@ -98,14 +98,14 @@ static void getIncomingVars(std::unordered_multimap &p } } -bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *procResponse, const Transfer::app_request *request, Socket::Adapter *socket_adapter) +bool initServerObjects(HttpServer::Request *procRequest, HttpServer::Response *procResponse, const Transfer::app_request *request, Socket::Adapter *socket_adapter) { const uint8_t *src = reinterpret_cast(request->request_data); size_t protocol_number; src = Utils::unpackNumber(&protocol_number, src); Transfer::ProtocolVariant protocol_variant = static_cast(protocol_number); - HttpClient::ClientProtocol *prot = nullptr; + HttpServer::ServerProtocol *prot = nullptr; std::string document_root; std::string host; @@ -139,7 +139,7 @@ bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *p getIncomingVars(params, path); - prot = new HttpClient::ClientHttp1(socket_adapter); + prot = new HttpServer::ServerHttp1(socket_adapter); break; } @@ -192,7 +192,7 @@ bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *p Http2::OutStream *stream = new Http2::OutStream(stream_id, settings, Http2::DynamicTable(settings.header_table_size, settings.max_header_list_size, std::move(dynamic_table) ), mtx); - prot = new HttpClient::ClientHttp2(socket_adapter, stream); + prot = new HttpServer::ServerHttp2(socket_adapter, stream); break; } @@ -203,7 +203,7 @@ bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *p } } - *procRequest = HttpClient::Request { + *procRequest = HttpServer::Request { prot, std::move(document_root), std::move(host), @@ -217,7 +217,7 @@ bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *p protocol_variant }; - *procResponse = HttpClient::Response { + *procResponse = HttpServer::Response { prot, protocol_variant, std::unordered_map(), @@ -227,14 +227,14 @@ bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *p return success; } -void freeProtocolData(HttpClient::Response *response) +void freeProtocolData(HttpServer::Response *response) { if (response) { delete response->prot; } } -bool isSwitchingProtocols(const HttpClient::Request &request, HttpClient::Response &response) +bool isSwitchingProtocols(const HttpServer::Request &request, HttpServer::Response &response) { // Check for https is not set if (request.prot->getSocket()->get_tls_session() != 0) { diff --git a/src/Init.h b/src/Init.h index e5e56af..bd173b5 100644 --- a/src/Init.h +++ b/src/Init.h @@ -10,7 +10,7 @@ void destroySocketAdapter(Socket::Adapter *adapter); std::string getClearPath(const std::string &path); -bool initServerObjects(HttpClient::Request *procRequest, HttpClient::Response *procResponse, const Transfer::app_request *request, Socket::Adapter *socket_adapter); -void freeProtocolData(HttpClient::Response *response); +bool initServerObjects(HttpServer::Request *procRequest, HttpServer::Response *procResponse, const Transfer::app_request *request, Socket::Adapter *socket_adapter); +void freeProtocolData(HttpServer::Response *response); -bool isSwitchingProtocols(const HttpClient::Request &request, HttpClient::Response &response); +bool isSwitchingProtocols(const HttpServer::Request &request, HttpServer::Response &response); diff --git a/src/Main.cpp b/src/Main.cpp index c649f9e..dce743b 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,4 +1,4 @@ - + #include "Main.h" #include "Init.h" @@ -19,10 +19,10 @@ EXPORT int application_call(Transfer::app_request *request, Transfer::app_respon // Create the socket adapter Socket::Adapter *socket_adapter = createSocketAdapter(request, addr); - HttpClient::Request proc_request; - HttpClient::Response proc_response; + HttpServer::Request proc_request; + HttpServer::Response proc_response; - if (false == initServerObjects(&proc_request, &proc_response, request, socket_adapter) == false) { + if (initServerObjects(&proc_request, &proc_response, request, socket_adapter) == false) { return EXIT_FAILURE; } @@ -38,8 +38,7 @@ EXPORT int application_call(Transfer::app_request *request, Transfer::app_respon { auto it_connection = proc_request.headers.find("connection"); - if (proc_request.headers.cend() != it_connection) - { + if (proc_request.headers.cend() != it_connection) { proc_response.headers["connection"] = it_connection->second; } diff --git a/src/application/Test.cpp b/src/application/Test.cpp index bf92bd3..ece7719 100644 --- a/src/application/Test.cpp +++ b/src/application/Test.cpp @@ -5,7 +5,7 @@ namespace Application { - bool test(HttpClient::Request &request, HttpClient::Response &response) + bool test(HttpServer::Request &request, HttpServer::Response &response) { // Output incoming headers @@ -135,10 +135,8 @@ namespace Application const std::chrono::milliseconds timeout(5000); - if (response.sendHeaders(additional, timeout, s.empty() ) ) - { - if (false == s.empty() ) - { + if (response.sendHeaders(additional, timeout, s.empty() ) ) { + if (s.empty() == false) { response.sendData(s.data(), s.size(), timeout, true); } } diff --git a/src/application/Test.h b/src/application/Test.h index 84b5260..56edaf8 100644 --- a/src/application/Test.h +++ b/src/application/Test.h @@ -5,5 +5,5 @@ namespace Application { - bool test(HttpClient::Request &, HttpClient::Response &); + bool test(HttpServer::Request &, HttpServer::Response &); } diff --git a/src/server/Request.cpp b/src/server/Request.cpp index 4ce001c..c78934a 100644 --- a/src/server/Request.cpp +++ b/src/server/Request.cpp @@ -1,7 +1,7 @@ #include "Request.h" -namespace HttpClient +namespace HttpServer { std::string Request::getHeader(const std::string &key) const { auto it = headers.find(key); @@ -38,6 +38,36 @@ namespace HttpClient return arr; } + bool Request::isFileExists(const std::string &key) const { + return this->files.cend() != this->files.find(key); + } + + Transfer::FileIncoming Request::getFile(const std::string &key) const { + auto const it = this->files.find(key); + return this->files.end() != it ? it->second : Transfer::FileIncoming(); + } + + std::vector Request::getFilesAsArray(const std::string &key) const + { + std::vector arr; + + const size_t count = this->files.count(key); + + if (count) { + auto const range = this->files.equal_range(key); + + arr.resize(count); + + size_t i = 0; + + for (auto it = range.first; it != range.second; ++it) { + arr[i++] = it->second; + } + } + + return arr; + } + std::string Request::getCookieAsString(const std::string &cookieName) const { auto it = cookies.find(cookieName); return cookies.end() != it ? it->second : std::string(); diff --git a/src/server/Request.h b/src/server/Request.h index b0a4b78..1255c65 100644 --- a/src/server/Request.h +++ b/src/server/Request.h @@ -1,12 +1,12 @@ -#pragma once +#pragma once -#include "protocol/ClientProtocol.h" +#include "protocol/ServerProtocol.h" #include "../transfer/FileIncoming.h" #include "../transfer/ProtocolVariant.h" #include -namespace HttpClient +namespace HttpServer { /** * Структура запроса (входные данные) @@ -23,7 +23,7 @@ namespace HttpClient */ struct Request { - ClientProtocol *prot; + ServerProtocol *prot; std::string document_root; std::string host; std::string path; @@ -45,6 +45,12 @@ namespace HttpClient std::vector getDataAsArray(const std::string &key) const; + bool isFileExists(const std::string &key) const; + + Transfer::FileIncoming getFile(const std::string &key) const; + + std::vector getFilesAsArray(const std::string &key) const; + std::string getCookieAsString(const std::string &cookieName) const; }; } diff --git a/src/server/Response.cpp b/src/server/Response.cpp index 0be1609..481de8d 100644 --- a/src/server/Response.cpp +++ b/src/server/Response.cpp @@ -5,7 +5,7 @@ #include -namespace HttpClient +namespace HttpServer { void Response::setStatusCode(const Http::StatusCode status) { this->status = status; diff --git a/src/server/Response.h b/src/server/Response.h index 966e455..aa08bdb 100644 --- a/src/server/Response.h +++ b/src/server/Response.h @@ -1,17 +1,17 @@ -#pragma once +#pragma once -#include "protocol/ClientProtocol.h" +#include "protocol/ServerProtocol.h" #include "../transfer/ProtocolVariant.h" #include "../transfer/HttpStatusCode.h" #include #include -namespace HttpClient +namespace HttpServer { struct Response { - ClientProtocol *prot; + ServerProtocol *prot; Transfer::ProtocolVariant protocol_variant; std::unordered_map headers; Http::StatusCode status; diff --git a/src/server/protocol/ClientProtocol.cpp b/src/server/protocol/ClientProtocol.cpp deleted file mode 100644 index 3aff100..0000000 --- a/src/server/protocol/ClientProtocol.cpp +++ /dev/null @@ -1,15 +0,0 @@ - -#include "ClientProtocol.h" - -namespace HttpClient -{ - ClientProtocol::ClientProtocol(Socket::Adapter *sock) : sock(sock) {} - - Socket::Adapter *ClientProtocol::getSocket() noexcept { - return this->sock; - } - - void ClientProtocol::close() noexcept { - this->sock->close(); - } -} diff --git a/src/server/protocol/ClientHttp1.cpp b/src/server/protocol/ServerHttp1.cpp similarity index 68% rename from src/server/protocol/ClientHttp1.cpp rename to src/server/protocol/ServerHttp1.cpp index fab4276..8e3aa4a 100644 --- a/src/server/protocol/ClientHttp1.cpp +++ b/src/server/protocol/ServerHttp1.cpp @@ -1,11 +1,11 @@ -#include "ClientHttp1.h" +#include "ServerHttp1.h" -namespace HttpClient +namespace HttpServer { - ClientHttp1::ClientHttp1(Socket::Adapter *sock) : ClientProtocol(sock) {} + ServerHttp1::ServerHttp1(Socket::Adapter *sock) : ServerProtocol(sock) {} - bool ClientHttp1::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const + bool ServerHttp1::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const { std::string out = "HTTP/1.1 " + std::to_string(static_cast(status) ) + "\r\n"; @@ -18,7 +18,7 @@ namespace HttpClient return this->sock->nonblock_send(out, timeout) > 0; } - long ClientHttp1::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const { + long ServerHttp1::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const { return this->sock->nonblock_send(src, size, timeout); } } diff --git a/src/server/protocol/ClientHttp1.h b/src/server/protocol/ServerHttp1.h similarity index 74% rename from src/server/protocol/ClientHttp1.h rename to src/server/protocol/ServerHttp1.h index ed32d81..dca7aab 100644 --- a/src/server/protocol/ClientHttp1.h +++ b/src/server/protocol/ServerHttp1.h @@ -1,13 +1,13 @@ #pragma once -#include "ClientProtocol.h" +#include "ServerProtocol.h" -namespace HttpClient +namespace HttpServer { - class ClientHttp1 : public ClientProtocol + class ServerHttp1 : public ServerProtocol { public: - ClientHttp1(Socket::Adapter *sock); + ServerHttp1(Socket::Adapter *sock); virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; virtual long sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; diff --git a/src/server/protocol/ClientHttp2.cpp b/src/server/protocol/ServerHttp2.cpp similarity index 91% rename from src/server/protocol/ClientHttp2.cpp rename to src/server/protocol/ServerHttp2.cpp index beeca42..b6b8fe1 100644 --- a/src/server/protocol/ClientHttp2.cpp +++ b/src/server/protocol/ServerHttp2.cpp @@ -1,20 +1,20 @@ -#include "ClientHttp2.h" +#include "ServerHttp2.h" #include "../../transfer/http2/HPack.h" #include #include -namespace HttpClient +namespace HttpServer { - ClientHttp2::ClientHttp2(Socket::Adapter *sock, Http2::OutStream *stream) - : ClientProtocol(sock), stream(stream) + ServerHttp2::ServerHttp2(Socket::Adapter *sock, Http2::OutStream *stream) + : ServerProtocol(sock), stream(stream) { } - ClientHttp2::~ClientHttp2() noexcept { + ServerHttp2::~ServerHttp2() noexcept { delete this->stream; } @@ -35,7 +35,7 @@ namespace HttpClient return padding; } - bool ClientHttp2::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const + bool ServerHttp2::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const { std::vector buf; buf.reserve(4096); @@ -79,7 +79,7 @@ namespace HttpClient return this->sock->nonblock_send(buf.data(), buf.size(), timeout) > 0; } - void ClientHttp2::sendWindowUpdate(const uint32_t size, const std::chrono::milliseconds &timeout) const + void ServerHttp2::sendWindowUpdate(const uint32_t size, const std::chrono::milliseconds &timeout) const { std::array buf; uint8_t *addr = buf.data(); @@ -93,7 +93,7 @@ namespace HttpClient this->sock->nonblock_send(buf.data(), buf.size(), timeout); } - long ClientHttp2::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const + long ServerHttp2::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const { const uint8_t *data = reinterpret_cast(src); diff --git a/src/server/protocol/ClientHttp2.h b/src/server/protocol/ServerHttp2.h similarity index 74% rename from src/server/protocol/ClientHttp2.h rename to src/server/protocol/ServerHttp2.h index 78170a8..6fc8142 100644 --- a/src/server/protocol/ClientHttp2.h +++ b/src/server/protocol/ServerHttp2.h @@ -1,19 +1,19 @@ #pragma once -#include "ClientProtocol.h" +#include "ServerProtocol.h" #include "../../transfer/http2/Http2.h" -namespace HttpClient +namespace HttpServer { - class ClientHttp2 : public ClientProtocol + class ServerHttp2 : public ServerProtocol { protected: Http2::OutStream *stream; public: - ClientHttp2(Socket::Adapter *sock, Http2::OutStream *stream); - virtual ~ClientHttp2() noexcept; + ServerHttp2(Socket::Adapter *sock, Http2::OutStream *stream); + virtual ~ServerHttp2() noexcept; void sendWindowUpdate(const uint32_t size, const std::chrono::milliseconds &timeout) const; diff --git a/src/server/protocol/ServerProtocol.cpp b/src/server/protocol/ServerProtocol.cpp new file mode 100644 index 0000000..7396ecc --- /dev/null +++ b/src/server/protocol/ServerProtocol.cpp @@ -0,0 +1,15 @@ + +#include "ServerProtocol.h" + +namespace HttpServer +{ + ServerProtocol::ServerProtocol(Socket::Adapter *sock) : sock(sock) {} + + Socket::Adapter *ServerProtocol::getSocket() noexcept { + return this->sock; + } + + void ServerProtocol::close() noexcept { + this->sock->close(); + } +} diff --git a/src/server/protocol/ClientProtocol.h b/src/server/protocol/ServerProtocol.h similarity index 81% rename from src/server/protocol/ClientProtocol.h rename to src/server/protocol/ServerProtocol.h index 9bdcd45..5e2c5c8 100644 --- a/src/server/protocol/ClientProtocol.h +++ b/src/server/protocol/ServerProtocol.h @@ -3,16 +3,16 @@ #include "../../socket/Adapter.h" #include "../../transfer/HttpStatusCode.h" -namespace HttpClient +namespace HttpServer { - class ClientProtocol + class ServerProtocol { protected: Socket::Adapter *sock; public: - ClientProtocol(Socket::Adapter *sock); - virtual ~ClientProtocol() noexcept = default; + ServerProtocol(Socket::Adapter *sock); + virtual ~ServerProtocol() noexcept = default; Socket::Adapter *getSocket() noexcept; diff --git a/src/socket/List.cpp b/src/socket/List.cpp index 8df0b9a..c8c0e63 100644 --- a/src/socket/List.cpp +++ b/src/socket/List.cpp @@ -1,4 +1,4 @@ - + #include "List.h" #ifdef POSIX @@ -34,8 +34,7 @@ namespace Socket #endif } - List::~List() noexcept - { + List::~List() noexcept { this->destroy(); } @@ -46,8 +45,7 @@ namespace Socket #ifdef WIN32 this->obj_list = (HANDLE) 1; - if (startListSize > 0) - { + if (startListSize > 0) { this->poll_events.reserve(startListSize); } @@ -55,13 +53,11 @@ namespace Socket #elif POSIX this->obj_list = ::epoll_create(startListSize); - if (this->obj_list == ~0) - { + if (this->obj_list == ~0) { return false; } - if (startListSize > 0) - { + if (startListSize > 0) { this->epoll_events.reserve(startListSize); } @@ -101,8 +97,7 @@ namespace Socket bool List::addSocket(const Socket &sock) noexcept { - if (false == this->is_created() ) - { + if (this->is_created() == false) { return false; } @@ -124,8 +119,7 @@ namespace Socket const int result = ::epoll_ctl(this->obj_list, EPOLL_CTL_ADD, sock.get_handle(), &event); - if (result == ~0) - { + if (result == ~0) { return false; } @@ -139,16 +133,13 @@ namespace Socket bool List::removeSocket(const Socket &sock) noexcept { - if (false == this->is_created() ) - { + if (this->is_created() == false) { return false; } #ifdef WIN32 - for (size_t i = 0; i < poll_events.size(); ++i) - { - if (sock.get_handle() == poll_events[i].fd) - { + for (size_t i = 0; i < poll_events.size(); ++i) { + if (sock.get_handle() == poll_events[i].fd) { poll_events.erase(poll_events.begin() + i); return true; } @@ -158,8 +149,7 @@ namespace Socket #elif POSIX const int result = ::epoll_ctl(this->obj_list, EPOLL_CTL_DEL, sock.get_handle(), nullptr); - if (result == ~0) - { + if (result == ~0) { return false; } @@ -178,8 +168,7 @@ namespace Socket #ifdef WIN32 const int count = ::WSAPoll(this->poll_events.data(), static_cast<::ULONG>(this->poll_events.size() ), ~0); - if (SOCKET_ERROR == count) - { + if (SOCKET_ERROR == count) { return false; } @@ -191,12 +180,10 @@ namespace Socket { System::native_socket_type client_socket = ~0; - do - { + do { client_socket = ::accept(event.fd, static_cast(nullptr), static_cast(nullptr) ); - if (~0 != client_socket) - { + if (~0 != client_socket) { sockets.emplace_back(Socket(client_socket) ); } } @@ -208,8 +195,7 @@ namespace Socket #elif POSIX const int count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); - if (count == ~0) - { + if (count == ~0) { return false; } @@ -221,12 +207,10 @@ namespace Socket { System::native_socket_type client_socket = ~0; - do - { + do { client_socket = ::accept(event.data.fd, static_cast(nullptr), static_cast(nullptr) ); - if (~0 != client_socket) - { + if (~0 != client_socket) { sockets.emplace_back(Socket(client_socket) ); } } @@ -250,8 +234,7 @@ namespace Socket #ifdef WIN32 const int count = ::WSAPoll(this->poll_events.data(), static_cast<::ULONG>(this->poll_events.size() ), ~0); - if (SOCKET_ERROR == count) - { + if (SOCKET_ERROR == count) { return false; } @@ -263,15 +246,13 @@ namespace Socket { System::native_socket_type client_socket = ~0; - do - { + do { ::sockaddr_in client_addr {}; socklen_t client_addr_len = sizeof(client_addr); client_socket = ::accept(event.fd, reinterpret_cast<::sockaddr *>(&client_addr), &client_addr_len); - if (~0 != client_socket) - { + if (~0 != client_socket) { sockets.emplace_back(Socket(client_socket) ); socketsAddress.emplace_back(client_addr); } @@ -284,8 +265,7 @@ namespace Socket #elif POSIX const int count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); - if (count == ~0) - { + if (count == ~0) { return false; } @@ -297,15 +277,13 @@ namespace Socket { System::native_socket_type client_socket = ~0; - do - { + do { ::sockaddr_in client_addr {}; socklen_t client_addr_len = sizeof(client_addr); client_socket = ::accept(event.data.fd, reinterpret_cast<::sockaddr *>(&client_addr), &client_addr_len); - if (~0 != client_socket) - { + if (~0 != client_socket) { sockets.emplace_back(Socket(client_socket) ); socketsAddress.emplace_back(client_addr); } @@ -325,16 +303,14 @@ namespace Socket bool List::recv(std::vector &sockets, std::vector &disconnected, std::chrono::milliseconds timeout) const noexcept { - if (false == this->is_created() ) - { + if (this->is_created() == false) { return false; } #ifdef WIN32 const int count = ::WSAPoll(this->poll_events.data(), static_cast<::ULONG>(this->poll_events.size() ), static_cast<::INT>(timeout.count() ) ); - if (SOCKET_ERROR == count) - { + if (SOCKET_ERROR == count) { return false; } @@ -342,12 +318,10 @@ namespace Socket { const WSAPOLLFD &event = this->poll_events[i]; - if (event.revents & POLLRDNORM) - { + if (event.revents & POLLRDNORM) { sockets.emplace_back(Socket(event.fd) ); } - else if (event.revents & POLLHUP) - { + else if (event.revents & POLLHUP) { disconnected.emplace_back(Socket(event.fd) ); } } @@ -356,8 +330,7 @@ namespace Socket #elif POSIX const int count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), timeout.count() ); - if (count == ~0) - { + if (count == ~0) { return false; } @@ -365,12 +338,10 @@ namespace Socket { const epoll_event &event = this->epoll_events[i]; - if (event.events & EPOLLIN) - { + if (event.events & EPOLLIN) { sockets.emplace_back(Socket(event.data.fd) ); } - else if (event.events & EPOLLRDHUP) - { + else if (event.events & EPOLLRDHUP) { disconnected.emplace_back(Socket(event.data.fd) ); } } @@ -380,4 +351,4 @@ namespace Socket #error "Undefine platform" #endif } -}; +} diff --git a/src/socket/List.h b/src/socket/List.h index 650447f..e687134 100644 --- a/src/socket/List.h +++ b/src/socket/List.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Socket.h" @@ -40,4 +40,4 @@ namespace Socket bool recv(std::vector &sockets, std::vector &errors, std::chrono::milliseconds timeout = std::chrono::milliseconds(~0) ) const noexcept; }; -}; +} diff --git a/src/transfer/FileIncoming.h b/src/transfer/FileIncoming.h index 2568b73..8070d0d 100644 --- a/src/transfer/FileIncoming.h +++ b/src/transfer/FileIncoming.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -14,16 +14,16 @@ namespace Transfer std::string file_type; size_t file_size; - private: - FileIncoming() = delete; - public: + FileIncoming() = default; FileIncoming(std::string &&fileTmpName, std::string &&fileName, std::string &&fileType, const size_t fileSize) noexcept; FileIncoming(const FileIncoming &obj); FileIncoming(FileIncoming &&obj) noexcept; ~FileIncoming() noexcept = default; + FileIncoming &operator =(const FileIncoming &) = default; + const std::string &getTmpName() const noexcept; const std::string &getName() const noexcept; const std::string &getType() const noexcept; diff --git a/src/utils/Event.cpp b/src/utils/Event.cpp index 35771ba..4c4c04a 100644 --- a/src/utils/Event.cpp +++ b/src/utils/Event.cpp @@ -17,7 +17,7 @@ namespace Utils do { this->cv.wait(lck); } - while (false == this->signaled.load() ); + while (this->signaled.load() == false); } if (false == this->manually) { @@ -55,7 +55,7 @@ namespace Utils break; } } - while (false == this->signaled.load() ); + while (this->signaled.load() == false); } if (false == this->manually) { From e68d77f8bca7fb01b65d5640a4ae10d8e34f88df Mon Sep 17 00:00:00 2001 From: awwit Date: Sun, 12 Nov 2017 02:03:12 +0300 Subject: [PATCH 25/31] Fixed project for QtCreator --- projects/qt-creator/httpserverapp.qbs | 12 ++++++------ projects/qt-creator/httpserverapp.qbs.user | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/projects/qt-creator/httpserverapp.qbs b/projects/qt-creator/httpserverapp.qbs index c7761f0..56d90fc 100644 --- a/projects/qt-creator/httpserverapp.qbs +++ b/projects/qt-creator/httpserverapp.qbs @@ -26,12 +26,12 @@ Project { "../../src/Init.h", "../../src/application/Test.cpp", "../../src/application/Test.h", - "../../src/server/protocol/ClientHttp1.cpp", - "../../src/server/protocol/ClientHttp1.h", - "../../src/server/protocol/ClientHttp2.cpp", - "../../src/server/protocol/ClientHttp2.h", - "../../src/server/protocol/ClientProtocol.cpp", - "../../src/server/protocol/ClientProtocol.h", + "../../src/server/protocol/ServerHttp1.cpp", + "../../src/server/protocol/ServerHttp1.h", + "../../src/server/protocol/ServerHttp2.cpp", + "../../src/server/protocol/ServerHttp2.h", + "../../src/server/protocol/ServerProtocol.cpp", + "../../src/server/protocol/ServerProtocol.h", "../../src/server/protocol/WebSocket.cpp", "../../src/server/protocol/WebSocket.h", "../../src/utils/Event.cpp", diff --git a/projects/qt-creator/httpserverapp.qbs.user b/projects/qt-creator/httpserverapp.qbs.user index 0ec54d0..6e36627 100644 --- a/projects/qt-creator/httpserverapp.qbs.user +++ b/projects/qt-creator/httpserverapp.qbs.user @@ -1,6 +1,6 @@ - + EnvironmentId From 51f8d206489ef7541c9cc03234cc1033166e338a Mon Sep 17 00:00:00 2001 From: awwit Date: Mon, 13 Nov 2017 02:33:01 +0300 Subject: [PATCH 26/31] Fixed interruption of data reception over HTTPS --- projects/qt-creator/httpserverapp.qbs.user | 248 --------------------- src/socket/AdapterTls.cpp | 7 +- src/socket/List.cpp | 2 +- src/socket/List.h | 2 +- src/socket/Socket.cpp | 6 +- src/socket/Socket.h | 2 +- src/utils/Event.cpp | 2 +- 7 files changed, 11 insertions(+), 258 deletions(-) delete mode 100644 projects/qt-creator/httpserverapp.qbs.user diff --git a/projects/qt-creator/httpserverapp.qbs.user b/projects/qt-creator/httpserverapp.qbs.user deleted file mode 100644 index 6e36627..0000000 --- a/projects/qt-creator/httpserverapp.qbs.user +++ /dev/null @@ -1,248 +0,0 @@ - - - - - - EnvironmentId - {7b83e9f0-0fbd-4603-9f7e-8190cca7f8ed} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - true - false - 0 - true - true - 0 - 8 - true - 1 - false - true - true - false - - - - ProjectExplorer.Project.PluginSettings - - - - ProjectExplorer.Project.Target.0 - - Desktop - Desktop - {0713182c-f672-4013-b877-de4e79ba7bda} - 0 - 0 - 0 - - /media/projects/httpserverapp/build - - - true - - Qbs (сборка) - Qbs.BuildStep - false - - debug - qtc_Desktop_d1177e0c - false - - false - false - true - 4 - false - false - - 1 - Сборка - - ProjectExplorer.BuildSteps.Build - - - - true - - Qbs (очистка) - Qbs.CleanStep - false - false - - 1 - Очистка - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Отладка - - Qbs.QbsBuildConfiguration - qtc_Desktop_d1177e0c-debug - - - /media/projects/httpserverapp/build - - - true - - Qbs (сборка) - Qbs.BuildStep - false - - release - qtc_Desktop_d1177e0c - - false - false - true - 4 - false - false - - 1 - Сборка - - ProjectExplorer.BuildSteps.Build - - - - true - - Qbs (очистка) - Qbs.CleanStep - false - false - - 1 - Очистка - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Выпуск - - Qbs.QbsBuildConfiguration - qtc_Desktop_d1177e0c-release - - 2 - - - 0 - Установка - - ProjectExplorer.BuildSteps.Deploy - - 1 - Локальная установка - Установка с Qbs - Qbs.Deploy - - 1 - - - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - 2 - - - - %{buildDir} - Custom Executable - - ProjectExplorer.CustomExecutableRunConfiguration - 3768 - false - true - false - false - true - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 18 - - - Version - 18 - - diff --git a/src/socket/AdapterTls.cpp b/src/socket/AdapterTls.cpp index afd4ca2..b725d37 100644 --- a/src/socket/AdapterTls.cpp +++ b/src/socket/AdapterTls.cpp @@ -82,8 +82,9 @@ namespace Socket do { sock.nonblock_send_sync(); + send_size = ::gnutls_record_send(this->session, reinterpret_cast(buf) + total, record_size); } - while (GNUTLS_E_AGAIN == (send_size = ::gnutls_record_send(this->session, reinterpret_cast(buf) + total, record_size) ) ); + while (GNUTLS_E_AGAIN == send_size); if (send_size < 0) { return send_size; @@ -116,10 +117,10 @@ namespace Socket long result; do { - sock.nonblock_recv_sync(); + sock.nonblock_recv_sync(timeout); result = ::gnutls_record_recv(this->session, buf, length); } - while (result == GNUTLS_E_AGAIN || result == GNUTLS_E_INTERRUPTED); + while (result == GNUTLS_E_INTERRUPTED); return result; } diff --git a/src/socket/List.cpp b/src/socket/List.cpp index c8c0e63..1746a79 100644 --- a/src/socket/List.cpp +++ b/src/socket/List.cpp @@ -1,4 +1,4 @@ - + #include "List.h" #ifdef POSIX diff --git a/src/socket/List.h b/src/socket/List.h index e687134..19f83b0 100644 --- a/src/socket/List.h +++ b/src/socket/List.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Socket.h" diff --git a/src/socket/Socket.cpp b/src/socket/Socket.cpp index f787e31..2edb3d0 100644 --- a/src/socket/Socket.cpp +++ b/src/socket/Socket.cpp @@ -289,7 +289,7 @@ namespace Socket return recv_len; } - void Socket::nonblock_recv_sync() const noexcept + void Socket::nonblock_recv_sync(const std::chrono::milliseconds &timeout) const noexcept { #ifdef WIN32 WSAPOLLFD event = { @@ -298,7 +298,7 @@ namespace Socket 0 }; - ::WSAPoll(&event, 1, ~0); + ::WSAPoll(&event, 1, timeout.count() ); #elif POSIX struct ::pollfd event = { this->socket_handle, @@ -306,7 +306,7 @@ namespace Socket 0 }; - ::poll(&event, 1, ~0); + ::poll(&event, 1, timeout.count() ); #else #error "Undefine platform" #endif diff --git a/src/socket/Socket.h b/src/socket/Socket.h index 0952e23..a2d0151 100644 --- a/src/socket/Socket.h +++ b/src/socket/Socket.h @@ -51,7 +51,7 @@ namespace Socket long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept; long nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept; - void nonblock_recv_sync() const noexcept; + void nonblock_recv_sync(const std::chrono::milliseconds &timeout) const noexcept; long send(const std::string &buf) const noexcept; long send(const void *buf, const size_t length) const noexcept; diff --git a/src/utils/Event.cpp b/src/utils/Event.cpp index 4c4c04a..d768a8e 100644 --- a/src/utils/Event.cpp +++ b/src/utils/Event.cpp @@ -32,7 +32,7 @@ namespace Utils if (this->signaled.load() == false) { std::unique_lock lck(this->mtx); - is_timeout = false == this->cv.wait_for(lck, ms, [this] { return this->notifed(); } ); + is_timeout = this->cv.wait_for(lck, ms, [this] { return this->notifed(); } ) == false; } if (false == this->manually) { From cdbba5c4fc6d2f2a57a7cc3af54799c6c5472a97 Mon Sep 17 00:00:00 2001 From: awwit Date: Mon, 13 Nov 2017 03:47:22 +0300 Subject: [PATCH 27/31] Final solution for stopping an interruption of data reception --- src/socket/AdapterTls.cpp | 13 +++++++------ src/socket/Socket.cpp | 6 +++--- src/socket/Socket.h | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/socket/AdapterTls.cpp b/src/socket/AdapterTls.cpp index b725d37..b63bf73 100644 --- a/src/socket/AdapterTls.cpp +++ b/src/socket/AdapterTls.cpp @@ -76,8 +76,6 @@ namespace Socket record_size = length - total; } - // const long send_size = ::gnutls_record_send(this->session, reinterpret_cast(buf) + total, record_size); - long send_size = 0; do { @@ -110,17 +108,20 @@ namespace Socket long AdapterTls::nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { - // ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); - Socket sock(this->get_handle() ); long result; do { - sock.nonblock_recv_sync(timeout); + if (sock.nonblock_recv_sync(timeout) == false) { + // Timeout + result = -1; + break; + } + result = ::gnutls_record_recv(this->session, buf, length); } - while (result == GNUTLS_E_INTERRUPTED); + while (GNUTLS_E_AGAIN == result || GNUTLS_E_INTERRUPTED == result); return result; } diff --git a/src/socket/Socket.cpp b/src/socket/Socket.cpp index 2edb3d0..96bd194 100644 --- a/src/socket/Socket.cpp +++ b/src/socket/Socket.cpp @@ -289,7 +289,7 @@ namespace Socket return recv_len; } - void Socket::nonblock_recv_sync(const std::chrono::milliseconds &timeout) const noexcept + bool Socket::nonblock_recv_sync(const std::chrono::milliseconds &timeout) const noexcept { #ifdef WIN32 WSAPOLLFD event = { @@ -298,7 +298,7 @@ namespace Socket 0 }; - ::WSAPoll(&event, 1, timeout.count() ); + return ::WSAPoll(&event, 1, timeout.count() ) == 1; #elif POSIX struct ::pollfd event = { this->socket_handle, @@ -306,7 +306,7 @@ namespace Socket 0 }; - ::poll(&event, 1, timeout.count() ); + return ::poll(&event, 1, timeout.count() ) == 1; #else #error "Undefine platform" #endif diff --git a/src/socket/Socket.h b/src/socket/Socket.h index a2d0151..e0bfc6c 100644 --- a/src/socket/Socket.h +++ b/src/socket/Socket.h @@ -51,7 +51,7 @@ namespace Socket long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept; long nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept; - void nonblock_recv_sync(const std::chrono::milliseconds &timeout) const noexcept; + bool nonblock_recv_sync(const std::chrono::milliseconds &timeout) const noexcept; long send(const std::string &buf) const noexcept; long send(const void *buf, const size_t length) const noexcept; From ed44f7a4eec2a31b71649fcb93cfbb3dc8280654 Mon Sep 17 00:00:00 2001 From: awwit Date: Sun, 26 Nov 2017 18:48:17 +0300 Subject: [PATCH 28/31] fix make error in ubuntu system --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2451e56..5900f8e 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ $(BUILDDIR): $(MKDIR) $@ $(EXECUTABLE): $(OBJECTS) - $(CXX) $(LDFLAGS) $(OBJECTS) -o $@ + $(CXX) $(OBJECTS) -o $@ $(LDFLAGS) $(OBJECTS) : $(OBJDIR)/%.o : $(SOURCEDIR)/%.cpp @$(MKDIR) $(dir $@) From 0fb04b16c9ca12c85132c84ba4456fe9d724fd5d Mon Sep 17 00:00:00 2001 From: awwit Date: Sat, 13 Jan 2018 18:11:01 +0300 Subject: [PATCH 29/31] Fixed bug in function `getPackNumberSize` (which caused the crash application in one case) --- src/utils/Utils.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index 77d8242..4ddc424 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -233,9 +233,14 @@ namespace Utils return binToHexString(&time, sizeof(time) ); } + constexpr uint8_t PACK_NUMBER_SIZE_BYTE = 252; + constexpr uint8_t PACK_NUMBER_SIZE_16 = 253; + constexpr uint8_t PACK_NUMBER_SIZE_32 = 254; + constexpr uint8_t PACK_NUMBER_SIZE_MAX = 255; + size_t getPackNumberSize(const size_t number) noexcept { - if (number <= 253) { + if (number <= PACK_NUMBER_SIZE_BYTE) { return sizeof(uint8_t); } else if (number <= std::numeric_limits::max() ) { @@ -259,13 +264,13 @@ namespace Utils uint8_t *packNumber(uint8_t *dest, const size_t number) noexcept { - if (number <= 252) { + if (number <= PACK_NUMBER_SIZE_BYTE) { *dest = number; dest += sizeof(uint8_t); } else if (number <= std::numeric_limits::max() ) { - *dest = 253; + *dest = PACK_NUMBER_SIZE_16; dest += sizeof(uint8_t); @@ -274,7 +279,7 @@ namespace Utils dest += sizeof(uint16_t); } else if (number <= std::numeric_limits::max() ) { - *dest = 254; + *dest = PACK_NUMBER_SIZE_32; dest += sizeof(uint8_t); @@ -282,7 +287,7 @@ namespace Utils dest += sizeof(uint32_t); } else { - *dest = 255; + *dest = PACK_NUMBER_SIZE_MAX; dest += sizeof(uint8_t); @@ -308,24 +313,24 @@ namespace Utils void packNumber(std::vector &buf, const size_t number) { - if (number <= 252) { + if (number <= PACK_NUMBER_SIZE_BYTE) { buf.emplace_back(number); } else if (number <= std::numeric_limits::max() ) { - buf.emplace_back(253); + buf.emplace_back(PACK_NUMBER_SIZE_16); buf.resize(buf.size() + sizeof(uint16_t) ); *reinterpret_cast(buf.data() + buf.size() - sizeof(uint16_t) ) = static_cast(number); } else if (number <= std::numeric_limits::max() ) { - buf.emplace_back(254); + buf.emplace_back(PACK_NUMBER_SIZE_32); buf.resize(buf.size() + sizeof(uint32_t) ); *reinterpret_cast(buf.data() + buf.size() - sizeof(uint32_t) ) = static_cast(number); } else { - buf.emplace_back(255); + buf.emplace_back(PACK_NUMBER_SIZE_MAX); buf.resize(buf.size() + sizeof(size_t) ); @@ -353,14 +358,14 @@ namespace Utils src += sizeof(uint8_t); - if (*number <= 252) { + if (*number <= PACK_NUMBER_SIZE_BYTE) { } - else if (*number == 253) { + else if (*number == PACK_NUMBER_SIZE_16) { *number = *reinterpret_cast(src); src += sizeof(uint16_t); } - else if (*number == 254) { + else if (*number == PACK_NUMBER_SIZE_32) { *number = *reinterpret_cast(src); src += sizeof(uint32_t); } else { From 913be66a6df3eed9d6805add3044b97d50f93cc0 Mon Sep 17 00:00:00 2001 From: awwit Date: Mon, 2 Apr 2018 17:09:19 +0300 Subject: [PATCH 30/31] Optimized some copy operations. Fixed many warnings in code. Changed code style. --- src/Init.cpp | 136 ++++++++---- src/Init.h | 19 +- src/Main.cpp | 26 ++- src/application/Test.cpp | 6 +- src/application/Test.h | 5 +- src/server/Response.cpp | 51 ++++- src/server/Response.h | 16 +- src/server/protocol/ServerHttp1.cpp | 27 ++- src/server/protocol/ServerHttp1.h | 17 +- src/server/protocol/ServerHttp2.cpp | 121 +++++++--- src/server/protocol/ServerHttp2.h | 28 ++- src/server/protocol/ServerProtocol.cpp | 6 +- src/server/protocol/ServerProtocol.h | 17 +- src/socket/Adapter.cpp | 22 +- src/socket/Adapter.h | 26 ++- src/socket/AdapterDefault.cpp | 16 +- src/socket/AdapterDefault.h | 13 +- src/socket/AdapterTls.cpp | 46 ++-- src/socket/AdapterTls.h | 28 ++- src/socket/List.cpp | 126 ++++++++--- src/socket/List.h | 18 +- src/socket/Socket.cpp | 291 +++++++++++++++++-------- src/socket/Socket.h | 43 +++- src/system/System.cpp | 62 ++++-- src/system/System.h | 40 ++-- src/transfer/AppRequest.h | 6 +- src/transfer/AppResponse.h | 3 +- src/transfer/FileIncoming.cpp | 47 +++- src/transfer/FileIncoming.h | 22 +- src/transfer/HttpStatusCode.h | 3 +- src/transfer/ProtocolVariant.h | 3 +- src/transfer/http2/HPack.cpp | 258 +++++++++++++++------- src/transfer/http2/HPack.h | 12 +- src/transfer/http2/Http2.cpp | 115 +++++++--- src/transfer/http2/Http2.h | 79 ++++--- src/utils/Event.cpp | 9 +- src/utils/Utils.cpp | 136 ++++++++---- src/utils/Utils.h | 5 +- 38 files changed, 1366 insertions(+), 538 deletions(-) diff --git a/src/Init.cpp b/src/Init.cpp index 6331f07..0831bdb 100644 --- a/src/Init.cpp +++ b/src/Init.cpp @@ -13,8 +13,10 @@ #include #include -Socket::Adapter *createSocketAdapter(Transfer::app_request *request, void *addr) -{ +Socket::Adapter *createSocketAdapter( + Transfer::app_request *request, + void *addr +) { if (request->tls_session) { return new (addr) Socket::AdapterTls(request->tls_session); } @@ -22,8 +24,7 @@ Socket::Adapter *createSocketAdapter(Transfer::app_request *request, void *addr) return new (addr) Socket::AdapterDefault(request->socket); } -void destroySocketAdapter(Socket::Adapter *adapter) -{ +void destroySocketAdapter(Socket::Adapter *adapter) { if (adapter) { adapter->~Adapter(); } @@ -37,7 +38,13 @@ std::string utf8ToLocal(const std::string &u8str) std::wstring wstr = conv.from_bytes(u8str); std::string str(wstr.size(), 0); - std::use_facet >(loc).narrow(wstr.data(), wstr.data() + wstr.size(), '?', &str.front() ); + + std::use_facet >(loc).narrow( + wstr.data(), + wstr.data() + wstr.size(), + '?', + &str.front() + ); return str; } @@ -46,7 +53,11 @@ std::string getClearPath(const std::string &path) { const size_t pos = path.find_first_of("?#"); - const std::string clean = Utils::urlDecode(std::string::npos == pos ? path : path.substr(0, pos) ); + const std::string clean = Utils::urlDecode( + std::string::npos == pos + ? path + : path.substr(0, pos) + ); #ifdef WIN32 return utf8ToLocal(clean); @@ -55,8 +66,10 @@ std::string getClearPath(const std::string &path) #endif } -static void getIncomingVars(std::unordered_multimap ¶ms, const std::string &uri) -{ +static void getIncomingVars( + std::unordered_multimap ¶ms, + const std::string &uri +) { const size_t start = uri.find('?'); if (std::string::npos == start) { @@ -69,8 +82,11 @@ static void getIncomingVars(std::unordered_multimap &p return; } - for (size_t var_pos = start + 1, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) - { + for ( + size_t var_pos = start + 1, var_end = 0; + std::string::npos != var_end; + var_pos = var_end + 1 + ) { var_end = uri.find('&', var_pos); if (var_end > finish) { @@ -79,27 +95,53 @@ static void getIncomingVars(std::unordered_multimap &p size_t delimiter = uri.find('=', var_pos); - if (delimiter >= var_end) - { - std::string var_name = Utils::urlDecode(uri.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos) ); - - params.emplace(std::move(var_name), std::string() ); - } - else - { - std::string var_name = Utils::urlDecode(uri.substr(var_pos, delimiter - var_pos) ); + if (delimiter >= var_end) { + std::string var_name = Utils::urlDecode( + uri.substr( + var_pos, + std::string::npos != var_end + ? var_end - var_pos + : std::string::npos + ) + ); + + params.emplace( + std::move(var_name), + std::string() + ); + } else { + std::string var_name = Utils::urlDecode( + uri.substr( + var_pos, + delimiter - var_pos + ) + ); ++delimiter; - std::string var_value = Utils::urlDecode(uri.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos) ); - - params.emplace(std::move(var_name), std::move(var_value) ); + std::string var_value = Utils::urlDecode( + uri.substr( + delimiter, + std::string::npos != var_end + ? var_end - delimiter + : std::string::npos + ) + ); + + params.emplace( + std::move(var_name), + std::move(var_value) + ); } } } -bool initServerObjects(HttpServer::Request *procRequest, HttpServer::Response *procResponse, const Transfer::app_request *request, Socket::Adapter *socket_adapter) -{ +bool initServerObjects( + HttpServer::Request *procRequest, + HttpServer::Response *procResponse, + const Transfer::app_request *request, + Socket::Adapter *socket_adapter +) { const uint8_t *src = reinterpret_cast(request->request_data); size_t protocol_number; @@ -151,26 +193,25 @@ bool initServerObjects(HttpServer::Request *procRequest, HttpServer::Response *p src = Utils::unpackString(path, src); src = Utils::unpackString(method, src); - size_t stream_id; + size_t number; - src = Utils::unpackNumber(&stream_id, src); + src = Utils::unpackNumber(&number, src); + const uint32_t stream_id = static_cast(number); Http2::ConnectionSettings settings; - size_t number; - src = Utils::unpackNumber(&number, src); - settings.header_table_size = number; + settings.header_table_size = static_cast(number); src = Utils::unpackNumber(&number, src); - settings.enable_push = number; + settings.enable_push = static_cast(number); src = Utils::unpackNumber(&number, src); - settings.max_concurrent_streams = number; + settings.max_concurrent_streams = static_cast(number); src = Utils::unpackNumber(&number, src); - settings.initial_window_size = number; + settings.initial_window_size = static_cast(number); src = Utils::unpackNumber(&number, src); - settings.max_frame_size = number; + settings.max_frame_size = static_cast(number); src = Utils::unpackNumber(&number, src); - settings.max_header_list_size = number; + settings.max_header_list_size = static_cast(number); std::deque > dynamic_table; src = Utils::unpackVector(dynamic_table, src); @@ -190,7 +231,16 @@ bool initServerObjects(HttpServer::Request *procRequest, HttpServer::Response *p getIncomingVars(params, path); - Http2::OutStream *stream = new Http2::OutStream(stream_id, settings, Http2::DynamicTable(settings.header_table_size, settings.max_header_list_size, std::move(dynamic_table) ), mtx); + Http2::OutStream *stream = new Http2::OutStream( + stream_id, + settings, + Http2::DynamicTable( + settings.header_table_size, + settings.max_header_list_size, + std::move(dynamic_table) + ), + mtx + ); prot = new HttpServer::ServerHttp2(socket_adapter, stream); @@ -227,17 +277,18 @@ bool initServerObjects(HttpServer::Request *procRequest, HttpServer::Response *p return success; } -void freeProtocolData(HttpServer::Response *response) -{ +void freeProtocolData(HttpServer::Response *response) { if (response) { delete response->prot; } } -bool isSwitchingProtocols(const HttpServer::Request &request, HttpServer::Response &response) -{ +bool isSwitchingProtocols( + const HttpServer::Request &request, + HttpServer::Response &response +) { // Check for https is not set - if (request.prot->getSocket()->get_tls_session() != 0) { + if (request.prot->getSocket()->get_tls_session() != nullptr) { return false; } @@ -305,7 +356,10 @@ bool isSwitchingProtocols(const HttpServer::Request &request, HttpServer::Respon const std::string headers = "HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nUpgrade: h2c\r\n\r\n"; - response.prot->getSocket()->nonblock_send(headers, std::chrono::milliseconds(5000) ); + response.prot->getSocket()->nonblock_send( + headers, + std::chrono::milliseconds(5000) + ); return true; } diff --git a/src/Init.h b/src/Init.h index bd173b5..b7a4c0b 100644 --- a/src/Init.h +++ b/src/Init.h @@ -5,12 +5,25 @@ #include "transfer/AppRequest.h" #include "transfer/AppResponse.h" -Socket::Adapter *createSocketAdapter(Transfer::app_request *request, void *addr); +Socket::Adapter *createSocketAdapter( + Transfer::app_request *request, + void *addr +); + void destroySocketAdapter(Socket::Adapter *adapter); std::string getClearPath(const std::string &path); -bool initServerObjects(HttpServer::Request *procRequest, HttpServer::Response *procResponse, const Transfer::app_request *request, Socket::Adapter *socket_adapter); +bool initServerObjects( + HttpServer::Request *procRequest, + HttpServer::Response *procResponse, + const Transfer::app_request *request, + Socket::Adapter *socket_adapter +); + void freeProtocolData(HttpServer::Response *response); -bool isSwitchingProtocols(const HttpServer::Request &request, HttpServer::Response &response); +bool isSwitchingProtocols( + const HttpServer::Request &request, + HttpServer::Response &response +); diff --git a/src/Main.cpp b/src/Main.cpp index dce743b..270689e 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -11,8 +11,10 @@ EXPORT bool application_init(const char *root) return true; } -EXPORT int application_call(Transfer::app_request *request, Transfer::app_response *response) -{ +EXPORT int application_call( + Transfer::app_request *request, + Transfer::app_response *response +) { // Allocate memory on the stack uint8_t addr[sizeof(Socket::AdapterTls)]; @@ -30,12 +32,12 @@ EXPORT int application_call(Transfer::app_request *request, Transfer::app_respon int result = EXIT_SUCCESS; - if (isSwitchingProtocols(proc_request, proc_response) ) - { + if (isSwitchingProtocols(proc_request, proc_response) ) { - } - else if (std::string::npos == absolute_path.find("/../") && System::isFileExists(absolute_path) ) - { + } else if ( + std::string::npos == absolute_path.find("/../") && + System::isFileExists(absolute_path) + ) { auto it_connection = proc_request.headers.find("connection"); if (proc_request.headers.cend() != it_connection) { @@ -43,9 +45,7 @@ EXPORT int application_call(Transfer::app_request *request, Transfer::app_respon } proc_response.headers["x-sendfile"] = absolute_path; - } - else - { + } else { // Call application result = Application::test(proc_request, proc_response); } @@ -55,7 +55,11 @@ EXPORT int application_call(Transfer::app_request *request, Transfer::app_respon if (proc_response.headers.size() ) { response->data_size = Utils::getPackContainerSize(proc_response.headers); response->response_data = new uint8_t[response->data_size]; - Utils::packContainer(reinterpret_cast(response->response_data), proc_response.headers); + + Utils::packContainer( + reinterpret_cast(response->response_data), + proc_response.headers + ); } freeProtocolData(&proc_response); diff --git a/src/application/Test.cpp b/src/application/Test.cpp index ece7719..78249e0 100644 --- a/src/application/Test.cpp +++ b/src/application/Test.cpp @@ -5,8 +5,10 @@ namespace Application { - bool test(HttpServer::Request &request, HttpServer::Response &response) - { + bool test( + HttpServer::Request &request, + HttpServer::Response &response + ) { // Output incoming headers std::string s = R"( diff --git a/src/application/Test.h b/src/application/Test.h index 56edaf8..d6a6316 100644 --- a/src/application/Test.h +++ b/src/application/Test.h @@ -5,5 +5,8 @@ namespace Application { - bool test(HttpServer::Request &, HttpServer::Response &); + bool test( + HttpServer::Request &, + HttpServer::Response & + ); } diff --git a/src/server/Response.cpp b/src/server/Response.cpp index 481de8d..27ec2c6 100644 --- a/src/server/Response.cpp +++ b/src/server/Response.cpp @@ -7,21 +7,54 @@ namespace HttpServer { - void Response::setStatusCode(const Http::StatusCode status) { + void Response::setStatusCode( + const Http::StatusCode status + ) noexcept { this->status = status; } - bool Response::sendHeaders(const std::vector > &additional, const std::chrono::milliseconds &timeout, const bool endStream) - { + bool Response::sendHeaders( + const std::vector > &additional, + const std::chrono::milliseconds &timeout, + const bool endStream + ) const { std::vector > headers; - std::copy(this->headers.begin(), this->headers.end(), std::back_inserter(headers) ); - std::copy(additional.begin(), additional.end(), std::back_inserter(headers) ); - - return this->prot->sendHeaders(this->status, headers, timeout, endStream); + headers.reserve( + this->headers.size() + additional.size() + ); + + headers.insert( + headers.end(), + this->headers.cbegin(), + this->headers.cend() + ); + + headers.insert( + headers.end(), + additional.cbegin(), + additional.cend() + ); + + return this->prot->sendHeaders( + this->status, + headers, + timeout, + endStream + ); } - long Response::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const { - return this->prot->sendData(src, size, timeout, endStream); + long Response::sendData( + const void *src, + const size_t size, + const std::chrono::milliseconds &timeout, + const bool endStream + ) const noexcept { + return this->prot->sendData( + src, + size, + timeout, + endStream + ); } } diff --git a/src/server/Response.h b/src/server/Response.h index aa08bdb..79ad7a8 100644 --- a/src/server/Response.h +++ b/src/server/Response.h @@ -17,9 +17,19 @@ namespace HttpServer Http::StatusCode status; public: - void setStatusCode(const Http::StatusCode status); + void setStatusCode(const Http::StatusCode status) noexcept; - bool sendHeaders(const std::vector > &additional, const std::chrono::milliseconds &timeout, const bool endStream = true); - long sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream = true) const; + bool sendHeaders( + const std::vector > &additional, + const std::chrono::milliseconds &timeout, + const bool endStream = true + ) const; + + long sendData( + const void *src, + const size_t size, + const std::chrono::milliseconds &timeout, + const bool endStream = true + ) const noexcept; }; } diff --git a/src/server/protocol/ServerHttp1.cpp b/src/server/protocol/ServerHttp1.cpp index 8e3aa4a..350f7c3 100644 --- a/src/server/protocol/ServerHttp1.cpp +++ b/src/server/protocol/ServerHttp1.cpp @@ -3,10 +3,18 @@ namespace HttpServer { - ServerHttp1::ServerHttp1(Socket::Adapter *sock) : ServerProtocol(sock) {} - - bool ServerHttp1::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const + ServerHttp1::ServerHttp1(Socket::Adapter *sock) noexcept + : ServerProtocol(sock) { + + } + + bool ServerHttp1::sendHeaders( + const Http::StatusCode status, + std::vector > &headers, + const std::chrono::milliseconds &timeout, + const bool endStream + ) const { std::string out = "HTTP/1.1 " + std::to_string(static_cast(status) ) + "\r\n"; for (auto const &h : headers) { @@ -18,7 +26,16 @@ namespace HttpServer return this->sock->nonblock_send(out, timeout) > 0; } - long ServerHttp1::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const { - return this->sock->nonblock_send(src, size, timeout); + long ServerHttp1::sendData( + const void *src, + const size_t size, + const std::chrono::milliseconds &timeout, + const bool endStream + ) const noexcept { + return this->sock->nonblock_send( + src, + size, + timeout + ); } } diff --git a/src/server/protocol/ServerHttp1.h b/src/server/protocol/ServerHttp1.h index dca7aab..55b3b08 100644 --- a/src/server/protocol/ServerHttp1.h +++ b/src/server/protocol/ServerHttp1.h @@ -7,9 +7,20 @@ namespace HttpServer class ServerHttp1 : public ServerProtocol { public: - ServerHttp1(Socket::Adapter *sock); + ServerHttp1(Socket::Adapter *sock) noexcept; - virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; - virtual long sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; + virtual bool sendHeaders( + const Http::StatusCode status, + std::vector > &headers, + const std::chrono::milliseconds &timeout, + const bool endStream = true + ) const override; + + virtual long sendData( + const void *src, + const size_t size, + const std::chrono::milliseconds &timeout, + const bool endStream = true + ) const noexcept override; }; } diff --git a/src/server/protocol/ServerHttp2.cpp b/src/server/protocol/ServerHttp2.cpp index b6b8fe1..fd64c82 100644 --- a/src/server/protocol/ServerHttp2.cpp +++ b/src/server/protocol/ServerHttp2.cpp @@ -8,7 +8,10 @@ namespace HttpServer { - ServerHttp2::ServerHttp2(Socket::Adapter *sock, Http2::OutStream *stream) + ServerHttp2::ServerHttp2( + Socket::Adapter *sock, + Http2::OutStream *stream + ) noexcept : ServerProtocol(sock), stream(stream) { @@ -26,7 +29,7 @@ namespace HttpServer std::random_device rd; - uint8_t padding = rd(); + uint8_t padding = uint8_t(rd()); while (dataSize <= padding) { padding /= 2; @@ -35,17 +38,30 @@ namespace HttpServer return padding; } - bool ServerHttp2::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const - { + bool ServerHttp2::sendHeaders( + const Http::StatusCode status, + std::vector > &headers, + const std::chrono::milliseconds &timeout, + const bool endStream + ) const { std::vector buf; buf.reserve(4096); - buf.resize(Http2::FRAME_HEADER_SIZE + sizeof(uint8_t) ); - headers.emplace(headers.begin(), ":status", std::to_string(static_cast(status) ) ); + buf.resize( + Http2::FRAME_HEADER_SIZE + sizeof(uint8_t) + ); + + headers.emplace( + headers.begin(), + ":status", + std::to_string(static_cast(status) ) + ); HPack::pack(buf, headers, this->stream->dynamic_table); - uint32_t data_size = buf.size() - Http2::FRAME_HEADER_SIZE - sizeof(uint8_t); + size_t data_size = ( + buf.size() - Http2::FRAME_HEADER_SIZE - sizeof(uint8_t) + ); const uint8_t padding = getPaddingSize(data_size); const uint16_t padding_size = padding + sizeof(uint8_t); @@ -54,9 +70,13 @@ namespace HttpServer data_size = this->stream->settings.max_frame_size - padding_size; } - const size_t frame_size = data_size + padding_size; + const uint32_t frame_size = static_cast( + data_size + padding_size + ); - buf.resize(frame_size + Http2::FRAME_HEADER_SIZE); + buf.resize( + frame_size + Http2::FRAME_HEADER_SIZE + ); Http2::FrameFlag flags = Http2::FrameFlag::END_HEADERS; @@ -66,25 +86,41 @@ namespace HttpServer flags |= Http2::FrameFlag::PADDED; - buf[Http2::FRAME_HEADER_SIZE] = padding; + buf[Http2::FRAME_HEADER_SIZE] = char(padding); if (padding) { - std::fill(buf.end() - padding, buf.end(), 0); + std::fill( + buf.end() - padding, + buf.end(), + 0 + ); } - this->stream->setHttp2FrameHeader(reinterpret_cast(buf.data() ), frame_size, Http2::FrameType::HEADERS, flags); + this->stream->setHttp2FrameHeader( + reinterpret_cast(buf.data() ), + frame_size, + Http2::FrameType::HEADERS, + flags + ); const std::unique_lock lock(*this->stream->mtx); return this->sock->nonblock_send(buf.data(), buf.size(), timeout) > 0; } - void ServerHttp2::sendWindowUpdate(const uint32_t size, const std::chrono::milliseconds &timeout) const - { + void ServerHttp2::sendWindowUpdate( + const uint32_t size, + const std::chrono::milliseconds &timeout + ) const { std::array buf; uint8_t *addr = buf.data(); - addr = this->stream->setHttp2FrameHeader(addr, sizeof(uint32_t), Http2::FrameType::WINDOW_UPDATE, Http2::FrameFlag::EMPTY); + addr = this->stream->setHttp2FrameHeader( + addr, + sizeof(uint32_t), + Http2::FrameType::WINDOW_UPDATE, + Http2::FrameFlag::EMPTY + ); *reinterpret_cast(addr) = ::htonl(size); @@ -93,18 +129,27 @@ namespace HttpServer this->sock->nonblock_send(buf.data(), buf.size(), timeout); } - long ServerHttp2::sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream) const - { + long ServerHttp2::sendData( + const void *src, + const size_t size, + const std::chrono::milliseconds &timeout, + const bool endStream + ) const noexcept { const uint8_t *data = reinterpret_cast(src); std::vector buf; - buf.reserve(this->stream->settings.max_frame_size + Http2::FRAME_HEADER_SIZE); + + buf.reserve( + this->stream->settings.max_frame_size + Http2::FRAME_HEADER_SIZE + ); size_t total = 0; while (total < size) { - size_t data_size = (size - total < this->stream->settings.max_frame_size) ? size - total : this->stream->settings.max_frame_size; + size_t data_size = (size - total < this->stream->settings.max_frame_size) + ? size - total + : this->stream->settings.max_frame_size; const uint8_t padding = getPaddingSize(data_size); const uint16_t padding_size = padding + sizeof(uint8_t); @@ -113,19 +158,22 @@ namespace HttpServer data_size = this->stream->settings.max_frame_size - padding_size; } - const size_t frame_size = data_size + padding_size; + const uint32_t frame_size = static_cast( + data_size + padding_size + ); buf.resize(frame_size + Http2::FRAME_HEADER_SIZE); - if (static_cast(this->stream->window_size_out - this->stream->settings.max_frame_size) <= 0) + if (this->stream->window_size_out - long(this->stream->settings.max_frame_size) <= 0) { - size_t update_size = this->stream->settings.initial_window_size + (size - total) - this->stream->window_size_out; + size_t update_size = this->stream->settings.initial_window_size + + (size - total) - size_t(this->stream->window_size_out); if (update_size > Http2::MAX_WINDOW_UPDATE) { update_size = Http2::MAX_WINDOW_UPDATE; } - this->sendWindowUpdate(static_cast(update_size), timeout); + this->sendWindowUpdate(uint32_t(update_size), timeout); this->stream->window_size_out += update_size; } @@ -144,17 +192,34 @@ namespace HttpServer ++cur; } - this->stream->setHttp2FrameHeader(buf.data(), frame_size, Http2::FrameType::DATA, flags); + this->stream->setHttp2FrameHeader( + buf.data(), + frame_size, + Http2::FrameType::DATA, + flags + ); - std::copy(data, data + data_size, buf.begin() + cur); + std::copy( + data, + data + data_size, + buf.data() + cur + ); if (padding) { - std::fill(buf.end() - padding, buf.end(), 0); + std::fill( + buf.end() - padding, + buf.end(), + 0 + ); } this->stream->lock(); - const long sended = this->sock->nonblock_send(buf.data(), buf.size(), timeout); + const long sended = this->sock->nonblock_send( + buf.data(), + buf.size(), + timeout + ); this->stream->unlock(); @@ -169,6 +234,6 @@ namespace HttpServer total += data_size; } - return static_cast(total); + return long(total); } } diff --git a/src/server/protocol/ServerHttp2.h b/src/server/protocol/ServerHttp2.h index 6fc8142..b7389f1 100644 --- a/src/server/protocol/ServerHttp2.h +++ b/src/server/protocol/ServerHttp2.h @@ -12,12 +12,30 @@ namespace HttpServer Http2::OutStream *stream; public: - ServerHttp2(Socket::Adapter *sock, Http2::OutStream *stream); - virtual ~ServerHttp2() noexcept; + ServerHttp2( + Socket::Adapter *sock, + Http2::OutStream *stream + ) noexcept; - void sendWindowUpdate(const uint32_t size, const std::chrono::milliseconds &timeout) const; + virtual ~ServerHttp2() noexcept override; - virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; - virtual long sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream = true) const override; + void sendWindowUpdate( + const uint32_t size, + const std::chrono::milliseconds &timeout + ) const; + + virtual bool sendHeaders( + const Http::StatusCode status, + std::vector > &headers, + const std::chrono::milliseconds &timeout, + const bool endStream = true + ) const override; + + virtual long sendData( + const void *src, + const size_t size, + const std::chrono::milliseconds &timeout, + const bool endStream = true + ) const noexcept override; }; } diff --git a/src/server/protocol/ServerProtocol.cpp b/src/server/protocol/ServerProtocol.cpp index 7396ecc..d5ac1dd 100644 --- a/src/server/protocol/ServerProtocol.cpp +++ b/src/server/protocol/ServerProtocol.cpp @@ -3,7 +3,11 @@ namespace HttpServer { - ServerProtocol::ServerProtocol(Socket::Adapter *sock) : sock(sock) {} + ServerProtocol::ServerProtocol(Socket::Adapter *sock) noexcept + : sock(sock) + { + + } Socket::Adapter *ServerProtocol::getSocket() noexcept { return this->sock; diff --git a/src/server/protocol/ServerProtocol.h b/src/server/protocol/ServerProtocol.h index 5e2c5c8..f0c211c 100644 --- a/src/server/protocol/ServerProtocol.h +++ b/src/server/protocol/ServerProtocol.h @@ -11,13 +11,24 @@ namespace HttpServer Socket::Adapter *sock; public: - ServerProtocol(Socket::Adapter *sock); + ServerProtocol(Socket::Adapter *sock) noexcept; virtual ~ServerProtocol() noexcept = default; Socket::Adapter *getSocket() noexcept; - virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream = true) const = 0; - virtual long sendData(const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream = true) const = 0; + virtual bool sendHeaders( + const Http::StatusCode status, + std::vector > &headers, + const std::chrono::milliseconds &timeout, + const bool endStream = true + ) const = 0; + + virtual long sendData( + const void *src, + const size_t size, + const std::chrono::milliseconds &timeout, + const bool endStream = true + ) const noexcept = 0; virtual void close() noexcept; }; diff --git a/src/socket/Adapter.cpp b/src/socket/Adapter.cpp index 0c50bc3..c99bee6 100644 --- a/src/socket/Adapter.cpp +++ b/src/socket/Adapter.cpp @@ -3,12 +3,26 @@ namespace Socket { - long Adapter::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept { - return this->nonblock_recv(buf.data(), buf.size(), timeout); + long Adapter::nonblock_recv( + std::vector &buf, + const std::chrono::milliseconds &timeout + ) const noexcept { + return this->nonblock_recv( + buf.data(), + buf.size(), + timeout + ); } - long Adapter::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const noexcept { - return this->nonblock_send(buf.data(), buf.length(), timeout); + long Adapter::nonblock_send( + const std::string &buf, + const std::chrono::milliseconds &timeout + ) const noexcept { + return this->nonblock_send( + buf.data(), + buf.length(), + timeout + ); } bool Adapter::operator ==(const Adapter &obj) const noexcept { diff --git a/src/socket/Adapter.h b/src/socket/Adapter.h index 35b3964..2787176 100644 --- a/src/socket/Adapter.h +++ b/src/socket/Adapter.h @@ -19,11 +19,27 @@ namespace Socket virtual ::gnutls_session_t get_tls_session() const noexcept = 0; virtual Adapter *copy() const noexcept = 0; - long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept; - virtual long nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept = 0; - - long nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const noexcept; - virtual long nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept = 0; + long nonblock_recv( + std::vector &buf, + const std::chrono::milliseconds &timeout + ) const noexcept; + + virtual long nonblock_recv( + void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept = 0; + + long nonblock_send( + const std::string &buf, + const std::chrono::milliseconds &timeout + ) const noexcept; + + virtual long nonblock_send( + const void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept = 0; virtual void close() noexcept = 0; diff --git a/src/socket/AdapterDefault.cpp b/src/socket/AdapterDefault.cpp index 1f2fe36..2940daf 100644 --- a/src/socket/AdapterDefault.cpp +++ b/src/socket/AdapterDefault.cpp @@ -3,25 +3,33 @@ namespace Socket { - AdapterDefault::AdapterDefault(const Socket &_sock) noexcept : sock(_sock) {} + AdapterDefault::AdapterDefault(const Socket &sock) noexcept : sock(sock) {} System::native_socket_type AdapterDefault::get_handle() const noexcept { return sock.get_handle(); } ::gnutls_session_t AdapterDefault::get_tls_session() const noexcept { - return 0; + return nullptr; } Adapter *AdapterDefault::copy() const noexcept { return new AdapterDefault(this->sock); } - long AdapterDefault::nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { + long AdapterDefault::nonblock_recv( + void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept { return sock.nonblock_recv(buf, length, timeout); } - long AdapterDefault::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { + long AdapterDefault::nonblock_send( + const void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept { return sock.nonblock_send(buf, length, timeout); } diff --git a/src/socket/AdapterDefault.h b/src/socket/AdapterDefault.h index d743783..db8b191 100644 --- a/src/socket/AdapterDefault.h +++ b/src/socket/AdapterDefault.h @@ -18,8 +18,17 @@ namespace Socket virtual ::gnutls_session_t get_tls_session() const noexcept override; virtual Adapter *copy() const noexcept override; - virtual long nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept override; - virtual long nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept override; + virtual long nonblock_recv( + void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept override; + + virtual long nonblock_send( + const void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept override; virtual void close() noexcept override; }; diff --git a/src/socket/AdapterTls.cpp b/src/socket/AdapterTls.cpp index b63bf73..0126830 100644 --- a/src/socket/AdapterTls.cpp +++ b/src/socket/AdapterTls.cpp @@ -3,8 +3,11 @@ namespace Socket { - AdapterTls::AdapterTls(const Socket &sock, ::gnutls_priority_t priority_cache, ::gnutls_certificate_credentials_t x509_cred) noexcept - { + AdapterTls::AdapterTls( + const Socket &sock, + ::gnutls_priority_t priority_cache, + ::gnutls_certificate_credentials_t x509_cred + ) noexcept { // https://leandromoreira.com.br/2015/10/12/how-to-optimize-nginx-configuration-for-http2-tls-ssl/ // https://www.gnutls.org/manual/html_node/False-Start.html @@ -39,6 +42,8 @@ namespace Socket { int ret; + ::gnutls_handshake_set_timeout(this->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); + do { ret = ::gnutls_handshake(this->session); } @@ -56,9 +61,10 @@ namespace Socket return true; } - long AdapterTls::nonblock_send_all(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept - { - // size_t record_size = ::gnutls_record_get_max_size(this->session); + long AdapterTls::nonblock_send_all( + const void *buf, const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept { size_t record_size = length; if (0 == record_size) { @@ -67,8 +73,6 @@ namespace Socket Socket sock(this->get_handle() ); - // ::gnutls_record_set_timeout(this->session, static_cast(timeout.count() ) ); - size_t total = 0; while (total < length) { @@ -80,7 +84,12 @@ namespace Socket do { sock.nonblock_send_sync(); - send_size = ::gnutls_record_send(this->session, reinterpret_cast(buf) + total, record_size); + + send_size = ::gnutls_record_send( + this->session, + reinterpret_cast(buf) + total, + record_size + ); } while (GNUTLS_E_AGAIN == send_size); @@ -88,14 +97,16 @@ namespace Socket return send_size; } - total += send_size; + total += long(send_size); } - return static_cast(total); + return long(total); } System::native_socket_type AdapterTls::get_handle() const noexcept { - return static_cast(::gnutls_transport_get_int(this->session) ); + return static_cast( + ::gnutls_transport_get_int(this->session) + ); } ::gnutls_session_t AdapterTls::get_tls_session() const noexcept { @@ -106,8 +117,11 @@ namespace Socket return new AdapterTls(this->session); } - long AdapterTls::nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept - { + long AdapterTls::nonblock_recv( + void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept { Socket sock(this->get_handle() ); long result; @@ -126,7 +140,11 @@ namespace Socket return result; } - long AdapterTls::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { + long AdapterTls::nonblock_send( + const void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept { return this->nonblock_send_all(buf, length, timeout); } diff --git a/src/socket/AdapterTls.h b/src/socket/AdapterTls.h index 27bad11..04aab40 100644 --- a/src/socket/AdapterTls.h +++ b/src/socket/AdapterTls.h @@ -12,18 +12,38 @@ namespace Socket public: AdapterTls() = delete; - AdapterTls(const Socket &sock, ::gnutls_priority_t priority_cache, ::gnutls_certificate_credentials_t x509_cred) noexcept; + + AdapterTls( + const Socket &sock, + ::gnutls_priority_t priority_cache, + ::gnutls_certificate_credentials_t x509_cred + ) noexcept; + AdapterTls(const ::gnutls_session_t session) noexcept; bool handshake() noexcept; - long nonblock_send_all(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept; + + long nonblock_send_all( + const void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept; virtual System::native_socket_type get_handle() const noexcept override; virtual ::gnutls_session_t get_tls_session() const noexcept override; virtual Adapter *copy() const noexcept override; - virtual long nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept override; - virtual long nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept override; + virtual long nonblock_recv( + void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept override; + + virtual long nonblock_send( + const void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept override; virtual void close() noexcept override; }; diff --git a/src/socket/List.cpp b/src/socket/List.cpp index 1746a79..eab986d 100644 --- a/src/socket/List.cpp +++ b/src/socket/List.cpp @@ -1,4 +1,4 @@ - + #include "List.h" #ifdef POSIX @@ -16,7 +16,7 @@ namespace Socket #elif POSIX this->obj_list = ~0; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -30,7 +30,7 @@ namespace Socket obj.obj_list = ~0; obj.epoll_events.swap(this->epoll_events); #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -63,7 +63,7 @@ namespace Socket return true; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -79,7 +79,7 @@ namespace Socket this->obj_list = ~0; this->epoll_events.clear(); #else - #error "Undefine platform" + #error "Undefined platform" #endif } } @@ -91,7 +91,7 @@ namespace Socket #elif POSIX return this->obj_list != ~0; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -102,7 +102,7 @@ namespace Socket } #ifdef WIN32 - WSAPOLLFD event = { + WSAPOLLFD event { sock.get_handle(), POLLRDNORM, 0 @@ -112,12 +112,17 @@ namespace Socket return true; #elif POSIX - struct ::epoll_event event = { + struct ::epoll_event event { EPOLLIN | EPOLLET | EPOLLRDHUP, reinterpret_cast(sock.get_handle() ) }; - const int result = ::epoll_ctl(this->obj_list, EPOLL_CTL_ADD, sock.get_handle(), &event); + const int result = ::epoll_ctl( + this->obj_list, + EPOLL_CTL_ADD, + sock.get_handle(), + &event + ); if (result == ~0) { return false; @@ -127,7 +132,7 @@ namespace Socket return true; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -147,7 +152,12 @@ namespace Socket return false; #elif POSIX - const int result = ::epoll_ctl(this->obj_list, EPOLL_CTL_DEL, sock.get_handle(), nullptr); + const int result = ::epoll_ctl( + this->obj_list, + EPOLL_CTL_DEL, + sock.get_handle(), + nullptr + ); if (result == ~0) { return false; @@ -157,7 +167,7 @@ namespace Socket return true; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -166,7 +176,11 @@ namespace Socket if (this->is_created() ) { #ifdef WIN32 - const int count = ::WSAPoll(this->poll_events.data(), static_cast<::ULONG>(this->poll_events.size() ), ~0); + const int count = ::WSAPoll( + this->poll_events.data(), + static_cast<::ULONG>(this->poll_events.size() ), + ~0 + ); if (SOCKET_ERROR == count) { return false; @@ -181,7 +195,11 @@ namespace Socket System::native_socket_type client_socket = ~0; do { - client_socket = ::accept(event.fd, static_cast(nullptr), static_cast(nullptr) ); + client_socket = ::accept( + event.fd, + static_cast(nullptr), + static_cast(nullptr) + ); if (~0 != client_socket) { sockets.emplace_back(Socket(client_socket) ); @@ -193,7 +211,12 @@ namespace Socket return false == sockets.empty(); #elif POSIX - const int count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); + const int count = ::epoll_wait( + this->obj_list, + this->epoll_events.data(), + this->epoll_events.size(), + ~0 + ); if (count == ~0) { return false; @@ -208,7 +231,11 @@ namespace Socket System::native_socket_type client_socket = ~0; do { - client_socket = ::accept(event.data.fd, static_cast(nullptr), static_cast(nullptr) ); + client_socket = ::accept( + event.data.fd, + static_cast(nullptr), + static_cast(nullptr) + ); if (~0 != client_socket) { sockets.emplace_back(Socket(client_socket) ); @@ -220,37 +247,45 @@ namespace Socket return false == sockets.empty(); #else - #error "Undefine platform" + #error "Undefined platform" #endif } return false; } - bool List::accept(std::vector &sockets, std::vector &socketsAddress) const noexcept - { + bool List::accept( + std::vector &sockets, + std::vector &socketsAddress + ) const noexcept { if (this->is_created() ) { #ifdef WIN32 - const int count = ::WSAPoll(this->poll_events.data(), static_cast<::ULONG>(this->poll_events.size() ), ~0); + const int count = ::WSAPoll( + this->poll_events.data(), + static_cast<::ULONG>(this->poll_events.size() ), + ~0 + ); if (SOCKET_ERROR == count) { return false; } - for (size_t i = 0; i < this->poll_events.size(); ++i) + for (auto const &event : this->poll_events) { - const WSAPOLLFD &event = this->poll_events[i]; - if (event.revents & POLLRDNORM) { System::native_socket_type client_socket = ~0; do { ::sockaddr_in client_addr {}; - socklen_t client_addr_len = sizeof(client_addr); + ::socklen_t client_addr_len = sizeof(client_addr); - client_socket = ::accept(event.fd, reinterpret_cast<::sockaddr *>(&client_addr), &client_addr_len); + client_socket = ::accept( + event.fd, + reinterpret_cast<::sockaddr *>(&client_addr), + &client_addr_len + ); if (~0 != client_socket) { sockets.emplace_back(Socket(client_socket) ); @@ -263,7 +298,12 @@ namespace Socket return false == sockets.empty(); #elif POSIX - const int count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); + const int count = ::epoll_wait( + this->obj_list, + this->epoll_events.data(), + this->epoll_events.size(), + ~0 + ); if (count == ~0) { return false; @@ -281,7 +321,11 @@ namespace Socket ::sockaddr_in client_addr {}; socklen_t client_addr_len = sizeof(client_addr); - client_socket = ::accept(event.data.fd, reinterpret_cast<::sockaddr *>(&client_addr), &client_addr_len); + client_socket = ::accept( + event.data.fd, + reinterpret_cast<::sockaddr *>(&client_addr), + &client_addr_len + ); if (~0 != client_socket) { sockets.emplace_back(Socket(client_socket) ); @@ -294,30 +338,35 @@ namespace Socket return false == sockets.empty(); #else - #error "Undefine platform" + #error "Undefined platform" #endif } return false; } - bool List::recv(std::vector &sockets, std::vector &disconnected, std::chrono::milliseconds timeout) const noexcept - { + bool List::recv( + std::vector &sockets, + std::vector &disconnected, + std::chrono::milliseconds timeout + ) const noexcept { if (this->is_created() == false) { return false; } #ifdef WIN32 - const int count = ::WSAPoll(this->poll_events.data(), static_cast<::ULONG>(this->poll_events.size() ), static_cast<::INT>(timeout.count() ) ); + const int count = ::WSAPoll( + this->poll_events.data(), + static_cast<::ULONG>(this->poll_events.size() ), + static_cast<::INT>(timeout.count() ) + ); if (SOCKET_ERROR == count) { return false; } - for (size_t i = 0; i < this->poll_events.size(); ++i) + for (auto const &event : this->poll_events) { - const WSAPOLLFD &event = this->poll_events[i]; - if (event.revents & POLLRDNORM) { sockets.emplace_back(Socket(event.fd) ); } @@ -328,7 +377,12 @@ namespace Socket return false == sockets.empty() || false == disconnected.empty(); #elif POSIX - const int count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), timeout.count() ); + const int count = ::epoll_wait( + this->obj_list, + this->epoll_events.data(), + this->epoll_events.size(), + timeout.count() + ); if (count == ~0) { return false; @@ -348,7 +402,7 @@ namespace Socket return false == sockets.empty() || false == disconnected.empty(); #else - #error "Undefine platform" + #error "Undefined platform" #endif } } diff --git a/src/socket/List.h b/src/socket/List.h index 19f83b0..cdd2747 100644 --- a/src/socket/List.h +++ b/src/socket/List.h @@ -19,7 +19,7 @@ namespace Socket int obj_list; mutable std::vector epoll_events; #else - #error "Undefine platform" + #error "Undefined platform" #endif public: @@ -35,9 +35,19 @@ namespace Socket bool addSocket(const Socket &sock) noexcept; bool removeSocket(const Socket &sock) noexcept; - bool accept(std::vector &sockets) const noexcept; - bool accept(std::vector &sockets, std::vector &socketsAddress) const noexcept; + bool accept( + std::vector &sockets + ) const noexcept; - bool recv(std::vector &sockets, std::vector &errors, std::chrono::milliseconds timeout = std::chrono::milliseconds(~0) ) const noexcept; + bool accept( + std::vector &sockets, + std::vector &socketsAddress + ) const noexcept; + + bool recv( + std::vector &sockets, + std::vector &errors, + std::chrono::milliseconds timeout = std::chrono::milliseconds(~0) + ) const noexcept; }; } diff --git a/src/socket/Socket.cpp b/src/socket/Socket.cpp index 96bd194..40b0f92 100644 --- a/src/socket/Socket.cpp +++ b/src/socket/Socket.cpp @@ -22,7 +22,7 @@ namespace Socket #elif POSIX return true; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -33,7 +33,7 @@ namespace Socket #elif POSIX return true; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -44,7 +44,7 @@ namespace Socket #elif POSIX return errno; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -54,7 +54,9 @@ namespace Socket Socket::Socket(const Socket &obj) noexcept : socket_handle(obj.socket_handle) {} - Socket::Socket(Socket &&obj) noexcept : socket_handle(obj.socket_handle) { + Socket::Socket(Socket &&obj) noexcept + : socket_handle(obj.socket_handle) + { obj.socket_handle = ~0; } @@ -73,7 +75,7 @@ namespace Socket #elif POSIX const int result = ::close(this->socket_handle); #else - #error "Undefine platform" + #error "Undefined platform" #endif if (0 == result) { @@ -92,7 +94,7 @@ namespace Socket #elif POSIX return ~0 != this->socket_handle; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -100,16 +102,19 @@ namespace Socket return this->socket_handle; } - bool Socket::bind(const int port) const noexcept - { - const ::sockaddr_in sock_addr = { - AF_INET, - htons(port), - ::htonl(INADDR_ANY), - 0 - }; + bool Socket::bind(const int port) const noexcept { + const ::sockaddr_in sock_addr { + AF_INET, + ::htons(port), + ::htonl(INADDR_ANY), + 0 + }; - return 0 == ::bind(this->socket_handle, reinterpret_cast(&sock_addr), sizeof(sockaddr_in) ); + return 0 == ::bind( + this->socket_handle, + reinterpret_cast(&sock_addr), + sizeof(sockaddr_in) + ); } bool Socket::listen() const noexcept { @@ -119,11 +124,19 @@ namespace Socket Socket Socket::accept() const noexcept { #ifdef WIN32 - System::native_socket_type client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); + System::native_socket_type client_socket = ::accept( + this->socket_handle, + static_cast(nullptr), + static_cast(nullptr) + ); #elif POSIX - System::native_socket_type client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); + System::native_socket_type client_socket = ::accept( + this->socket_handle, + static_cast(nullptr), + static_cast(nullptr) + ); #else - #error "Undefine platform" + #error "Undefined platform" #endif return Socket(client_socket); } @@ -132,27 +145,35 @@ namespace Socket { System::native_socket_type client_socket = ~0; #ifdef WIN32 - WSAPOLLFD event = { + WSAPOLLFD event { this->socket_handle, POLLRDNORM, 0 }; if (1 == ::WSAPoll(&event, 1, ~0) && event.revents & POLLRDNORM) { - client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); + client_socket = ::accept( + this->socket_handle, + static_cast(nullptr), + static_cast(nullptr) + ); } #elif POSIX - struct ::pollfd event = { + struct ::pollfd event { this->socket_handle, POLLIN, 0 }; if (1 == ::poll(&event, 1, ~0) && event.revents & POLLIN) { - client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); + client_socket = ::accept( + this->socket_handle, + static_cast(nullptr), + static_cast(nullptr) + ); } #else - #error "Undefine platform" + #error "Undefined platform" #endif return Socket(client_socket); } @@ -161,27 +182,35 @@ namespace Socket { System::native_socket_type client_socket = ~0; #ifdef WIN32 - WSAPOLLFD event = { + WSAPOLLFD event { this->socket_handle, - POLLRDNORM, - 0 - }; + POLLRDNORM, + 0 + }; - if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLRDNORM) { - client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); + if (1 == ::WSAPoll(&event, 1, int(timeout.count()) ) && event.revents & POLLRDNORM) { + client_socket = ::accept( + this->socket_handle, + static_cast(nullptr), + static_cast(nullptr) + ); } #elif POSIX - struct ::pollfd event = { + struct ::pollfd event { this->socket_handle, - POLLIN, - 0 - }; + POLLIN, + 0 + }; - if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLIN) { - client_socket = ::accept(this->socket_handle, static_cast(nullptr), static_cast(nullptr) ); + if (1 == ::poll(&event, 1, int(timeout.count()) ) && event.revents & POLLIN) { + client_socket = ::accept( + this->socket_handle, + static_cast(nullptr), + static_cast(nullptr) + ); } #else - #error "Undefine platform" + #error "Undefined platform" #endif return Socket(client_socket); } @@ -195,7 +224,7 @@ namespace Socket #elif POSIX return 0 == ::shutdown(this->socket_handle, SHUT_RDWR); #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -206,11 +235,22 @@ namespace Socket { #ifdef WIN32 unsigned long value = isNonBlock; - return 0 == ::ioctlsocket(this->socket_handle, FIONBIO, &value); + + return 0 == ::ioctlsocket( + this->socket_handle, + FIONBIO, + &value + ); #elif POSIX - return ~0 != ::fcntl(this->socket_handle, F_SETFL, isNonBlock ? O_NONBLOCK : O_SYNC); + return ~0 != ::fcntl( + this->socket_handle, + F_SETFL, + isNonBlock + ? O_NONBLOCK + : O_SYNC + ); #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -223,7 +263,7 @@ namespace Socket const int flags = ::fcntl(socket_handle, F_GETFL, 0); return (flags != ~0) && (flags & O_NONBLOCK); #else - #error "Undefine platform" + #error "Undefined platform" #endif } */ @@ -232,98 +272,145 @@ namespace Socket { #ifdef WIN32 int flags = nodelay ? 1 : 0; - return 0 == setsockopt(this->socket_handle, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&flags), sizeof(flags) ); + + return 0 == ::setsockopt( + this->socket_handle, + IPPROTO_TCP, + TCP_NODELAY, + reinterpret_cast(&flags), + sizeof(flags) + ); #elif POSIX int flags = nodelay ? 1 : 0; - return 0 == setsockopt(this->socket_handle, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags) ); + + return 0 == ::setsockopt( + this->socket_handle, + IPPROTO_TCP, + TCP_NODELAY, + &flags, + sizeof(flags) + ); #else - #error "Undefine platform" + #error "Undefined platform" #endif } - long Socket::recv(std::vector &buf) const noexcept { + long Socket::recv( + std::vector &buf + ) const noexcept { return this->recv(buf.data(), buf.size() ); } - long Socket::recv(void *buf, const size_t length) const noexcept - { + long Socket::recv( + void *buf, + const size_t length + ) const noexcept { #ifdef WIN32 - return ::recv(this->socket_handle, reinterpret_cast(buf), static_cast(length), 0); + return ::recv( + this->socket_handle, + reinterpret_cast(buf), + static_cast(length), + 0 + ); #elif POSIX return ::recv(this->socket_handle, buf, length, 0); #else - #error "Undefine platform" + #error "Undefined platform" #endif } - long Socket::nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept { - return this->nonblock_recv(buf.data(), buf.size(), timeout); + long Socket::nonblock_recv( + std::vector &buf, + const std::chrono::milliseconds &timeout + ) const noexcept { + return this->nonblock_recv( + buf.data(), + buf.size(), + timeout + ); } - long Socket::nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept - { + long Socket::nonblock_recv( + void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept { long recv_len = ~0; #ifdef WIN32 - WSAPOLLFD event = { + WSAPOLLFD event { this->socket_handle, POLLRDNORM, 0 }; - if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLRDNORM) { - recv_len = ::recv(this->socket_handle, reinterpret_cast(buf), static_cast(length), 0); + if (1 == ::WSAPoll(&event, 1, int(timeout.count()) ) && event.revents & POLLRDNORM) { + recv_len = ::recv( + this->socket_handle, + reinterpret_cast(buf), + static_cast(length), + 0 + ); } #elif POSIX - struct ::pollfd event = { + struct ::pollfd event { this->socket_handle, POLLIN, 0 }; - if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLIN) { + if (1 == ::poll(&event, 1, int(timeout.count()) ) && event.revents & POLLIN) { recv_len = ::recv(this->socket_handle, buf, length, 0); } #else - #error "Undefine platform" + #error "Undefined platform" #endif return recv_len; } - bool Socket::nonblock_recv_sync(const std::chrono::milliseconds &timeout) const noexcept - { + bool Socket::nonblock_recv_sync( + const std::chrono::milliseconds &timeout + ) const noexcept { #ifdef WIN32 - WSAPOLLFD event = { + WSAPOLLFD event { this->socket_handle, POLLIN, 0 }; - return ::WSAPoll(&event, 1, timeout.count() ) == 1; + return ::WSAPoll(&event, 1, int(timeout.count()) ) == 1; #elif POSIX - struct ::pollfd event = { + struct ::pollfd event { this->socket_handle, POLLIN, 0 }; - return ::poll(&event, 1, timeout.count() ) == 1; + return ::poll(&event, 1, int(timeout.count()) ) == 1; #else - #error "Undefine platform" + #error "Undefined platform" #endif } - static long send_all(const System::native_socket_type socket_handle, const void *data, const size_t length) noexcept - { + static long send_all( + const System::native_socket_type socket_handle, + const void *data, + const size_t length + ) noexcept { size_t total = 0; while (total < length) { - const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, length - total, 0); + const long send_size = ::send( + socket_handle, + reinterpret_cast(data) + total, + length - total, + 0 + ); if (send_size < 0) { return send_size; } - total += send_size; + total += size_t(send_size); } return static_cast(total); @@ -337,8 +424,12 @@ namespace Socket return send_all(this->socket_handle, buf, length); } - static long nonblock_send_all(const System::native_socket_type socket_handle, const void *data, const size_t length, const std::chrono::milliseconds &timeout) noexcept - { + static long nonblock_send_all( + const System::native_socket_type socket_handle, + const void *data, + const size_t length, + const std::chrono::milliseconds &timeout + ) noexcept { size_t total = 0; #ifdef WIN32 @@ -349,14 +440,19 @@ namespace Socket }; while (total < length) { - if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLOUT) { - const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, static_cast(length - total), 0); + if (1 == ::WSAPoll(&event, 1, int(timeout.count()) ) && event.revents & POLLOUT) { + const long send_size = ::send( + socket_handle, + reinterpret_cast(data) + total, + static_cast(length - total), + 0 + ); if (send_size < 0) { return send_size; } - total += send_size; + total += size_t(send_size); } else { return -1; } @@ -370,37 +466,58 @@ namespace Socket }; while (total < length) { - if (1 == ::poll(&event, 1, timeout.count() ) && event.revents & POLLOUT) { - const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, length - total, 0); + if (1 == ::poll(&event, 1, int(timeout.count()) ) && event.revents & POLLOUT) { + const long send_size = ::send( + socket_handle, + reinterpret_cast(data) + total, + length - total, + 0 + ); if (send_size < 0) { return send_size; } - total += send_size; + total += size_t(send_size); } else { return -1; } } #else - #error "Undefine platform" + #error "Undefined platform" #endif - return static_cast(total); + return long(total); } - long Socket::nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const noexcept { - return this->nonblock_send(buf.data(), buf.length(), timeout); + long Socket::nonblock_send( + const std::string &buf, + const std::chrono::milliseconds &timeout + ) const noexcept { + return this->nonblock_send( + buf.data(), + buf.length(), + timeout + ); } - long Socket::nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept { - return nonblock_send_all(this->socket_handle, buf, length, timeout); + long Socket::nonblock_send( + const void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept { + return nonblock_send_all( + this->socket_handle, + buf, + length, + timeout + ); } void Socket::nonblock_send_sync() const noexcept { #ifdef WIN32 - WSAPOLLFD event = { + WSAPOLLFD event { this->socket_handle, POLLOUT, 0 @@ -408,7 +525,7 @@ namespace Socket ::WSAPoll(&event, 1, ~0); #elif POSIX - struct ::pollfd event = { + struct ::pollfd event { this->socket_handle, POLLOUT, 0 @@ -416,7 +533,7 @@ namespace Socket ::poll(&event, 1, ~0); #else - #error "Undefine platform" + #error "Undefined platform" #endif } diff --git a/src/socket/Socket.h b/src/socket/Socket.h index e0bfc6c..0d5b711 100644 --- a/src/socket/Socket.h +++ b/src/socket/Socket.h @@ -37,7 +37,10 @@ namespace Socket Socket accept() const noexcept; Socket nonblock_accept() const noexcept; - Socket nonblock_accept(const std::chrono::milliseconds &timeout) const noexcept; + + Socket nonblock_accept( + const std::chrono::milliseconds &timeout + ) const noexcept; bool shutdown() const noexcept; @@ -45,19 +48,43 @@ namespace Socket // bool is_nonblock() const noexcept; bool tcp_nodelay(const bool nodelay = true) const noexcept; - long recv(std::vector &buf) const noexcept; - long recv(void *buf, const size_t length) const noexcept; + long recv( + std::vector &buf + ) const noexcept; + + long recv( + void *buf, + const size_t length + ) const noexcept; - long nonblock_recv(std::vector &buf, const std::chrono::milliseconds &timeout) const noexcept; - long nonblock_recv(void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept; + long nonblock_recv( + std::vector &buf, + const std::chrono::milliseconds &timeout + ) const noexcept; - bool nonblock_recv_sync(const std::chrono::milliseconds &timeout) const noexcept; + long nonblock_recv( + void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept; + + bool nonblock_recv_sync( + const std::chrono::milliseconds &timeout + ) const noexcept; long send(const std::string &buf) const noexcept; long send(const void *buf, const size_t length) const noexcept; - long nonblock_send(const std::string &buf, const std::chrono::milliseconds &timeout) const noexcept; - long nonblock_send(const void *buf, const size_t length, const std::chrono::milliseconds &timeout) const noexcept; + long nonblock_send( + const std::string &buf, + const std::chrono::milliseconds &timeout + ) const noexcept; + + long nonblock_send( + const void *buf, + const size_t length, + const std::chrono::milliseconds &timeout + ) const noexcept; void nonblock_send_sync() const noexcept; diff --git a/src/system/System.cpp b/src/system/System.cpp index 9dcaeb7..ebb5935 100644 --- a/src/system/System.cpp +++ b/src/system/System.cpp @@ -1,4 +1,4 @@ - + #include "System.h" #include @@ -20,8 +20,7 @@ namespace System { #ifdef WIN32 - struct EnumData - { + struct EnumData { native_processid_type process_id; ::HWND hWnd; }; @@ -34,11 +33,11 @@ namespace System ::GetWindowThreadProcessId(hWnd, &process_id); - if (process_id == ed.process_id && ::GetConsoleWindow() != hWnd) + if (process_id == ed.process_id && ::GetConsoleWindow() != hWnd) { std::array<::TCHAR, 257> class_name; - ::GetClassName(hWnd, class_name.data(), static_cast(class_name.size() - 1) ); + ::GetClassName(hWnd, class_name.data(), int(class_name.size() - 1) ); if (0 == ::_tcscmp(class_name.data(), myWndClassName) ) { ed.hWnd = hWnd; @@ -57,7 +56,7 @@ namespace System #elif POSIX return ::getpid(); #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -74,7 +73,7 @@ namespace System #elif POSIX return 0 == ::chdir(dir.c_str() ); #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -87,7 +86,7 @@ namespace System #elif POSIX return 0 == ::kill(pid, 0); #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -106,7 +105,7 @@ namespace System #elif POSIX return 0 == ::kill(pid, signal); #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -117,7 +116,7 @@ namespace System #elif POSIX return 0 != ::pthread_kill(handle, 0); #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -135,7 +134,7 @@ namespace System return std::string(buf.cbegin(), buf.cbegin() + len); #endif #elif POSIX - const char *buf = ::getenv("TMPDIR"); + const char *buf = ::getenv("TMPDIR"); if (nullptr == buf) { return std::string("/tmp/"); @@ -149,7 +148,7 @@ namespace System return str; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -179,12 +178,15 @@ namespace System return S_ISREG(attrib.st_mode); #else - #error "Undefine platform" + #error "Undefined platform" #endif } - bool getFileSizeAndTimeGmt(const std::string &filePath, size_t *fileSize, time_t *fileTime) - { + bool getFileSizeAndTimeGmt( + const std::string &filePath, + size_t *fileSize, + time_t *fileTime + ) { #ifdef WIN32 #ifdef UNICODE std::wstring_convert> converter; @@ -193,7 +195,15 @@ namespace System const std::string &file_path = filePath; #endif - const ::HANDLE hFile = ::CreateFile(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + const ::HANDLE hFile = ::CreateFile( + file_path.c_str(), + GENERIC_READ, + FILE_SHARE_READ, + nullptr, + OPEN_EXISTING, + 0, + nullptr + ); if (INVALID_HANDLE_VALUE == hFile) { return false; @@ -206,7 +216,12 @@ namespace System ::FILETIME ftWrite; - ::BOOL result = ::GetFileTime(hFile, nullptr, nullptr, &ftWrite); + ::BOOL result = ::GetFileTime( + hFile, + nullptr, + nullptr, + &ftWrite + ); ::CloseHandle(hFile); @@ -227,7 +242,7 @@ namespace System stUtc.wYear - 1900, 0, 0, - -1 + -1 }; *fileTime = std::mktime(&tm_time); @@ -240,7 +255,7 @@ namespace System return false; } - *fileSize = attrib.st_size; + *fileSize = static_cast(attrib.st_size); std::tm clock {}; @@ -250,7 +265,7 @@ namespace System return true; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -269,7 +284,10 @@ namespace System const size_t pos = memory_name.rfind(file_ext); if (pos == memory_name.length() - file_ext.length() ) { - memory_name.erase(memory_name.begin() + pos, memory_name.end() ); + memory_name.erase( + pos, + memory_name.length() + ); } ::TCHAR buf[MAX_PATH + 1] {}; @@ -297,7 +315,7 @@ namespace System } } #else - #error "Undefine platform" + #error "Undefined platform" #endif } } diff --git a/src/system/System.h b/src/system/System.h index 3b5b1bc..8b637d4 100644 --- a/src/system/System.h +++ b/src/system/System.h @@ -1,33 +1,35 @@ -#pragma once +#pragma once #ifdef WIN32 #include - typedef long ssize_t; + #ifndef ssize_t + typedef long ssize_t; + #endif ::TCHAR myWndClassName[]; - #ifdef SIGTERM - #undef SIGTERM - #define SIGTERM (WM_USER + 15) - #endif + #ifdef SIGTERM + #undef SIGTERM + #define SIGTERM (WM_USER + 15) + #endif - #ifdef SIGINT - #undef SIGINT - #define SIGINT (WM_USER + 2) - #endif + #ifdef SIGINT + #undef SIGINT + #define SIGINT (WM_USER + 2) + #endif - #ifndef SIGUSR1 - #define SIGUSR1 (WM_USER + 10) - #endif + #ifndef SIGUSR1 + #define SIGUSR1 (WM_USER + 10) + #endif - #ifndef SIGUSR2 - #define SIGUSR2 (WM_USER + 12) - #endif + #ifndef SIGUSR2 + #define SIGUSR2 (WM_USER + 12) + #endif #elif POSIX #include #else - #error "Undefine platform" + #error "Undefined platform" #endif #include @@ -41,7 +43,7 @@ namespace System #elif POSIX typedef int native_socket_type; #else - #error "Undefine platform" + #error "Undefined platform" #endif #ifdef WIN32 @@ -49,7 +51,7 @@ namespace System #elif POSIX typedef ::pid_t native_processid_type; #else - #error "Undefine platform" + #error "Undefined platform" #endif native_processid_type getProcessId() noexcept; diff --git a/src/transfer/AppRequest.h b/src/transfer/AppRequest.h index b345a51..52d894e 100644 --- a/src/transfer/AppRequest.h +++ b/src/transfer/AppRequest.h @@ -7,15 +7,13 @@ namespace Transfer { - struct request_data - { + struct request_data { std::unordered_multimap incoming_headers; std::unordered_multimap incoming_data; std::unordered_multimap incoming_files; }; - struct app_request - { + struct app_request { const System::native_socket_type socket; const ::gnutls_session_t tls_session; const void * const request_data; diff --git a/src/transfer/AppResponse.h b/src/transfer/AppResponse.h index 51ff300..e059e55 100644 --- a/src/transfer/AppResponse.h +++ b/src/transfer/AppResponse.h @@ -5,8 +5,7 @@ namespace Transfer { - struct app_response - { + struct app_response { void *response_data; size_t data_size; }; diff --git a/src/transfer/FileIncoming.cpp b/src/transfer/FileIncoming.cpp index ed2c49f..07fb877 100644 --- a/src/transfer/FileIncoming.cpp +++ b/src/transfer/FileIncoming.cpp @@ -6,23 +6,34 @@ namespace Transfer { - FileIncoming::FileIncoming(std::string &&fileTmpName, std::string &&fileName, std::string &&fileType, const size_t fileSize) noexcept - : file_tmp_name(std::move(fileTmpName) ), file_name(std::move(fileName) ), - file_type(std::move(fileType) ), file_size(fileSize) + FileIncoming::FileIncoming( + std::string &&fileTmpName, + std::string &&fileName, + std::string &&fileType, + const size_t fileSize + ) noexcept + : file_tmp_name(std::move(fileTmpName) ), + file_name(std::move(fileName) ), + file_type(std::move(fileType) ), + file_size(fileSize) { } FileIncoming::FileIncoming(const FileIncoming &obj) - : file_tmp_name(obj.file_tmp_name), file_name(obj.file_name), - file_type(obj.file_type), file_size(obj.file_size) + : file_tmp_name(obj.file_tmp_name), + file_name(obj.file_name), + file_type(obj.file_type), + file_size(obj.file_size) { } FileIncoming::FileIncoming(FileIncoming &&obj) noexcept - : file_tmp_name(std::move(obj.file_tmp_name) ), file_name(std::move(obj.file_name) ), - file_type(std::move(obj.file_type) ), file_size(obj.file_size) + : file_tmp_name(std::move(obj.file_tmp_name) ), + file_name(std::move(obj.file_name) ), + file_type(std::move(obj.file_type) ), + file_size(obj.file_size) { obj.file_size = 0; } @@ -53,8 +64,10 @@ namespace Transfer namespace Utils { - void packFilesIncoming(std::vector &buf, const std::unordered_multimap &map) - { + void packFilesIncoming( + std::vector &buf, + const std::unordered_multimap &map + ) { packNumber(buf, map.size() ); for (auto it = map.cbegin(); map.cend() != it; ++it) { @@ -69,8 +82,10 @@ namespace Utils } } - const uint8_t *unpackFilesIncoming(std::unordered_multimap &map, const uint8_t *src) - { + const uint8_t *unpackFilesIncoming( + std::unordered_multimap &map, + const uint8_t *src + ) { size_t count; src = unpackNumber(&count, src); @@ -90,7 +105,15 @@ namespace Utils size_t file_size; src = unpackNumber(&file_size, src); - map.emplace(std::move(key), Transfer::FileIncoming(std::move(file_tmp_name), std::move(file_name), std::move(file_type), file_size) ); + map.emplace( + std::move(key), + Transfer::FileIncoming( + std::move(file_tmp_name), + std::move(file_name), + std::move(file_type), + file_size + ) + ); } return src; diff --git a/src/transfer/FileIncoming.h b/src/transfer/FileIncoming.h index 8070d0d..448c8c8 100644 --- a/src/transfer/FileIncoming.h +++ b/src/transfer/FileIncoming.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -16,7 +16,14 @@ namespace Transfer public: FileIncoming() = default; - FileIncoming(std::string &&fileTmpName, std::string &&fileName, std::string &&fileType, const size_t fileSize) noexcept; + + FileIncoming( + std::string &&fileTmpName, + std::string &&fileName, + std::string &&fileType, + const size_t fileSize + ) noexcept; + FileIncoming(const FileIncoming &obj); FileIncoming(FileIncoming &&obj) noexcept; @@ -35,6 +42,13 @@ namespace Transfer namespace Utils { - void packFilesIncoming(std::vector &buf, const std::unordered_multimap &map); - const uint8_t *unpackFilesIncoming(std::unordered_multimap &map, const uint8_t *src); + void packFilesIncoming( + std::vector &buf, + const std::unordered_multimap &map + ); + + const uint8_t *unpackFilesIncoming( + std::unordered_multimap &map, + const uint8_t *src + ); } diff --git a/src/transfer/HttpStatusCode.h b/src/transfer/HttpStatusCode.h index a560814..abb0c85 100644 --- a/src/transfer/HttpStatusCode.h +++ b/src/transfer/HttpStatusCode.h @@ -2,8 +2,7 @@ namespace Http { - enum class StatusCode - { + enum class StatusCode { EMPTY = 0, CONTINUE = 100, diff --git a/src/transfer/ProtocolVariant.h b/src/transfer/ProtocolVariant.h index fca95ef..093a02a 100644 --- a/src/transfer/ProtocolVariant.h +++ b/src/transfer/ProtocolVariant.h @@ -2,8 +2,7 @@ namespace Transfer { - enum class ProtocolVariant - { + enum class ProtocolVariant { UNKNOWN = 0, HTTP_1, HTTP_2 diff --git a/src/transfer/http2/HPack.cpp b/src/transfer/http2/HPack.cpp index 7075b2f..b8d0128 100644 --- a/src/transfer/http2/HPack.cpp +++ b/src/transfer/http2/HPack.cpp @@ -11,8 +11,7 @@ namespace HPack { - struct HuffmanSymbol - { + struct HuffmanSymbol { int nbits; uint32_t code; }; @@ -277,8 +276,7 @@ namespace HPack {30, 0x3fffffff}, }; - struct HuffmanDecodeNode - { + struct HuffmanDecodeNode { uint8_t state; uint8_t flags; uint8_t symbol; @@ -5218,22 +5216,27 @@ namespace HPack return sizeof(staticTable) / sizeof(*staticTable); } - static size_t huffmanEncodeLength(const void *dest, const size_t length) noexcept - { + static size_t huffmanEncodeLength( + const void *dest, + const size_t length + ) noexcept { const uint8_t *data = reinterpret_cast(dest); size_t n = 0; for (size_t i = 0; i < length; ++i) { - n += huffmanSymbolTable[data[i] ].nbits; + n += size_t(huffmanSymbolTable[data[i] ].nbits); } return (n + 7) / 8; } - static uint8_t huffmanEncodeSymbol(std::vector &dest, uint8_t rembits, const HuffmanSymbol &sym) - { - uint8_t nbits = sym.nbits; + static uint8_t huffmanEncodeSymbol( + std::vector &dest, + uint8_t rembits, + const HuffmanSymbol &sym + ) { + uint8_t nbits = uint8_t(sym.nbits); for (;;) { if (rembits > nbits) { @@ -5257,8 +5260,11 @@ namespace HPack return rembits; } - static void encode(std::vector &dest, const void* src, const size_t srcSize) - { + static void encode( + std::vector &dest, + const void* src, + const size_t srcSize + ) { const uint8_t *data = reinterpret_cast(src); uint8_t rembits = 8; @@ -5279,15 +5285,17 @@ namespace HPack } } - enum HuffmanDecode - { + enum HuffmanDecode { ACCEPT = 0x1, SYMBOL = 0x2, FAIL = 0x4 }; - static bool decode(std::vector &dest, const void* src, const size_t srcSize) - { + static bool decode( + std::vector &dest, + const void* src, + const size_t srcSize + ) { const uint8_t *data = reinterpret_cast(src); const uint8_t *end = data + srcSize; @@ -5321,9 +5329,12 @@ namespace HPack return accept; } - static void packInteger(std::vector &dest, uint64_t num, const uint8_t prefix) - { - uint64_t k = (1 << prefix) - 1; + static void packInteger( + std::vector &dest, + uint64_t num, + const uint8_t prefix + ) { + const uint64_t k = (1 << prefix) - 1; if (num < k) { dest.emplace_back(num); @@ -5350,14 +5361,19 @@ namespace HPack } } - static void packIndex(std::vector &dest, const size_t index) { + static void packIndex( + std::vector &dest, + const size_t index + ) { const size_t head = dest.size(); packInteger(dest, index, 7); dest[head] |= 0x80; } - static std::tuple findHeaderInTable(const std::pair &header, const Http2::DynamicTable &dynamicTable) - { + static std::tuple findHeaderInTable( + const std::pair &header, + const Http2::DynamicTable &dynamicTable + ) { std::tuple result { 0, false }; @@ -5423,19 +5439,31 @@ namespace HPack dest[head] |= 0x80; } else { packInteger(dest, str.length(), 7); - std::copy(str.cbegin(), str.cend(), std::back_inserter(dest) ); + + dest.insert( + dest.end(), + str.cbegin(), + str.cend() + ); } } - static void packFullHeader(std::vector &dest, const std::pair &header, const bool indexing) - { + static void packFullHeader( + std::vector &dest, + const std::pair &header, + const bool indexing + ) { dest.emplace_back(packFirstByte(indexing) ); packString(dest, header.first); packString(dest, header.second); } - static void packHeaderValue(std::vector &dest, const size_t keyIndex, const std::pair &header, const bool indexing) - { + static void packHeaderValue( + std::vector &dest, + const size_t keyIndex, + const std::pair &header, + const bool indexing + ) { const size_t head = dest.size(); const uint8_t prefix = indexing ? 6 : 4; @@ -5458,8 +5486,11 @@ namespace HPack return false; } - static void packHeader(std::vector &dest, const std::pair &header, Http2::DynamicTable &dynamicTable) - { + static void packHeader( + std::vector &dest, + const std::pair &header, + Http2::DynamicTable &dynamicTable + ) { size_t index; bool is_full_match; @@ -5492,23 +5523,24 @@ namespace HPack dest[head] |= 0x20; } */ - void pack(std::vector &dest, const std::vector > &headers, Http2::DynamicTable &dynamicTable) - { + void pack( + std::vector &dest, + const std::vector > &headers, + Http2::DynamicTable &dynamicTable + ) { for (auto const &header : headers) { packHeader(dest, header, dynamicTable); } } - enum class HuffmanDecodeOpcode - { + enum class HuffmanDecodeOpcode { NONE, INDEXED, NOT_INDEXED, INDEXED_KEY, }; - enum class HuffmanDecodeState - { + enum class HuffmanDecodeState { OPCODE, READ_TABLE_SIZE, READ_INDEX, @@ -5526,8 +5558,10 @@ namespace HPack return getStaticTableSize() + stream.conn.decoding_dynamic_table.size(); } - static const std::pair *getHeaderFromTable(const size_t index, const Http2::IncStream &stream) noexcept - { + static const std::pair *getHeaderFromTable( + const size_t index, + const Http2::IncStream &stream + ) noexcept { if (getStaticTableSize() >= index) { return &staticTable[index - 1]; } @@ -5538,7 +5572,10 @@ namespace HPack return nullptr; } - static const std::pair *unpackIndexed(const size_t index, const Http2::IncStream &stream) noexcept { + static const std::pair *unpackIndexed( + const size_t index, + const Http2::IncStream &stream + ) noexcept { return getHeaderFromTable(index, stream); } @@ -5546,8 +5583,12 @@ namespace HPack return c & (1 << 7); } - static std::tuple unpackHuffman(std::vector &dest, const uint8_t *data, const size_t dataSize, const uint64_t left) - { + static std::tuple unpackHuffman( + std::vector &dest, + const uint8_t *data, + const size_t dataSize, + const uint64_t left + ) { std::tuple result { left, false }; @@ -5556,24 +5597,42 @@ namespace HPack std::get(result) = dataSize; } - std::get(result) = decode(dest, data, std::get(result) ); + std::get(result) = decode( + dest, + data, + std::get(result) + ); return result; } - static uint64_t unpackString(std::vector &dest, const uint8_t *data, const size_t dataSize, uint64_t left) - { + static uint64_t unpackString( + std::vector &dest, + const uint8_t *data, + const size_t dataSize, + uint64_t left + ) { if (dataSize < left) { left = dataSize; } - std::copy(data, data + left, std::back_inserter(dest) ); + dest.insert( + dest.end(), + data, + data + left + ); return left; } - static std::tuple unpackInteger(const uint8_t *data, const size_t dataSize, const uint64_t initial, const uint8_t initialShift, const uint8_t prefix) - { + static std::tuple + unpackInteger( + const uint8_t *data, + const size_t dataSize, + const uint64_t initial, + const uint8_t initialShift, + const uint8_t prefix + ) { std::tuple result { initial, 0, initialShift, true }; @@ -5582,7 +5641,7 @@ namespace HPack uint64_t &nread = std::get<1>(result); uint8_t &shift = std::get(result); - uint8_t k = (1 << prefix) - 1; + const uint8_t k = uint8_t(1 << prefix) - 1; if (0 == num) { @@ -5658,8 +5717,8 @@ namespace HPack std::pair unpackFullHeader(Http2::IncStream &stream) { std::pair header { - std::string(this->buf.cbegin(), this->buf.cbegin() + this->key_length), - std::string(this->buf.cbegin() + this->key_length, this->buf.cend() ) + std::string(this->buf.cbegin(), this->buf.cbegin() + long(this->key_length)), + std::string(this->buf.cbegin() + long(this->key_length), this->buf.cend() ) }; this->buf.clear(); @@ -5695,8 +5754,11 @@ namespace HPack } }; - bool unpack(const void *src, const size_t srcSize, Http2::IncStream &stream) - { + bool unpack( + const void *src, + const size_t srcSize, + Http2::IncStream &stream + ) { const uint8_t *data = reinterpret_cast(src); size_t cur = 0; @@ -5743,7 +5805,13 @@ namespace HPack uint64_t nread; bool success; - std::tie(dec.left, nread, dec.shift, success) = unpackInteger(data + cur, srcSize - cur, dec.left, dec.shift, 5); + std::tie(dec.left, nread, dec.shift, success) = unpackInteger( + data + cur, + srcSize - cur, + dec.left, + dec.shift, + 5 + ); cur += nread; @@ -5756,7 +5824,9 @@ namespace HPack return false; } - stream.conn.decoding_dynamic_table.changeHeaderTableSize(dec.left); + stream.conn.decoding_dynamic_table.changeHeaderTableSize( + static_cast(dec.left) + ); dec.state = HuffmanDecodeState::OPCODE; @@ -5779,7 +5849,13 @@ namespace HPack uint64_t nread; bool success; - std::tie(dec.left, nread, dec.shift, success) = unpackInteger(data + cur, srcSize - cur, dec.left, dec.shift, prefixlen); + std::tie(dec.left, nread, dec.shift, success) = unpackInteger( + data + cur, + srcSize - cur, + dec.left, + dec.shift, + prefixlen + ); cur += nread; @@ -5811,7 +5887,13 @@ namespace HPack uint64_t nread; bool success; - std::tie(dec.left, nread, dec.shift, success) = unpackInteger(data + cur, srcSize - cur, dec.left, dec.shift, 7); + std::tie(dec.left, nread, dec.shift, success) = unpackInteger( + data + cur, + srcSize - cur, + dec.left, + dec.shift, + 7 + ); cur += nread; @@ -5819,9 +5901,9 @@ namespace HPack return false; } - dec.state = dec.huffman_encoded ? - HuffmanDecodeState::READ_KEY_HUFFMAN : - HuffmanDecodeState::READ_KEY; + dec.state = dec.huffman_encoded + ? HuffmanDecodeState::READ_KEY_HUFFMAN + : HuffmanDecodeState::READ_KEY; break; } @@ -5831,7 +5913,12 @@ namespace HPack uint64_t nread; bool success; - std::tie(nread, success) = unpackHuffman(dec.buf, data + cur, srcSize - cur, dec.left); + std::tie(nread, success) = unpackHuffman( + dec.buf, + data + cur, + srcSize - cur, + dec.left + ); cur += nread; dec.left -= nread; @@ -5849,7 +5936,12 @@ namespace HPack case HuffmanDecodeState::READ_KEY: { - const uint64_t nread = unpackString(dec.buf, data + cur, srcSize - cur, dec.left); + const uint64_t nread = unpackString( + dec.buf, + data + cur, + srcSize - cur, + dec.left + ); cur += nread; dec.left -= nread; @@ -5878,7 +5970,13 @@ namespace HPack uint64_t nread; bool success; - std::tie(dec.left, nread, dec.shift, success) = unpackInteger(data + cur, srcSize - cur, dec.left, dec.shift, 7); + std::tie(dec.left, nread, dec.shift, success) = unpackInteger( + data + cur, + srcSize - cur, + dec.left, + dec.shift, + 7 + ); cur += nread; @@ -5888,18 +5986,18 @@ namespace HPack if (0 == dec.left) { - HuffmanDecodeOpcode::NOT_INDEXED == dec.opcode ? - stream.incoming_headers.emplace(dec.unpackFullHeader(stream) ) : - stream.incoming_headers.emplace(dec.unpackHeaderValue(stream) ); + HuffmanDecodeOpcode::NOT_INDEXED == dec.opcode + ? stream.incoming_headers.emplace(dec.unpackFullHeader(stream) ) + : stream.incoming_headers.emplace(dec.unpackHeaderValue(stream) ); dec.state = HuffmanDecodeState::OPCODE; break; } - dec.state = dec.huffman_encoded ? - HuffmanDecodeState::READ_VALUE_HUFFMAN : - HuffmanDecodeState::READ_VALUE; + dec.state = dec.huffman_encoded + ? HuffmanDecodeState::READ_VALUE_HUFFMAN + : HuffmanDecodeState::READ_VALUE; break; } @@ -5909,7 +6007,12 @@ namespace HPack uint64_t nread; bool success; - std::tie(nread, success) = unpackHuffman(dec.buf, data + cur, srcSize - cur, dec.left); + std::tie(nread, success) = unpackHuffman( + dec.buf, + data + cur, + srcSize - cur, + dec.left + ); cur += nread; dec.left -= nread; @@ -5918,9 +6021,9 @@ namespace HPack return false; } - HuffmanDecodeOpcode::NOT_INDEXED == dec.opcode ? - stream.incoming_headers.emplace(dec.unpackFullHeader(stream) ) : - stream.incoming_headers.emplace(dec.unpackHeaderValue(stream) ); + HuffmanDecodeOpcode::NOT_INDEXED == dec.opcode + ? stream.incoming_headers.emplace(dec.unpackFullHeader(stream) ) + : stream.incoming_headers.emplace(dec.unpackHeaderValue(stream) ); dec.state = HuffmanDecodeState::OPCODE; @@ -5929,7 +6032,12 @@ namespace HPack case HuffmanDecodeState::READ_VALUE: { - const uint64_t nread = unpackString(dec.buf, data + cur, srcSize - cur, dec.left); + const uint64_t nread = unpackString( + dec.buf, + data + cur, + srcSize - cur, + dec.left + ); cur += nread; dec.left -= nread; @@ -5938,9 +6046,9 @@ namespace HPack return false; } - HuffmanDecodeOpcode::NOT_INDEXED == dec.opcode ? - stream.incoming_headers.emplace(dec.unpackFullHeader(stream) ) : - stream.incoming_headers.emplace(dec.unpackHeaderValue(stream) ); + HuffmanDecodeOpcode::NOT_INDEXED == dec.opcode + ? stream.incoming_headers.emplace(dec.unpackFullHeader(stream) ) + : stream.incoming_headers.emplace(dec.unpackHeaderValue(stream) ); dec.state = HuffmanDecodeState::OPCODE; diff --git a/src/transfer/http2/HPack.h b/src/transfer/http2/HPack.h index b467a15..c030a7f 100644 --- a/src/transfer/http2/HPack.h +++ b/src/transfer/http2/HPack.h @@ -8,8 +8,16 @@ namespace HPack { - void pack(std::vector &dest, const std::vector > &headers, Http2::DynamicTable &dynamicTable); + void pack( + std::vector &dest, + const std::vector > &headers, + Http2::DynamicTable &dynamicTable + ); // TODO: replace IncStream to DynamicTable if possible - bool unpack(const void *src, const size_t srcSize, Http2::IncStream &stream); + bool unpack( + const void *src, + const size_t srcSize, + Http2::IncStream &stream + ); } diff --git a/src/transfer/http2/Http2.cpp b/src/transfer/http2/Http2.cpp index ed7b963..71c60c9 100644 --- a/src/transfer/http2/Http2.cpp +++ b/src/transfer/http2/Http2.cpp @@ -4,16 +4,29 @@ namespace Http2 { - bool operator &(const FrameFlag left, const FrameFlag right) noexcept { + bool operator &( + const FrameFlag left, + const FrameFlag right + ) noexcept { return static_cast(left) & static_cast(right); } - FrameFlag operator |(const FrameFlag left, const FrameFlag right) noexcept { - return static_cast(static_cast(left) | static_cast(right) ); + FrameFlag operator |( + const FrameFlag left, + const FrameFlag right + ) noexcept { + return static_cast( + static_cast(left) | static_cast(right) + ); } - FrameFlag operator |=(FrameFlag &left, const FrameFlag right) noexcept { - return static_cast(*reinterpret_cast(&left) |= static_cast(right) ); + FrameFlag operator |=( + FrameFlag &left, + const FrameFlag right + ) noexcept { + return static_cast( + *reinterpret_cast(&left) |= static_cast(right) + ); } ConnectionSettings ConnectionSettings::defaultSettings() noexcept { @@ -28,7 +41,9 @@ namespace Http2 } DynamicTable::DynamicTable() noexcept - : header_table_size(0), max_header_list_size(0), cur_header_list_size(0) + : header_table_size(0), + max_header_list_size(0), + cur_header_list_size(0) { } @@ -37,8 +52,15 @@ namespace Http2 return this->list.size(); } - DynamicTable::DynamicTable(const uint32_t headerTableSize, const uint32_t maxHeaderListSize, std::deque > &&list) noexcept - : list(std::move(list) ), header_table_size(headerTableSize), max_header_list_size(maxHeaderListSize), cur_header_list_size(0) + DynamicTable::DynamicTable( + const uint32_t headerTableSize, + const uint32_t maxHeaderListSize, + std::deque > &&list + ) noexcept + : list(std::move(list) ), + header_table_size(headerTableSize), + max_header_list_size(maxHeaderListSize), + cur_header_list_size(0) { for (auto const &pair : list) { this->cur_header_list_size += pair.first.length() + pair.second.length(); @@ -51,8 +73,12 @@ namespace Http2 this->list.emplace_front(header); - while (this->list.size() > this->header_table_size || (0 != this->max_header_list_size && this->cur_header_list_size > this->max_header_list_size) ) - { + while ( + this->list.size() > this->header_table_size || ( + this->max_header_list_size != 0 && + this->cur_header_list_size > this->max_header_list_size + ) + ) { auto const &pair = this->list.back(); this->cur_header_list_size -= pair.first.length() + pair.second.length(); @@ -67,8 +93,12 @@ namespace Http2 this->list.emplace_front(std::move(header) ); - while (this->list.size() > this->header_table_size || (0 != this->max_header_list_size && this->cur_header_list_size > this->max_header_list_size) ) - { + while ( + this->list.size() > this->header_table_size || ( + this->max_header_list_size != 0 && + this->cur_header_list_size > this->max_header_list_size + ) + ) { auto const &pair = this->list.back(); this->cur_header_list_size -= pair.first.length() + pair.second.length(); @@ -94,8 +124,10 @@ namespace Http2 { this->max_header_list_size = maxHeaderListSize; - while (0 != this->max_header_list_size && this->cur_header_list_size > this->max_header_list_size) - { + while ( + this->max_header_list_size != 0 && + this->cur_header_list_size > this->max_header_list_size + ) { auto const &pair = this->list.back(); this->cur_header_list_size -= pair.first.length() + pair.second.length(); @@ -104,11 +136,13 @@ namespace Http2 } } - const std::pair &DynamicTable::operator[](const size_t index) const noexcept { + const std::pair & + DynamicTable::operator[](const size_t index) const noexcept { return this->list[index]; } - std::pair &DynamicTable::operator[](const size_t index) noexcept { + std::pair & + DynamicTable::operator[](const size_t index) noexcept { return this->list[index]; } @@ -117,15 +151,23 @@ namespace Http2 } IncStream::IncStream(const uint32_t streamId, ConnectionData &conn) noexcept - : conn(conn), window_size_inc(conn.server_settings.initial_window_size), - window_size_out(conn.client_settings.initial_window_size), stream_id(streamId), - state(StreamState::IDLE), priority(0), reserved(nullptr) + : conn(conn), + window_size_inc(int32_t(conn.server_settings.initial_window_size)), + window_size_out(int32_t(conn.client_settings.initial_window_size)), + stream_id(streamId), + state(StreamState::IDLE), + priority(0), + reserved(nullptr) { } - uint8_t *IncStream::setHttp2FrameHeader(uint8_t *addr, const uint32_t frameSize, const Http2::FrameType frameType, const Http2::FrameFlag frameFlags) noexcept - { + uint8_t *IncStream::setHttp2FrameHeader( + uint8_t *addr, + const uint32_t frameSize, + const Http2::FrameType frameType, + const Http2::FrameFlag frameFlags + ) noexcept { Utils::hton24(addr, frameSize); *(addr + 3) = static_cast(frameType); *(addr + 4) = static_cast(frameFlags); @@ -142,8 +184,7 @@ namespace Http2 this->conn.sync.mtx.unlock(); } - void IncStream::close() noexcept - { + void IncStream::close() noexcept { this->incoming_headers.clear(); this->incoming_data.clear(); this->incoming_files.clear(); @@ -155,21 +196,37 @@ namespace Http2 // this->state = StreamState::CLOSED; } - OutStream::OutStream(const uint32_t streamId, const ConnectionSettings &settings, DynamicTable &&dynamic_table, std::mutex *mtx) noexcept - : stream_id(streamId), settings(settings), window_size_out(settings.initial_window_size), dynamic_table(std::move(dynamic_table) ), mtx(mtx) + OutStream::OutStream( + const uint32_t streamId, + const ConnectionSettings &settings, + DynamicTable &&dynamic_table, + std::mutex *mtx + ) noexcept + : stream_id(streamId), + window_size_out(int32_t(settings.initial_window_size)), + settings(settings), + dynamic_table(std::move(dynamic_table) ), + mtx(mtx) { } OutStream::OutStream(const IncStream &stream) - : stream_id(stream.stream_id), settings(stream.conn.client_settings), - window_size_out(stream.window_size_out), dynamic_table(stream.conn.encoding_dynamic_table), mtx(&stream.conn.sync.mtx) + : stream_id(stream.stream_id), + window_size_out(stream.window_size_out), + settings(stream.conn.client_settings), + dynamic_table(stream.conn.encoding_dynamic_table), + mtx(&stream.conn.sync.mtx) { } - uint8_t *OutStream::setHttp2FrameHeader(uint8_t *addr, const uint32_t frameSize, const Http2::FrameType frameType, const Http2::FrameFlag frameFlags) noexcept - { + uint8_t *OutStream::setHttp2FrameHeader( + uint8_t *addr, + const uint32_t frameSize, + const Http2::FrameType frameType, + const Http2::FrameFlag frameFlags + ) noexcept { Utils::hton24(addr, frameSize); *(addr + 3) = static_cast(frameType); *(addr + 4) = static_cast(frameFlags); diff --git a/src/transfer/http2/Http2.h b/src/transfer/http2/Http2.h index 12b6d65..f4927f2 100644 --- a/src/transfer/http2/Http2.h +++ b/src/transfer/http2/Http2.h @@ -17,8 +17,7 @@ namespace Http2 { - enum class ErrorCode : uint32_t - { + enum class ErrorCode : uint32_t { NO_ERROR = 0x0, PROTOCOL_ERROR, INTERNAL_ERROR, @@ -35,8 +34,7 @@ namespace Http2 HTTP_1_1_REQUIRED }; - enum class FrameType : uint8_t - { + enum class FrameType : uint8_t { DATA = 0x0, HEADERS, PRIORITY, @@ -49,8 +47,7 @@ namespace Http2 CONTINUATION }; - enum class FrameFlag : uint8_t - { + enum class FrameFlag : uint8_t { EMPTY = 0x0, ACK = 0x1, END_STREAM = 0x1, @@ -63,8 +60,7 @@ namespace Http2 FrameFlag operator |(const FrameFlag left, const FrameFlag right) noexcept; FrameFlag operator |=(FrameFlag &left, const FrameFlag right) noexcept; - struct FrameMeta - { + struct FrameMeta { uint32_t stream_id; uint32_t length; FrameType type; @@ -72,10 +68,9 @@ namespace Http2 }; constexpr uint32_t FRAME_HEADER_SIZE = 9; - constexpr uint32_t MAX_WINDOW_UPDATE = uint32_t(1 << 31) - 1; + constexpr uint32_t MAX_WINDOW_UPDATE = (uint32_t(1) << 31) - 1; - enum class ConnectionSetting : uint16_t - { + enum class ConnectionSetting : uint16_t { SETTINGS_HEADER_TABLE_SIZE = 0x1, SETTINGS_ENABLE_PUSH = 0x2, SETTINGS_MAX_CONCURRENT_STREAMS = 0x3, @@ -84,8 +79,7 @@ namespace Http2 SETTINGS_MAX_HEADER_LIST_SIZE = 0x6 }; - struct ConnectionSettings - { + struct ConnectionSettings { uint32_t header_table_size; uint32_t enable_push; uint32_t max_concurrent_streams; @@ -96,8 +90,7 @@ namespace Http2 static ConnectionSettings defaultSettings() noexcept; }; - enum class StreamState : uint8_t - { + enum class StreamState : uint8_t { IDLE, RESERVED, OPEN, @@ -105,8 +98,7 @@ namespace Http2 CLOSED }; - struct ConnectionSync - { + struct ConnectionSync { Utils::Event event; std::mutex mtx; std::atomic completed {}; @@ -124,7 +116,12 @@ namespace Http2 public: DynamicTable() noexcept; - DynamicTable(const uint32_t headerTableSize, const uint32_t maxHeaderListSize, std::deque > &&list) noexcept; + + DynamicTable( + const uint32_t headerTableSize, + const uint32_t maxHeaderListSize, + std::deque > &&list + ) noexcept; size_t size() const noexcept; @@ -134,14 +131,17 @@ namespace Http2 void changeHeaderTableSize(const uint32_t headerTableSize); void changeMaxHeaderListSize(const uint32_t maxHeaderListSize); - const std::pair &operator[](const size_t index) const noexcept; - std::pair &operator[](const size_t index) noexcept; + const std::pair & + operator[](const size_t index) const noexcept; - const std::deque > &getList() const noexcept; + std::pair & + operator[](const size_t index) noexcept; + + const std::deque > & + getList() const noexcept; }; - struct ConnectionData - { + struct ConnectionData { DynamicTable decoding_dynamic_table; DynamicTable encoding_dynamic_table; @@ -169,9 +169,17 @@ namespace Http2 void *reserved; public: - IncStream(const uint32_t streamId, ConnectionData &conn) noexcept; - - uint8_t *setHttp2FrameHeader(uint8_t *addr, const uint32_t frameSize, const Http2::FrameType frameType, const Http2::FrameFlag frameFlags) noexcept; + IncStream( + const uint32_t streamId, + ConnectionData &conn + ) noexcept; + + uint8_t *setHttp2FrameHeader( + uint8_t *addr, + const uint32_t frameSize, + const Http2::FrameType frameType, + const Http2::FrameFlag frameFlags + ) noexcept; void lock(); void unlock() noexcept; @@ -182,20 +190,29 @@ namespace Http2 struct OutStream { uint32_t stream_id; - - ConnectionSettings settings; - int32_t window_size_out; + ConnectionSettings settings; DynamicTable dynamic_table; std::mutex *mtx; public: - OutStream(const uint32_t streamId, const ConnectionSettings &settings, DynamicTable &&dynamic_table, std::mutex *mtx) noexcept; + OutStream( + const uint32_t streamId, + const ConnectionSettings &settings, + DynamicTable &&dynamic_table, + std::mutex *mtx + ) noexcept; + OutStream(const IncStream &stream); - uint8_t *setHttp2FrameHeader(uint8_t *addr, const uint32_t frameSize, const Http2::FrameType frameType, const Http2::FrameFlag frameFlags) noexcept; + uint8_t *setHttp2FrameHeader( + uint8_t *addr, + const uint32_t frameSize, + const Http2::FrameType frameType, + const Http2::FrameFlag frameFlags + ) noexcept; void lock(); void unlock() noexcept; diff --git a/src/utils/Event.cpp b/src/utils/Event.cpp index d768a8e..3c9fd01 100644 --- a/src/utils/Event.cpp +++ b/src/utils/Event.cpp @@ -32,7 +32,9 @@ namespace Utils if (this->signaled.load() == false) { std::unique_lock lck(this->mtx); - is_timeout = this->cv.wait_for(lck, ms, [this] { return this->notifed(); } ) == false; + is_timeout = false == this->cv.wait_for(lck, ms, [this] { + return this->notifed(); + }); } if (false == this->manually) { @@ -42,8 +44,9 @@ namespace Utils return is_timeout; } - bool Event::wait_until(const std::chrono::high_resolution_clock::time_point &tp) - { + bool Event::wait_until( + const std::chrono::high_resolution_clock::time_point &tp + ) { bool is_timeout = false; if (this->signaled.load() == false) { diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index 4ddc424..aacd218 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -32,7 +32,11 @@ namespace Utils return str.clear(); } - str.assign(str.cbegin() + str.find_first_not_of(whitespace.data() ), str.cbegin() + last + 1); + str.assign( + str, + str.find_first_not_of(whitespace.data() ), + last + 1 + ); } std::string getTrimmedString(const std::string &str) { @@ -103,13 +107,13 @@ namespace Utils static unsigned char hexStringToBinEncodeSymbol(const char c) noexcept { if (c >= '0' && c <= '9') { - return c - 0x30; + return static_cast(c - 0x30); } else if (c >= 'a' && c <= 'f') { - return c - 0x57; + return static_cast(c - 0x57); } else if (c >= 'A' && c <= 'F') { - return c - 0x37; + return static_cast(c - 0x37); } return 0; @@ -123,7 +127,7 @@ namespace Utils const char a = hexStr[i * 2 + 0]; const char b = hexStr[i * 2 + 1]; - bin[i] = ( + bin[i] = char( (hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b) ); } @@ -224,12 +228,16 @@ namespace Utils x.c[1] = addr[1]; x.c[2] = addr[0]; - return x.ui;// *reinterpret_cast(x.c); + return x.ui; } std::string getUniqueName() { - size_t time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + size_t time = size_t( + std::chrono::high_resolution_clock::now().time_since_epoch().count() + ); + time = hton64(time); + return binToHexString(&time, sizeof(time) ); } @@ -265,7 +273,7 @@ namespace Utils uint8_t *packNumber(uint8_t *dest, const size_t number) noexcept { if (number <= PACK_NUMBER_SIZE_BYTE) { - *dest = number; + *dest = static_cast(number); dest += sizeof(uint8_t); } @@ -343,12 +351,21 @@ namespace Utils packNumber(buf, str.length() ); if (str.length() ) { - std::copy(str.cbegin(), str.cend(), std::back_inserter(buf) ); + buf.insert( + buf.end(), + str.cbegin(), + str.cend() + ); } } const uint8_t *unpackPointer(void **pointer, const uint8_t *src) noexcept { - *pointer = *reinterpret_cast(const_cast(static_cast(src) ) ); + *pointer = *reinterpret_cast( + const_cast( + static_cast(src) + ) + ); + return src + sizeof(void *); } @@ -403,8 +420,7 @@ namespace Utils /** * Parse RFC 882 (ddd, dd MMM yyyy HH:mm:ss K) */ - time_t rfc822DatetimeToTimestamp(const std::string &strTime) - { + time_t rfc822DatetimeToTimestamp(const std::string &strTime) { std::tm tc {}; // Parse RFC 882 (ddd, dd MMM yyyy HH:mm:ss K) @@ -433,7 +449,7 @@ namespace Utils return ~0; } - tc.tm_mday = std::strtoul(strTime.data() + pos, nullptr, 10); + tc.tm_mday = std::atoi(strTime.data() + pos); pos = strTime.find_first_not_of(' ', delimiter + 1); delimiter = strTime.find_first_of(' ', pos); @@ -459,7 +475,7 @@ namespace Utils return ~0; } - tc.tm_year = std::strtoul(strTime.data() + pos, nullptr, 10) - 1900; + tc.tm_year = std::atoi(strTime.data() + pos) - 1900; pos = strTime.find_first_not_of(' ', delimiter + 1); delimiter = strTime.find_first_of(':', pos); @@ -468,7 +484,7 @@ namespace Utils return ~0; } - tc.tm_hour = std::strtoul(strTime.data() + pos, nullptr, 10); + tc.tm_hour = std::atoi(strTime.data() + pos); pos = strTime.find_first_not_of(' ', delimiter + 1); delimiter = strTime.find_first_of(':', pos); @@ -477,7 +493,7 @@ namespace Utils return ~0; } - tc.tm_min = std::strtoul(strTime.data() + pos, nullptr, 10); + tc.tm_min = std::atoi(strTime.data() + pos); pos = strTime.find_first_not_of(' ', delimiter + 1); delimiter = strTime.find_first_of(' ', pos); @@ -486,7 +502,7 @@ namespace Utils return ~0; } - tc.tm_sec = std::strtoul(strTime.data() + pos, nullptr, 10); + tc.tm_sec = std::atoi(strTime.data() + pos); pos = strTime.find_first_not_of(' ', delimiter + 1); delimiter = strTime.find_first_of(' ', pos); @@ -516,8 +532,8 @@ namespace Utils zone.copy(hours.data(), 2, 1); zone.copy(minutes.data(), 2, 3); - timezone = std::strtoul(hours.data(), nullptr, 10) * 3600; - timezone += std::strtoul(minutes.data(), nullptr, 10) * 60; + timezone = std::atoi(hours.data()) * 3600; + timezone += std::atoi(minutes.data()) * 60; if (zone.front() == '-') { timezone *= -1; @@ -584,7 +600,7 @@ namespace Utils return ~0; } - tc.tm_mday = std::strtoul(ptrStr, nullptr, 10); + tc.tm_mday = std::atoi(ptrStr); ++strTime; @@ -594,7 +610,7 @@ namespace Utils return ~0; } - tc.tm_year = std::strtoul(strTime, nullptr, 10) - 1900; + tc.tm_year = std::atoi(strTime) - 1900; ++ptrStr; @@ -604,7 +620,7 @@ namespace Utils return ~0; } - tc.tm_hour = std::strtoul(ptrStr, nullptr, 10); + tc.tm_hour = std::atoi(ptrStr); ++strTime; @@ -614,11 +630,11 @@ namespace Utils return ~0; } - tc.tm_min = std::strtoul(strTime, nullptr, 10); + tc.tm_min = std::atoi(strTime); ++ptrStr; - tc.tm_sec = std::strtoul(ptrStr, nullptr, 10); + tc.tm_sec = std::atoi(ptrStr); return localToGmt(std::mktime(&tc) ); } @@ -637,21 +653,29 @@ namespace Utils #ifdef WIN32 std::tm stm {}; - isGmtTime ? - ::localtime_s(&stm, &tTime) : - ::gmtime_s(&stm, &tTime); + isGmtTime + ? ::localtime_s(&stm, &tTime) + : ::gmtime_s(&stm, &tTime); - // RFC 822 - auto const len = std::strftime(buf.data(), buf.size(), "%a, %d %b %Y %H:%M:%S GMT", &stm); + auto const len = std::strftime( + buf.data(), + buf.size(), + "%a, %d %b %Y %H:%M:%S GMT", // RFC 822 + &stm + ); #else std::tm stm {}; - isGmtTime ? - ::localtime_r(&tTime, &stm) : - ::gmtime_r(&tTime, &stm); + isGmtTime + ? ::localtime_r(&tTime, &stm) + : ::gmtime_r(&tTime, &stm); - // RFC 822 - auto const len = std::strftime(buf.data(), buf.size(), "%a, %d %b %G %H:%M:%S GMT", &stm); + auto const len = std::strftime( + buf.data(), + buf.size(), + "%a, %d %b %G %H:%M:%S GMT", // RFC 822 + &stm + ); #endif return std::string(buf.data(), buf.data() + len); @@ -675,14 +699,19 @@ namespace Utils return length; } - bool parseCookies(const std::string &cookieHeader, std::unordered_multimap &cookies) - { + bool parseCookies( + const std::string &cookieHeader, + std::unordered_multimap &cookies + ) { if (cookieHeader.empty() ) { return true; } - for (size_t cur_pos = 0, next_value; std::string::npos != cur_pos; cur_pos = next_value) - { + for ( + size_t cur_pos = 0, next_value; + std::string::npos != cur_pos; + cur_pos = next_value + ) { next_value = cookieHeader.find(';', cur_pos); size_t delimiter = cookieHeader.find('=', cur_pos); @@ -691,17 +720,30 @@ namespace Utils return false; } - std::string key = cookieHeader.substr(cur_pos, delimiter - cur_pos); + std::string key = cookieHeader.substr( + cur_pos, + delimiter - cur_pos + ); + trim(key); key = urlDecode(key); ++delimiter; - std::string value = cookieHeader.substr(delimiter, std::string::npos != next_value ? next_value - delimiter : next_value); + std::string value = cookieHeader.substr( + delimiter, + std::string::npos != next_value + ? next_value - delimiter + : next_value + ); + trim(value); value = urlDecode(value); - cookies.emplace(std::move(key), std::move(value) ); + cookies.emplace( + std::move(key), + std::move(value) + ); if (std::string::npos != next_value) { ++next_value; @@ -723,10 +765,10 @@ namespace Utils for (size_t i = 0; i < str.length(); ++i) { - const unsigned char c = str[i]; + const unsigned char c = static_cast(str[i]); - if (std::isalnum(c) || isCharUrlAllowed(c) ) { - encoded.push_back(c); + if (std::isalnum(c) || isCharUrlAllowed(char(c) ) ) { + encoded.push_back(char(c) ); } else if (' ' == c) { encoded.push_back('+'); @@ -749,14 +791,14 @@ namespace Utils for (size_t i = 0; i < str.length(); ++i) { - unsigned char c = str[i]; + unsigned char c = static_cast(str[i]); if ('%' == c) { if (i + 2 < str.length() ) { const char a = str[++i]; const char b = str[++i]; - c = ( + c = static_cast( (hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b) ); } @@ -765,7 +807,7 @@ namespace Utils c = ' '; } - decoded.push_back(c); + decoded.push_back(char(c) ); } return decoded; diff --git a/src/utils/Utils.h b/src/utils/Utils.h index 340c6eb..551e975 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -128,7 +128,10 @@ namespace Utils size_t getNumberLength(size_t number) noexcept; - bool parseCookies(const std::string &cookieHeader, std::unordered_multimap &cookies); + bool parseCookies( + const std::string &cookieHeader, + std::unordered_multimap &cookies + ); std::string urlEncode(const std::string &str); std::string urlDecode(const std::string &str); From e269cde1d46c5e5c790fbed008c370251f391d4c Mon Sep 17 00:00:00 2001 From: awwit Date: Wed, 30 Mar 2022 00:13:42 +0300 Subject: [PATCH 31/31] refactor: unmask websocket frame without reallocation --- .gitignore | 2 ++ src/server/protocol/WebSocket.cpp | 16 ++++++---------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 378eac2..707f4da 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ build +projects/build* +projects/qt-creator/*.user diff --git a/src/server/protocol/WebSocket.cpp b/src/server/protocol/WebSocket.cpp index f80fac4..58bffd4 100644 --- a/src/server/protocol/WebSocket.cpp +++ b/src/server/protocol/WebSocket.cpp @@ -112,25 +112,21 @@ namespace HttpClient cur_pos += sizeof(uint32_t); } - const uint8_t align = (recv_size - cur_pos) % sizeof(uint32_t); - - frame.reserve(recv_size - cur_pos + align); + frame.reserve(recv_size - cur_pos); frame.assign(buf.cbegin() + cur_pos, buf.cbegin() + recv_size); if (is_mask_set) { - if (align) { - frame.insert(frame.cend(), align, 0); - } + const size_t aligned = frame.size() - (frame.size() % sizeof(mask)); - uint32_t *addr = reinterpret_cast(frame.data() ); + uint32_t * const addr = reinterpret_cast(frame.data() ); - for (size_t i = 0; i < frame.size() / sizeof(uint32_t); ++i) { + for (size_t i = 0; i < aligned / sizeof(uint32_t); ++i) { addr[i] ^= mask; } - if (align) { - frame.erase(frame.cend() - align, frame.cend() ); + for (size_t i = aligned; i < frame.size(); ++i) { + frame[i] ^= reinterpret_cast(&mask)[i % sizeof(mask)]; } }