From cf6d66e5d5f420ef276a32a5fdcc5ef731997626 Mon Sep 17 00:00:00 2001 From: awwit Date: Wed, 18 Mar 2015 16:50:00 +0300 Subject: [PATCH 01/50] Fixed minor bugs --- apps.conf | 2 +- httpserver.pro | 7 + httpserver.pro.user | 10 +- httpserver/DataVariantAbstract.h | 4 +- httpserver/DataVariantFormUrlencoded.cpp | 4 +- httpserver/DataVariantFormUrlencoded.h | 2 +- httpserver/DataVariantMultipartFormData.cpp | 76 +++++---- httpserver/DataVariantMultipartFormData.h | 2 +- httpserver/DataVariantTextPlain.cpp | 4 +- httpserver/DataVariantTextPlain.h | 2 +- httpserver/Module.cpp | 2 +- httpserver/Server.cpp | 59 +++++-- httpserver/SignalsHandles.cpp | 52 +++--- httpserver/Socket.cpp | 22 +-- httpserver/SocketList.cpp | 172 +++++++++++++++----- httpserver/SocketList.h | 7 +- httpserver/System.cpp | 37 ++++- httpserver/System.h | 38 +++-- 18 files changed, 343 insertions(+), 159 deletions(-) diff --git a/apps.conf b/apps.conf index 1a95d6c..bf7887f 100644 --- a/apps.conf +++ b/apps.conf @@ -1,7 +1,7 @@ server { listen 2280; server_name servertest www.servertest; - server_module /media/projects/sites/servertest/module/servertest_release.so; + server_module /media/projects/sites/servertest/module/appgameserver_debug.so; server_module_update /media/projects/httpserverapp/httpserverapp/bin/Release/libhttpserverapp.so; root_dir /media/projects/sites/servertest/www/; request_max_size 10485760; diff --git a/httpserver.pro b/httpserver.pro index 55ff0e2..7c10e82 100644 --- a/httpserver.pro +++ b/httpserver.pro @@ -5,8 +5,15 @@ CONFIG -= qt DEFINES += POSIX +CONFIG(debug, debug|release):DEFINES += DEBUG + QMAKE_CXXFLAGS += -std=c++11 +QMAKE_CFLAGS_RELEASE -= -O +QMAKE_CFLAGS_RELEASE -= -O1 +QMAKE_CFLAGS_RELEASE -= -O2 +QMAKE_CFLAGS_RELEASE *= -O3 + LIBS += -ldl -pthread SOURCES += \ diff --git a/httpserver.pro.user b/httpserver.pro.user index 1ba38e0..fac74c6 100644 --- a/httpserver.pro.user +++ b/httpserver.pro.user @@ -1,10 +1,10 @@ - + EnvironmentId - {9920746f-9985-46af-bb9c-6023d18266c8} + {1b4c0b3e-5aa0-412f-8f7e-3a13c2b330b9} ProjectExplorer.Project.ActiveTarget @@ -60,8 +60,8 @@ Desktop Desktop - {fb1b1040-2620-42ea-a3ce-627c9d29cc16} - 1 + {c77ee4a2-1c2a-4bac-9185-8378ec4ebf5d} + 0 0 0 @@ -235,7 +235,7 @@ 2 httpserver - httpserver2 + Qt4ProjectManager.Qt4RunConfiguration:/media/projects/httpserver/httpserver.pro --start httpserver.pro diff --git a/httpserver/DataVariantAbstract.h b/httpserver/DataVariantAbstract.h index fd9eea8..c3e5f60 100644 --- a/httpserver/DataVariantAbstract.h +++ b/httpserver/DataVariantAbstract.h @@ -27,7 +27,7 @@ namespace HttpServer /** * @param const Socket & - сокет, откуда можно достать остальные данные * @param const std::chrono::milliseconds & - максимальное время ожидания данных (на сокете) - * @param const std::string & - первая часть полученных данных + * @param std::string & - первая часть полученных данных * @param const size_t - сколько осталось данных (в байтах) получить из сокета * @param const std::unordered_map & - дополнительные параметры, описывающие формат данных * @param std::unordered_multimap & - данные в виде ключ->значение @@ -39,7 +39,7 @@ namespace HttpServer ( const Socket &, const std::chrono::milliseconds &, - const std::string &, + std::string &, const size_t, const std::unordered_map &, std::unordered_multimap &, diff --git a/httpserver/DataVariantFormUrlencoded.cpp b/httpserver/DataVariantFormUrlencoded.cpp index 1646031..90cb281 100644 --- a/httpserver/DataVariantFormUrlencoded.cpp +++ b/httpserver/DataVariantFormUrlencoded.cpp @@ -14,7 +14,7 @@ namespace HttpServer ( const Socket &sock, const std::chrono::milliseconds &timeout, - const std::string &str, + std::string &str, const size_t leftBytes, const std::unordered_map ¶ms, std::unordered_multimap &data, @@ -54,6 +54,8 @@ namespace HttpServer } } + str.clear(); + return true; } diff --git a/httpserver/DataVariantFormUrlencoded.h b/httpserver/DataVariantFormUrlencoded.h index 196f378..5e3893a 100644 --- a/httpserver/DataVariantFormUrlencoded.h +++ b/httpserver/DataVariantFormUrlencoded.h @@ -14,7 +14,7 @@ namespace HttpServer ( const Socket &, const std::chrono::milliseconds &, - const std::string &, + std::string &, const size_t, const std::unordered_map &, std::unordered_multimap &, diff --git a/httpserver/DataVariantMultipartFormData.cpp b/httpserver/DataVariantMultipartFormData.cpp index c57d6d5..c6bed71 100644 --- a/httpserver/DataVariantMultipartFormData.cpp +++ b/httpserver/DataVariantMultipartFormData.cpp @@ -57,7 +57,7 @@ namespace HttpServer ( const Socket &sock, const std::chrono::milliseconds &timeout, - const std::string &str, + std::string &str, const size_t leftBytes, const std::unordered_map ¶ms, std::unordered_multimap &data, @@ -82,7 +82,6 @@ namespace HttpServer // Создание буферов std::vector buf(buf_len); - std::string str_buf = str; size_t str_cur; // Текущая позиция в буфере @@ -90,18 +89,18 @@ namespace HttpServer size_t read_len = 0; // Прочитано байт из сокета всего // Поиск разделителя блока данных - str_cur = str_buf.find(block_delimiter); + str_cur = str.find(block_delimiter); if (std::string::npos == str_cur) { // Получить следующий кусок данных - if (false == append(sock, timeout, buf, str_buf, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) { return false; } // Поиск разделителя блока данных - str_cur = str_buf.find(block_delimiter); + str_cur = str.find(block_delimiter); if (std::string::npos == str_cur) { @@ -122,19 +121,19 @@ namespace HttpServer bool is_block_valid = true; // Поиск конца заголовков блока данных - size_t headers_end = str_buf.find("\r\n\r\n", str_cur); + size_t headers_end = str.find("\r\n\r\n", str_cur); // Если конец не был найден, то if (std::string::npos == headers_end) { // Получить следующий кусок данных - if (false == append(sock, timeout, buf, str_buf, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) { return false; } // Провести повторный поиск - headers_end = str_buf.find("\r\n\r\n", str_cur); + headers_end = str.find("\r\n\r\n", str_cur); // Если снова не найдено, то данные некорректны if (std::string::npos == headers_end) @@ -148,24 +147,24 @@ namespace HttpServer // Разобрать заголовки блока данных std::unordered_map headers; - for (size_t line_end = str_buf.find("\r\n", str_cur); str_cur < headers_end; line_end = str_buf.find("\r\n", str_cur) ) + for (size_t line_end = str.find("\r\n", str_cur); str_cur < headers_end; line_end = str.find("\r\n", str_cur) ) { - size_t delimiter = str_buf.find(':', str_cur); + size_t delimiter = str.find(':', str_cur); if (std::string::npos == delimiter || delimiter > line_end) { - std::string header_name = str_buf.substr(str_cur, line_end - str_cur); + std::string header_name = str.substr(str_cur, line_end - str_cur); Utils::trim(header_name); headers.emplace(std::move(header_name), ""); } else { - std::string header_name = str_buf.substr(str_cur, delimiter - str_cur); + std::string header_name = str.substr(str_cur, delimiter - str_cur); Utils::trim(header_name); ++delimiter; - std::string header_value = str_buf.substr(delimiter, line_end - delimiter); + std::string header_value = str.substr(delimiter, line_end - delimiter); Utils::trim(header_value); headers.emplace(std::move(header_name), std::move(header_value) ); @@ -271,31 +270,33 @@ namespace HttpServer if (file.is_open() ) { // Смещение данных в буфере в начало - str_buf.assign(str_buf.cbegin() + str_cur, str_buf.cend() ); +// str.assign(str.cbegin() + str_cur, str.cend() ); + str.erase(str.begin(), str.begin() + str_cur); // Поиск конца блока данных - size_t delimiter = str_buf.find(block_delimiter); + size_t delimiter = str.find(block_delimiter); // Пока конец блока данных не найден while (std::string::npos == delimiter) { // Добавить данные к значению - file.write(str_buf.data(), str_buf.length() - data_end.length() ); + file.write(str.data(), str.length() - data_end.length() ); - str_buf.assign(str_buf.cend() - data_end.length(), str_buf.cend() ); +// str.assign(str.cend() - data_end.length(), str.cend() ); + str.erase(str.begin(), str.end() - data_end.length() ); // Получить следующий кусок данных - if (false == append(sock, timeout, buf, str_buf, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) { return false; } // Поиск конца блока данных - delimiter = str_buf.find(block_delimiter); + delimiter = str.find(block_delimiter); } // Добавить последнюю часть данных к значению - file.write(str_buf.data(), delimiter); + file.write(str.data(), delimiter); // Добавить данные в список files.emplace(it_name->second, FileIncoming(std::move(tmp_name), it_filetype->second, file.tellp() ) ); @@ -303,7 +304,7 @@ namespace HttpServer file.close(); // Если найден конец данных - if (str_buf.find(data_end, delimiter) == delimiter) + if (str.find(data_end, delimiter) == delimiter) { is_find_data_end = true; } @@ -325,37 +326,39 @@ namespace HttpServer std::string value; // Смещение данных в буфере в начало - str_buf.assign(str_buf.cbegin() + str_cur, str_buf.cend() ); +// str.assign(str.cbegin() + str_cur, str.cend() ); + str.erase(str.begin(), str.begin() + str_cur); // Поиск конца блока данных - size_t delimiter = str_buf.find(block_delimiter); + size_t delimiter = str.find(block_delimiter); // Пока конец блока данных не найден while (std::string::npos == delimiter) { // Добавить данные к значению - value.append(str_buf.cbegin(), str_buf.cend() - data_end.length() ); + value.append(str.cbegin(), str.cend() - data_end.length() ); - str_buf.assign(str_buf.cend() - data_end.length(), str_buf.cend() ); +// str.assign(str.cend() - data_end.length(), str.cend() ); + str.erase(str.begin(), str.end() - data_end.length() ); // Получить следующий кусок данных - if (false == append(sock, timeout, buf, str_buf, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) { return false; } // Поиск конца блока данных - delimiter = str_buf.find(block_delimiter); + delimiter = str.find(block_delimiter); } // Добавить последнюю часть данных к значению - value.append(str_buf.cbegin(), str_buf.cbegin() + delimiter); + value.append(str.cbegin(), str.cbegin() + delimiter); // Добавить данные в список data.emplace(it_name->second, std::move(value) ); // Если найден конец данных - if (str_buf.find(data_end, delimiter) == delimiter) + if (str.find(data_end, delimiter) == delimiter) { is_find_data_end = true; } @@ -383,29 +386,34 @@ namespace HttpServer if (false == is_block_valid) { // то блок данных пропускаем (ищем следующий блок) - str_cur = str_buf.find(block_delimiter, str_cur); + str_cur = str.find(block_delimiter, str_cur); while (std::string::npos == str_cur) { - str_buf.assign(str_buf.cend() - data_end.length(), str_buf.cend() ); +// str.assign(str.cend() - data_end.length(), str.cend() ); + str.erase(str.begin(), str.end() - data_end.length() ); // Получить следующий кусок данных - if (false == append(sock, timeout, buf, str_buf, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) { return false; } - str_cur = str_buf.find(block_delimiter); + str_cur = str.find(block_delimiter); } // Если найден конец данных - if (str_buf.find(data_end, str_cur) == str_cur) + if (str.find(data_end, str_cur) == str_cur) { is_find_data_end = true; } str_cur += block_delimiter.length() + 2; } + + str.erase(str.begin(), str.begin() + str_cur); + + str_cur = 0; } while (false == is_find_data_end); diff --git a/httpserver/DataVariantMultipartFormData.h b/httpserver/DataVariantMultipartFormData.h index 22b417c..daadc63 100644 --- a/httpserver/DataVariantMultipartFormData.h +++ b/httpserver/DataVariantMultipartFormData.h @@ -26,7 +26,7 @@ namespace HttpServer ( const Socket &, const std::chrono::milliseconds &, - const std::string &, + std::string &, const size_t, const std::unordered_map &, std::unordered_multimap &, diff --git a/httpserver/DataVariantTextPlain.cpp b/httpserver/DataVariantTextPlain.cpp index b8da9c2..a40c897 100644 --- a/httpserver/DataVariantTextPlain.cpp +++ b/httpserver/DataVariantTextPlain.cpp @@ -12,7 +12,7 @@ namespace HttpServer ( const Socket &sock, const std::chrono::milliseconds &timeout, - const std::string &str, + std::string &str, const size_t leftBytes, const std::unordered_map ¶ms, std::unordered_multimap &data, @@ -52,6 +52,8 @@ namespace HttpServer } } + str.clear(); + return true; } diff --git a/httpserver/DataVariantTextPlain.h b/httpserver/DataVariantTextPlain.h index 285b1de..58cd4db 100644 --- a/httpserver/DataVariantTextPlain.h +++ b/httpserver/DataVariantTextPlain.h @@ -14,7 +14,7 @@ namespace HttpServer ( const Socket &, const std::chrono::milliseconds &, - const std::string &, + std::string &, const size_t, const std::unordered_map &, std::unordered_multimap &, diff --git a/httpserver/Module.cpp b/httpserver/Module.cpp index 1dd3ee9..b0f6a7b 100644 --- a/httpserver/Module.cpp +++ b/httpserver/Module.cpp @@ -43,7 +43,7 @@ namespace HttpServer if (nullptr == lib_handle) { #ifdef POSIX - std::cout << dlerror() << std::endl; + std::cout << ::dlerror() << std::endl; #endif return false; } diff --git a/httpserver/Server.cpp b/httpserver/Server.cpp index 4ac93c5..9846d1c 100644 --- a/httpserver/Server.cpp +++ b/httpserver/Server.cpp @@ -429,15 +429,17 @@ namespace HttpServer bool connection_upgrade = false; bool connection_keep_alive; + size_t keep_alive_count = 100; + + const size_t buf_len = 4096; + std::vector buf(buf_len); + + std::string str_buf; do { app_exit_code = EXIT_FAILURE; - const size_t buf_len = 4096; - std::vector buf(buf_len); - std::string str_buf; - std::unordered_map incoming_headers; std::unordered_multimap incoming_params; std::unordered_multimap incoming_data; @@ -449,11 +451,13 @@ namespace HttpServer std::string version; std::string uri_reference; - // Получить данные запроса от клиента + // Подготовить параметры для получения данных std::chrono::milliseconds timeout(5000); - const size_t recv_len = clientSocket.nonblock_recv(buf, timeout); - if (std::numeric_limits::max() == recv_len) + // Получить данные запроса от клиента + const size_t recv_size = clientSocket.nonblock_recv(buf, timeout); + + if (std::numeric_limits::max() == recv_size && str_buf.empty() ) { #ifdef DEBUG #ifdef WIN32 @@ -464,10 +468,14 @@ namespace HttpServer #endif break; } - else if (recv_len) // Если данные были получены + + if (recv_size) // Если данные были получены { - str_buf.assign(buf.cbegin(), buf.cbegin() + recv_len); + str_buf.append(buf.cbegin(), buf.cbegin() + recv_size); + } + if (false == str_buf.empty() ) + { // Поиск конца заголовков (пустая строка) size_t headers_end = str_buf.find("\r\n\r\n"); @@ -568,6 +576,8 @@ namespace HttpServer str_cur = str_end + 2; } + str_buf.erase(str_buf.begin(), str_buf.begin() + headers_end + 2); + // Получить доменное имя (или адрес) назначения запроса auto it_host = incoming_headers.find("Host"); @@ -665,13 +675,22 @@ namespace HttpServer // Сколько осталось получить данных size_t left_bytes = 0; - if (data_length) + std::string data_buf; + + if (data_length >= str_buf.length() ) { - left_bytes = data_length - (recv_len - (headers_end + 2) ); + left_bytes = data_length - str_buf.length(); + + data_buf.swap(str_buf); + } + else + { + data_buf.assign(str_buf.cbegin(), str_buf.cbegin() + data_length); + str_buf.erase(str_buf.begin(), str_buf.begin() + data_length); } // Разобрать данные на составляющие - if (false == data_variant->parse(clientSocket, timeout, str_buf.substr(headers_end + 2), left_bytes, content_params, incoming_data, incoming_files) ) + if (false == data_variant->parse(clientSocket, timeout, data_buf, left_bytes, content_params, incoming_data, incoming_files) ) { for (auto &it : incoming_files) { @@ -683,17 +702,26 @@ namespace HttpServer break; } + + if (false == data_buf.empty() ) + { + str_buf.swap(data_buf); + } } else { // HTTP 413 Request Entity Too Large this->sendStatus(clientSocket, timeout, 413); + + break; } } else { // HTTP 400 Bad Request this->sendStatus(clientSocket, timeout, 400); + + break; } } @@ -775,6 +803,7 @@ namespace HttpServer { // HTTP 400 Bad Request this->sendStatus(clientSocket, timeout, 400); + break; } @@ -804,7 +833,9 @@ namespace HttpServer { if ("keep-alive" == connection_out) { - connection_keep_alive = true; + --keep_alive_count; + + connection_keep_alive = (0 < keep_alive_count); } } else if ("upgrade" == connection_in) @@ -820,7 +851,7 @@ namespace HttpServer if (outgoing_headers.cend() != it_x_sendfile) { - const std::string connection_header = connection_keep_alive ? "Connection: keep-alive\r\n" : "Connection: close\r\n"; + const std::string connection_header = connection_keep_alive ? "Connection: Keep-Alive\r\nKeep-Alive: timeout=5; max=" + std::to_string(keep_alive_count) + "\r\n" : "Connection: Close\r\n"; const bool headers_only = ("head" == method); diff --git a/httpserver/SignalsHandles.cpp b/httpserver/SignalsHandles.cpp index ba73b4f..93a68b1 100644 --- a/httpserver/SignalsHandles.cpp +++ b/httpserver/SignalsHandles.cpp @@ -38,14 +38,19 @@ void handlerSigUsr2(int sig) #ifdef WIN32 -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +/** + * Note: PostQuitMessage(0) + * It doesn't work in case the program was launched and was + * attempted to finish under different remote sessions. + */ +::LRESULT CALLBACK WndProc(::HWND hWnd, ::UINT message, ::WPARAM wParam, ::LPARAM lParam) { switch (message) { case SIGTERM: { handlerSigTerm(message); - PostQuitMessage(0); + ::PostMessage(hWnd, WM_QUIT, 0, 0); // Fuck ::PostQuitMessage(0); break; } @@ -53,7 +58,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case SIGINT: { handlerSigInt(message); - PostQuitMessage(0); + ::PostMessage(hWnd, WM_QUIT, 0, 0); // Fuck ::PostQuitMessage(0); break; } @@ -72,16 +77,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) default: { - return DefWindowProc(hWnd, message, wParam, lParam); + return ::DefWindowProc(hWnd, message, wParam, lParam); } } return 0; } -WPARAM mainMessageLoop(HINSTANCE hInstance, HttpServer::Event *pCreatedWindow) +::WPARAM mainMessageLoop(::HINSTANCE hInstance, HttpServer::Event *pCreatedWindow) { - HWND hWnd = CreateWindow(myWndClassName, nullptr, 0, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, nullptr, nullptr, hInstance, nullptr); + ::HWND hWnd = ::CreateWindow(myWndClassName, nullptr, 0, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, nullptr, nullptr, hInstance, nullptr); pCreatedWindow->notify(); @@ -90,12 +95,12 @@ WPARAM mainMessageLoop(HINSTANCE hInstance, HttpServer::Event *pCreatedWindow) return 0; } - MSG msg; + ::MSG msg; - while (GetMessage(&msg, hWnd, 0, 0) ) + while (::GetMessage(&msg, hWnd, 0, 0) ) { - TranslateMessage(&msg); - DispatchMessage(&msg); + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); } return msg.wParam; @@ -108,22 +113,25 @@ int bindSignalsHandles(HttpServer::Server *server) #ifdef WIN32 - signal(SIGINT, handlerSigInt); - signal(SIGTERM, handlerSigTerm); + const int sig_int = 2; // SIGINT + const int sig_term = 15; // SIGTERM - _set_abort_behavior(0, _WRITE_ABORT_MSG); + ::signal(sig_int, handlerSigInt); + ::signal(sig_term, handlerSigTerm); - HINSTANCE hInstance = GetModuleHandle(nullptr); + ::_set_abort_behavior(0, _WRITE_ABORT_MSG); - WNDCLASSEX wcex = { - sizeof(WNDCLASSEX) + ::HINSTANCE hInstance = ::GetModuleHandle(nullptr); + + ::WNDCLASSEX wcex = { + sizeof(::WNDCLASSEX) }; wcex.lpfnWndProc = WndProc; wcex.hInstance = hInstance; wcex.lpszClassName = myWndClassName; - if (0 == RegisterClassEx(&wcex) ) + if (0 == ::RegisterClassEx(&wcex) ) { return 0; } @@ -136,19 +144,19 @@ int bindSignalsHandles(HttpServer::Server *server) #elif POSIX - struct sigaction act = {0}; + struct ::sigaction act = {0}; act.sa_handler = handlerSigInt; - sigaction(SIGINT, &act, nullptr); + ::sigaction(SIGINT, &act, nullptr); act.sa_handler = handlerSigTerm; - sigaction(SIGTERM, &act, nullptr); + ::sigaction(SIGTERM, &act, nullptr); act.sa_handler = handlerSigUsr1; - sigaction(SIGUSR1, &act, nullptr); + ::sigaction(SIGUSR1, &act, nullptr); act.sa_handler = handlerSigUsr2; - sigaction(SIGUSR2, &act, nullptr); + ::sigaction(SIGUSR2, &act, nullptr); #else #error "Undefine platform" #endif diff --git a/httpserver/Socket.cpp b/httpserver/Socket.cpp index e317211..b8bff64 100644 --- a/httpserver/Socket.cpp +++ b/httpserver/Socket.cpp @@ -118,7 +118,7 @@ namespace HttpServer 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) ); } @@ -129,7 +129,7 @@ namespace HttpServer 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) ); } @@ -149,7 +149,7 @@ namespace HttpServer 0 }; - if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents | POLLRDNORM) + if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents & POLLRDNORM) { client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); } @@ -160,7 +160,7 @@ namespace HttpServer 0 }; - if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents | POLLIN) + if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents & POLLIN) { client_socket = ::accept(socket_handle, static_cast(nullptr), static_cast(nullptr) ); } @@ -231,7 +231,7 @@ namespace HttpServer 0 }; - if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents | POLLRDNORM) + if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents & POLLRDNORM) { recv_len = ::recv(socket_handle, buf.data(), buf.size(), 0); } @@ -242,7 +242,7 @@ namespace HttpServer 0 }; - if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents | POLLIN) + if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents & POLLIN) { recv_len = ::recv(socket_handle, buf.data(), buf.size(), MSG_NOSIGNAL); } @@ -284,7 +284,7 @@ namespace HttpServer 0 }; - if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents | POLLWRNORM) + if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents & POLLWRNORM) { send_len = ::send(socket_handle, buf.data(), buf.length(), 0); } @@ -295,7 +295,7 @@ namespace HttpServer 0 }; - if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents | POLLOUT) + if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents & POLLOUT) { send_len = ::send(socket_handle, buf.data(), buf.length(), MSG_NOSIGNAL); } @@ -315,7 +315,7 @@ namespace HttpServer 0 }; - if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents | POLLWRNORM) + if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents & POLLWRNORM) { send_len = ::send(socket_handle, buf.data(), length, 0); } @@ -326,7 +326,7 @@ namespace HttpServer 0 }; - if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents | POLLOUT) + if (1 == ::poll(&event, 1, timeWait.count() ) && event.revents & POLLOUT) { send_len = ::send(socket_handle, buf.data(), length, MSG_WAITALL | MSG_NOSIGNAL); } @@ -341,4 +341,4 @@ namespace HttpServer socket_handle = s.socket_handle; return *this; } -}; \ No newline at end of file +}; diff --git a/httpserver/SocketList.cpp b/httpserver/SocketList.cpp index d7653fb..e8dc976 100644 --- a/httpserver/SocketList.cpp +++ b/httpserver/SocketList.cpp @@ -6,9 +6,9 @@ namespace HttpServer SocketList::SocketList() { #ifdef WIN32 - obj_list = INVALID_HANDLE_VALUE; + this->obj_list = INVALID_HANDLE_VALUE; #elif POSIX - obj_list = ~0; + this->obj_list = ~0; #else #error "Undefine platform" #endif @@ -28,16 +28,16 @@ namespace HttpServer return true; #elif POSIX - obj_list = ::epoll_create(listSize); + this->obj_list = ::epoll_create(listSize); - if ( (size_t)~0 == obj_list) + if (std::numeric_limits::max() == this->obj_list) { return false; } if (listSize > 0) { - epoll_events.reserve(listSize); + this->epoll_events.reserve(listSize); } return true; @@ -51,12 +51,12 @@ namespace HttpServer if (is_created() ) { #ifdef WIN32 - obj_list = INVALID_HANDLE_VALUE; - poll_events.clear(); + this->obj_list = INVALID_HANDLE_VALUE; + this->poll_events.clear(); #elif POSIX - ::close(obj_list); - obj_list = ~0; - epoll_events.clear(); + ::close(this->obj_list); + this->obj_list = ~0; + this->epoll_events.clear(); #else #error "Undefine platform" #endif @@ -65,40 +65,74 @@ namespace HttpServer bool SocketList::addSocket(const Socket &sock) { - if (is_created() ) + if (false == is_created() ) { - #ifdef WIN32 - WSAPOLLFD event = { - sock.get_handle(), - POLLRDNORM, - 0 - }; + return false; + } + + #ifdef WIN32 + WSAPOLLFD event = { + sock.get_handle(), + POLLRDNORM | POLLHUP, + 0 + }; - poll_events.emplace_back(event); + poll_events.emplace_back(event); - return true; - #elif POSIX - struct ::epoll_event event = { - EPOLLIN | EPOLLET, - reinterpret_cast(sock.get_handle() ) - }; + return true; + #elif POSIX + struct ::epoll_event event = { + EPOLLIN | EPOLLET | EPOLLRDHUP, + reinterpret_cast(sock.get_handle() ) + }; + + size_t result = ::epoll_ctl(this->obj_list, EPOLL_CTL_ADD, sock.get_handle(), &event); + + if (std::numeric_limits::max() == result) + { + return false; + } + + this->epoll_events.emplace_back(); + + return true; + #else + #error "Undefine platform" + #endif + } - size_t result = ::epoll_ctl(obj_list, EPOLL_CTL_ADD, sock.get_handle(), &event); + bool SocketList::removeSocket(const Socket &sock) + { + if (false == is_created() ) + { + return false; + } - if ( (size_t)~0 == result) + #ifdef WIN32 + for (size_t i = 0; i < poll_events.size(); ++i) + { + if (sock.get_handle() == poll_events[i].fd) { - return false; + poll_events.erase(poll_events.begin() + i); + return true; } + } - epoll_events.emplace_back(); + return false; + #elif POSIX + size_t result = ::epoll_ctl(this->obj_list, EPOLL_CTL_DEL, sock.get_handle(), nullptr); - return true; - #else - #error "Undefine platform" - #endif + if (std::numeric_limits::max() == result) + { + return false; } - return false; + this->epoll_events.pop_back(); + + return true; + #else + #error "Undefine platform" + #endif } bool SocketList::accept(std::vector &sockets) const @@ -106,18 +140,18 @@ namespace HttpServer if (is_created() ) { #ifdef WIN32 - size_t count = ::WSAPoll(poll_events.data(), poll_events.size(), ~0); + size_t count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), ~0); if (SOCKET_ERROR == count) { return false; } - for (size_t i = 0; i < poll_events.size(); ++i) + for (size_t i = 0; i < this->poll_events.size(); ++i) { - WSAPOLLFD &event = poll_events[i]; + WSAPOLLFD &event = this->poll_events[i]; - if (event.revents | POLLRDNORM) + if (event.revents & POLLRDNORM) { System::native_socket_type client_socket = ~0; @@ -136,7 +170,7 @@ namespace HttpServer return false == sockets.empty(); #elif POSIX - size_t count = ::epoll_wait(obj_list, epoll_events.data(), epoll_events.size(), ~0); + size_t count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); if (std::numeric_limits::max() == count) { @@ -145,9 +179,9 @@ namespace HttpServer for (size_t i = 0; i < count; ++i) { - epoll_event &event = epoll_events[i]; + epoll_event &event = this->epoll_events[i]; - if (event.events | EPOLLIN) + if (event.events & EPOLLIN) { System::native_socket_type client_socket = ~0; @@ -172,4 +206,62 @@ namespace HttpServer return false; } + + bool SocketList::recv(std::vector &sockets, std::vector &disconnected) const + { + if (false == is_created() ) + { + return false; + } + + #ifdef WIN32 + size_t count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), ~0); + + if (SOCKET_ERROR == count) + { + return false; + } + + for (size_t i = 0; i < this->poll_events.size(); ++i) + { + WSAPOLLFD &event = this->poll_events[i]; + + if (event.revents & POLLHUP) + { + disconnected.emplace_back(Socket(event.fd) ); + } + else if (event.revents & POLLRDNORM) + { + sockets.emplace_back(Socket(event.fd) ); + } + } + + return false == sockets.empty(); + #elif POSIX + size_t count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); + + if (std::numeric_limits::max() == count) + { + return false; + } + + for (size_t i = 0; i < count; ++i) + { + epoll_event &event = this->epoll_events[i]; + + if (event.events & EPOLLRDHUP) + { + disconnected.emplace_back(Socket(event.data.fd) ); + } + else if (event.events & EPOLLIN) + { + sockets.emplace_back(Socket(event.data.fd) ); + } + } + + return false == sockets.empty(); + #else + #error "Undefine platform" + #endif + } }; \ No newline at end of file diff --git a/httpserver/SocketList.h b/httpserver/SocketList.h index 968d6cd..c731ea5 100644 --- a/httpserver/SocketList.h +++ b/httpserver/SocketList.h @@ -26,16 +26,19 @@ namespace HttpServer inline bool is_created() const { #ifdef WIN32 - return INVALID_HANDLE_VALUE != obj_list; + return INVALID_HANDLE_VALUE != this->obj_list; #elif POSIX - return (size_t)~0 != obj_list; + return std::numeric_limits::max() != this->obj_list; #else #error "Undefine platform" #endif } bool addSocket(const Socket &); + bool removeSocket(const Socket &); bool accept(std::vector &sockets) const; + + bool recv(std::vector &sockets, std::vector &errors) const; }; }; \ No newline at end of file diff --git a/httpserver/System.cpp b/httpserver/System.cpp index c8789fd..f5491ca 100644 --- a/httpserver/System.cpp +++ b/httpserver/System.cpp @@ -10,7 +10,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,13 +18,13 @@ namespace System ::GetWindowThreadProcessId(hWnd, &process_id); - if (process_id == ed.process_id && GetConsoleWindow() != hWnd) + if (process_id == ed.process_id && ::GetConsoleWindow() != hWnd) { char class_name[65] = {0}; - GetClassName(hWnd, class_name, 64); + ::GetClassName(hWnd, class_name, 64); - if (0 == strcmp(class_name, myWndClassName) ) + if (0 == ::strcmp(class_name, myWndClassName) ) { ed.hWnd = hWnd; @@ -56,6 +56,35 @@ namespace System #endif } + std::string getTempDir() + { + #ifdef WIN32 + std::vector buf(MAX_PATH + 1); + + size_t len = ::GetTempPath(MAX_PATH + 1, 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 getFileSizeAndTimeGmt(const std::string &filePath, size_t *fileSize, time_t *fileTime) { #ifdef WIN32 diff --git a/httpserver/System.h b/httpserver/System.h index fbc06b4..13afd4e 100644 --- a/httpserver/System.h +++ b/httpserver/System.h @@ -3,6 +3,24 @@ #ifdef WIN32 #include extern 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 @@ -12,14 +30,7 @@ #error "Undefine platform" #endif -#ifndef SIGUSR1 - #define SIGUSR1 1010 -#endif - -#ifndef SIGUSR2 - #define SIGUSR2 1012 -#endif - +#include #include #include #include @@ -66,16 +77,7 @@ 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 getFileSizeAndTimeGmt(const std::string &, size_t *, time_t *); }; \ No newline at end of file From 4235fb93622889638b39e1cb1ad743bd5632491a Mon Sep 17 00:00:00 2001 From: awwit Date: Fri, 27 Mar 2015 17:59:20 +0300 Subject: [PATCH 02/50] Fixed X-Sendfile for directory (infinite loop) --- httpserver.pro.user | 4 ++-- httpserver/Server.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/httpserver.pro.user b/httpserver.pro.user index fac74c6..265f7f0 100644 --- a/httpserver.pro.user +++ b/httpserver.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/httpserver/Server.cpp b/httpserver/Server.cpp index 9846d1c..066074c 100644 --- a/httpserver/Server.cpp +++ b/httpserver/Server.cpp @@ -348,7 +348,7 @@ namespace HttpServer file.read(reinterpret_cast(buf.data() ), buf.size() ); send_size = clientSocket.nonblock_send(buf, file.gcount(), timeout); } - while (false == file.eof() && std::numeric_limits::max() != send_size); + while (false == file.eof() && false == file.fail() && std::numeric_limits::max() != send_size); } file.close(); From 88dea46f8e1c6c2e0a4e76191d5fa545ae60aeba Mon Sep 17 00:00:00 2001 From: awwit Date: Fri, 27 Mar 2015 18:10:32 +0300 Subject: [PATCH 03/50] Fixed X-Sendfile for directory (infinite loop) in partial get request --- httpserver.pro.user | 4 ++-- httpserver/Server.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/httpserver.pro.user b/httpserver.pro.user index 265f7f0..ffbb731 100644 --- a/httpserver.pro.user +++ b/httpserver.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/httpserver/Server.cpp b/httpserver/Server.cpp index 066074c..95779eb 100644 --- a/httpserver/Server.cpp +++ b/httpserver/Server.cpp @@ -226,7 +226,7 @@ namespace HttpServer send_size_left -= send_size; } - while (false == file.eof() && std::numeric_limits::max() != send_size && send_size_left); + while (false == file.eof() && false == file.fail() && std::numeric_limits::max() != send_size && send_size_left); } } @@ -348,7 +348,7 @@ namespace HttpServer file.read(reinterpret_cast(buf.data() ), buf.size() ); send_size = clientSocket.nonblock_send(buf, file.gcount(), timeout); } - while (false == file.eof() && false == file.fail() && std::numeric_limits::max() != send_size); + while (false == file.eof() && false == file.fail() && std::numeric_limits::max() != send_size); } file.close(); From ed0682a3099db533537e7955164a7751537b5f05 Mon Sep 17 00:00:00 2001 From: awwit Date: Sat, 20 Jun 2015 18:04:38 +0300 Subject: [PATCH 04/50] Fixed delay in keep-alive connections --- apps.conf | 4 ++-- httpserver.pro | 11 ++++++---- httpserver.pro.user | 4 ++-- httpserver/Event.cpp | 36 +++++++++++++++++++++++++++---- httpserver/Event.h | 7 +++++- httpserver/Server.cpp | 10 ++++++++- httpserver/Socket.cpp | 50 +++++++++++++++++++++++++++++++++++++++++-- httpserver/Socket.h | 7 ++++++ 8 files changed, 113 insertions(+), 16 deletions(-) diff --git a/apps.conf b/apps.conf index bf7887f..bb3c060 100644 --- a/apps.conf +++ b/apps.conf @@ -1,7 +1,7 @@ server { listen 2280; - server_name servertest www.servertest; - server_module /media/projects/sites/servertest/module/appgameserver_debug.so; + server_name servertest www.servertest 192.168.1.35; + server_module /media/projects/appgameserver/build/Release/libappgameserver.so; server_module_update /media/projects/httpserverapp/httpserverapp/bin/Release/libhttpserverapp.so; root_dir /media/projects/sites/servertest/www/; request_max_size 10485760; diff --git a/httpserver.pro b/httpserver.pro index 7c10e82..8d01ada 100644 --- a/httpserver.pro +++ b/httpserver.pro @@ -9,10 +9,13 @@ CONFIG(debug, debug|release):DEFINES += DEBUG QMAKE_CXXFLAGS += -std=c++11 -QMAKE_CFLAGS_RELEASE -= -O -QMAKE_CFLAGS_RELEASE -= -O1 -QMAKE_CFLAGS_RELEASE -= -O2 -QMAKE_CFLAGS_RELEASE *= -O3 +CONFIG(release, debug|release) +{ + QMAKE_CFLAGS_RELEASE -= -O + QMAKE_CFLAGS_RELEASE -= -O1 + QMAKE_CFLAGS_RELEASE -= -O2 + QMAKE_CFLAGS_RELEASE *= -O3 +} LIBS += -ldl -pthread diff --git a/httpserver.pro.user b/httpserver.pro.user index ffbb731..4918208 100644 --- a/httpserver.pro.user +++ b/httpserver.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/httpserver/Event.cpp b/httpserver/Event.cpp index 7b9620c..218caf3 100644 --- a/httpserver/Event.cpp +++ b/httpserver/Event.cpp @@ -22,9 +22,37 @@ namespace HttpServer } } - void Event::notify() + bool Event::wait_for(const std::chrono::milliseconds &ms) { std::unique_lock lck(mtx); + + auto status = cv.wait_for(lck, ms); + + if (false == manualy) + { + signaled = false; + } + + return std::cv_status::timeout == status; + } + + bool Event::wait_until(const std::chrono::high_resolution_clock::time_point &tp) + { + std::unique_lock lck(mtx); + + auto status = cv.wait_until(lck, tp); + + if (false == manualy) + { + signaled = false; + } + + return std::cv_status::timeout == status; + } + + void Event::notify() + { + // std::unique_lock lck(mtx); signaled = true; cv.notify_all(); } @@ -33,7 +61,7 @@ namespace HttpServer { if (threadsCount) { - std::unique_lock lck(mtx); + // std::unique_lock lck(mtx); signaled = true; @@ -46,14 +74,14 @@ namespace HttpServer void Event::reset() { - std::unique_lock lck(mtx); + // std::unique_lock lck(mtx); signaled = false; } bool Event::notifed() { - std::unique_lock lck(mtx); + // std::unique_lock lck(mtx); return signaled; } diff --git a/httpserver/Event.h b/httpserver/Event.h index 723c2bb..f20cec5 100644 --- a/httpserver/Event.h +++ b/httpserver/Event.h @@ -2,6 +2,7 @@ #include #include +#include namespace HttpServer { @@ -10,7 +11,7 @@ namespace HttpServer private: std::mutex mtx; std::condition_variable cv; - bool signaled; + std::atomic signaled; bool manualy; public: @@ -19,8 +20,12 @@ namespace HttpServer public: void wait(); + bool wait_for(const std::chrono::milliseconds &); + bool wait_until(const std::chrono::high_resolution_clock::time_point &); + void notify(); void notify(const size_t); + void reset(); bool notifed(); diff --git a/httpserver/Server.cpp b/httpserver/Server.cpp index 95779eb..6dadc76 100644 --- a/httpserver/Server.cpp +++ b/httpserver/Server.cpp @@ -340,6 +340,10 @@ namespace HttpServer if (false == headersOnly && file_size) { std::vector buf(file_size < 512 * 1024 ? file_size : 512 * 1024); + // buf.assign(headers.cbegin(), headers.cend() ); + + // file.read(reinterpret_cast(buf.data() + headers.length() ), buf.size() - headers.length() ); + // size_t send_size = clientSocket.nonblock_send(buf, file.gcount(), timeout); size_t send_size; @@ -452,7 +456,7 @@ namespace HttpServer std::string uri_reference; // Подготовить параметры для получения данных - std::chrono::milliseconds timeout(5000); + std::chrono::milliseconds timeout(500); // Получить данные запроса от клиента const size_t recv_size = clientSocket.nonblock_recv(buf, timeout); @@ -863,6 +867,9 @@ namespace HttpServer if (false == connection_upgrade) { + // TODO: wait for send all data to client + clientSocket.nonblock_send_sync(); + clientSocket.shutdown(); clientSocket.close(); } @@ -1439,6 +1446,7 @@ namespace HttpServer if (sock.is_open() ) { sock.nonblock(true); + sock.tcp_nodelay(true); sockets.emplace(std::move(sock) ); } } diff --git a/httpserver/Socket.cpp b/httpserver/Socket.cpp index b8bff64..7c05d1c 100644 --- a/httpserver/Socket.cpp +++ b/httpserver/Socket.cpp @@ -210,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 @@ -328,7 +341,7 @@ namespace HttpServer if (1 == ::poll(&event, 1, timeWait.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" @@ -336,9 +349,42 @@ namespace HttpServer return send_len; } + 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 s) { socket_handle = s.socket_handle; return *this; } -}; + + bool Socket::operator ==(const Socket &sock) const + { + return this->socket_handle == sock.socket_handle; + } + + bool Socket::operator !=(const Socket &sock) const + { + return this->socket_handle != sock.socket_handle; + } +}; \ No newline at end of file diff --git a/httpserver/Socket.h b/httpserver/Socket.h index 85796bd..e4939fa 100644 --- a/httpserver/Socket.h +++ b/httpserver/Socket.h @@ -10,6 +10,7 @@ #include #include #include + #include #include #include #else @@ -69,6 +70,7 @@ namespace HttpServer bool nonblock(const bool = true) const; // bool is_nonblock() const; + bool tcp_nodelay(const bool = true) const; size_t recv(std::vector &) const; size_t nonblock_recv(std::vector &, const std::chrono::milliseconds &) const; @@ -79,11 +81,16 @@ namespace HttpServer 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; + void nonblock_send_sync() const; + inline System::native_socket_type get_handle() const { return socket_handle; } Socket &operator =(const Socket); + + bool operator ==(const Socket &sock) const; + bool operator !=(const Socket &sock) const; }; }; \ No newline at end of file From 68c79d31cc7468e2c33ca2da28436eddca36bcf6 Mon Sep 17 00:00:00 2001 From: awwit Date: Fri, 28 Aug 2015 20:30:24 +0300 Subject: [PATCH 05/50] Fixed: parsing requests without data --- apps.conf | 2 +- httpserver.pro | 6 +-- httpserver.pro.user | 4 +- httpserver/DataVariantFormUrlencoded.cpp | 58 ++++++++++----------- httpserver/DataVariantMultipartFormData.cpp | 9 +++- httpserver/DataVariantTextPlain.cpp | 58 ++++++++++----------- httpserver/Server.cpp | 14 ++--- httpserver/Server.h | 13 ++++- httpserver/Utils.h | 28 ++++++++++ 9 files changed, 117 insertions(+), 75 deletions(-) diff --git a/apps.conf b/apps.conf index bb3c060..9955438 100644 --- a/apps.conf +++ b/apps.conf @@ -1,6 +1,6 @@ server { listen 2280; - server_name servertest www.servertest 192.168.1.35; + server_name servertest www.servertest; server_module /media/projects/appgameserver/build/Release/libappgameserver.so; server_module_update /media/projects/httpserverapp/httpserverapp/bin/Release/libhttpserverapp.so; root_dir /media/projects/sites/servertest/www/; diff --git a/httpserver.pro b/httpserver.pro index 8d01ada..6cd9179 100644 --- a/httpserver.pro +++ b/httpserver.pro @@ -7,14 +7,14 @@ DEFINES += POSIX CONFIG(debug, debug|release):DEFINES += DEBUG -QMAKE_CXXFLAGS += -std=c++11 +QMAKE_CXXFLAGS += -std=c++1y CONFIG(release, debug|release) { QMAKE_CFLAGS_RELEASE -= -O QMAKE_CFLAGS_RELEASE -= -O1 - QMAKE_CFLAGS_RELEASE -= -O2 - QMAKE_CFLAGS_RELEASE *= -O3 + QMAKE_CFLAGS_RELEASE *= -O2 +# QMAKE_CFLAGS_RELEASE *= -O3 } LIBS += -ldl -pthread diff --git a/httpserver.pro.user b/httpserver.pro.user index 4918208..3e82bde 100644 --- a/httpserver.pro.user +++ b/httpserver.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/httpserver/DataVariantFormUrlencoded.cpp b/httpserver/DataVariantFormUrlencoded.cpp index 90cb281..74b4637 100644 --- a/httpserver/DataVariantFormUrlencoded.cpp +++ b/httpserver/DataVariantFormUrlencoded.cpp @@ -21,44 +21,44 @@ namespace HttpServer std::unordered_multimap &files ) { - if (str.length() ) + if (str.empty() ) { - for (size_t var_pos = 0, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) - { - // Поиск следующего параметра - var_end = str.find('&', var_pos); - - // Поиск значения параметра - size_t delimiter = str.find('=', var_pos); - - if (delimiter >= var_end) - { - // Получить имя параметра - std::string var_name = Utils::urlDecode(str.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos) ); + return true; + } - // Сохранить параметр с пустым значением - data.emplace(std::move(var_name), ""); - } - else - { - // Получить имя параметра - std::string var_name = Utils::urlDecode(str.substr(var_pos, delimiter - var_pos) ); + for (size_t var_pos = 0, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) + { + // Поиск следующего параметра + var_end = str.find('&', var_pos); - ++delimiter; + // Поиск значения параметра + size_t delimiter = str.find('=', var_pos); - // Получить значение параметра - std::string var_value = Utils::urlDecode(str.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos) ); + if (delimiter >= var_end) + { + // Получить имя параметра + std::string var_name = Utils::urlDecode(str.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos) ); - // Сохранить параметр и значение - data.emplace(std::move(var_name), std::move(var_value) ); - } + // Сохранить параметр с пустым значением + data.emplace(std::move(var_name), ""); } + else + { + // Получить имя параметра + std::string var_name = Utils::urlDecode(str.substr(var_pos, delimiter - var_pos) ); - str.clear(); + ++delimiter; - return true; + // Получить значение параметра + std::string var_value = Utils::urlDecode(str.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos) ); + + // Сохранить параметр и значение + data.emplace(std::move(var_name), std::move(var_value) ); + } } - return false; + str.clear(); + + return true; } }; \ No newline at end of file diff --git a/httpserver/DataVariantMultipartFormData.cpp b/httpserver/DataVariantMultipartFormData.cpp index c6bed71..c5b0280 100644 --- a/httpserver/DataVariantMultipartFormData.cpp +++ b/httpserver/DataVariantMultipartFormData.cpp @@ -75,7 +75,14 @@ namespace HttpServer // Определить признак начала блока данных std::string block_delimiter("--" + it->second); // Определить признак окончания всех данных - const std::string data_end("\r\n--" + it->second + "--\r\n"); + std::string data_end("--" + it->second + "--\r\n"); + + if (0 == str.find(data_end) ) + { + return true; + } + + data_end = "\r\n" + data_end; // Установить размер буфера данных const size_t buf_len = (leftBytes >= 512 * 1024) ? 512 * 1024 : leftBytes; diff --git a/httpserver/DataVariantTextPlain.cpp b/httpserver/DataVariantTextPlain.cpp index a40c897..0134b9e 100644 --- a/httpserver/DataVariantTextPlain.cpp +++ b/httpserver/DataVariantTextPlain.cpp @@ -19,44 +19,44 @@ namespace HttpServer std::unordered_multimap &files ) { - if (str.length() ) + if (str.empty() ) { - for (size_t var_pos = 0, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) - { - // Поиск следующего параметра - var_end = str.find('&', var_pos); - - // Поиск значения параметра - size_t delimiter = str.find('=', var_pos); - - if (delimiter >= var_end) - { - // Получить имя параметра - std::string var_name = str.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos); + return true; + } - // Сохранить параметр с пустым значением - data.emplace(std::move(var_name), ""); - } - else - { - // Получить имя параметра - std::string var_name = str.substr(var_pos, delimiter - var_pos); + for (size_t var_pos = 0, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) + { + // Поиск следующего параметра + var_end = str.find('&', var_pos); - ++delimiter; + // Поиск значения параметра + size_t delimiter = str.find('=', var_pos); - // Получить значение параметра - std::string var_value = str.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos); + if (delimiter >= var_end) + { + // Получить имя параметра + std::string var_name = str.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos); - // Сохранить параметр и значение - data.emplace(std::move(var_name), std::move(var_value) ); - } + // Сохранить параметр с пустым значением + data.emplace(std::move(var_name), ""); } + else + { + // Получить имя параметра + std::string var_name = str.substr(var_pos, delimiter - var_pos); - str.clear(); + ++delimiter; - return true; + // Получить значение параметра + std::string var_value = str.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos); + + // Сохранить параметр и значение + data.emplace(std::move(var_name), std::move(var_value) ); + } } - return false; + str.clear(); + + return true; } }; \ No newline at end of file diff --git a/httpserver/Server.cpp b/httpserver/Server.cpp index 6dadc76..7404c89 100644 --- a/httpserver/Server.cpp +++ b/httpserver/Server.cpp @@ -244,7 +244,7 @@ namespace HttpServer const std::chrono::milliseconds &timeout, const std::string &fileName, const std::unordered_map &inHeaders, - const std::map &outHeaders, + const std::unordered_map &outHeaders, const std::string &connectionHeader, const bool headersOnly ) const @@ -340,10 +340,6 @@ namespace HttpServer if (false == headersOnly && file_size) { std::vector buf(file_size < 512 * 1024 ? file_size : 512 * 1024); - // buf.assign(headers.cbegin(), headers.cend() ); - - // file.read(reinterpret_cast(buf.data() + headers.length() ), buf.size() - headers.length() ); - // size_t send_size = clientSocket.nonblock_send(buf, file.gcount(), timeout); size_t send_size; @@ -449,7 +445,7 @@ namespace HttpServer std::unordered_multimap incoming_data; std::unordered_multimap incoming_files; - std::map outgoing_headers; + std::unordered_map outgoing_headers; std::string method; std::string version; @@ -771,7 +767,7 @@ namespace HttpServer if (EXIT_SUCCESS == app_exit_code) { - Utils::rawPairsToStlMap(outgoing_headers, response.headers, response.headers_count); + Utils::rawPairsToStl(outgoing_headers, response.headers, response.headers_count); } try @@ -783,7 +779,7 @@ namespace HttpServer Utils::destroyRawPairs(raw_pair_params, incoming_params.size() ); Utils::destroyRawPairs(raw_pair_headers, incoming_headers.size() ); Utils::destroyRawPairs(raw_pair_data, incoming_data.size() ); - Utils::destroyRawFilesInfo(raw_fileinfo_files, incoming_files.size() ); + Utils::destroyRawFilesInfo(raw_fileinfo_files, incoming_files.size() ); } else { @@ -867,7 +863,7 @@ namespace HttpServer if (false == connection_upgrade) { - // TODO: wait for send all data to client + // Wait for send all data to client clientSocket.nonblock_send_sync(); clientSocket.shutdown(); diff --git a/httpserver/Server.h b/httpserver/Server.h index 2950f15..9301abe 100644 --- a/httpserver/Server.h +++ b/httpserver/Server.h @@ -3,6 +3,7 @@ #include #include + #include #include #include @@ -52,7 +53,17 @@ namespace HttpServer int threadRequestProc(Socket) const; void threadRequestCycle(std::queue &) const; int transferFilePart(const Socket &, const std::chrono::milliseconds &, const std::string &, const time_t, const size_t, const std::string &, const std::string &, const std::string &, const bool) const; - int transferFile(const Socket &, const std::chrono::milliseconds &, const std::string &, const std::unordered_map &, const std::map &, const std::string &, const bool) const; + + int transferFile( + const Socket &, + const std::chrono::milliseconds &, + const std::string &, + const std::unordered_map &, + const std::unordered_map &, + const std::string &, + const bool + ) const; + bool parseIncomingVars(std::unordered_multimap &, const std::string &) const; bool init(); diff --git a/httpserver/Utils.h b/httpserver/Utils.h index 1581a5f..d19c3ef 100644 --- a/httpserver/Utils.h +++ b/httpserver/Utils.h @@ -34,6 +34,34 @@ namespace Utils char *stlStringToPChar(const std::string &); + 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 stlMapToRawPairs(Utils::raw_pair *[], const std::map &); void stlMultimapToRawPairs(Utils::raw_pair *[], const std::multimap &); void stlUnorderedMapToRawPairs(Utils::raw_pair *[], const std::unordered_map &); From 6fea450759459939ecd1656a1deea57ff2e126a3 Mon Sep 17 00:00:00 2001 From: awwit Date: Thu, 1 Oct 2015 00:03:02 +0300 Subject: [PATCH 06/50] Fixed critical bug for Windows Refactoring function to process the request in a thread --- httpserver.pro | 6 +- httpserver.pro.user | 4 +- httpserver/DataVariantAbstract.h | 16 +- httpserver/DataVariantFormUrlencoded.cpp | 10 +- httpserver/DataVariantFormUrlencoded.h | 6 +- httpserver/DataVariantMultipartFormData.cpp | 24 +- httpserver/DataVariantMultipartFormData.h | 9 +- httpserver/DataVariantTextPlain.cpp | 10 +- httpserver/DataVariantTextPlain.h | 6 +- httpserver/Event.cpp | 4 +- httpserver/RequestParameters.cpp | 21 + httpserver/RequestParameters.h | 31 + httpserver/Server.cpp | 967 +++++++++++--------- httpserver/Server.h | 75 +- httpserver/ServerApplicationsTree.cpp | 18 +- httpserver/ServerApplicationsTree.h | 4 +- httpserver/SocketList.cpp | 14 +- httpserver/System.cpp | 2 +- httpserver/Utils.cpp | 6 +- httpserver/Utils.h | 2 +- 20 files changed, 689 insertions(+), 546 deletions(-) create mode 100644 httpserver/RequestParameters.cpp create mode 100644 httpserver/RequestParameters.h diff --git a/httpserver.pro b/httpserver.pro index 6cd9179..a43e9af 100644 --- a/httpserver.pro +++ b/httpserver.pro @@ -34,7 +34,8 @@ SOURCES += \ httpserver/SocketList.cpp \ httpserver/System.cpp \ httpserver/Utils.cpp \ - httpserver/ConfigParser.cpp + httpserver/ConfigParser.cpp \ + httpserver/RequestParameters.cpp include(deployment.pri) qtcAddDeployment() @@ -60,5 +61,6 @@ HEADERS += \ httpserver/SocketList.h \ httpserver/System.h \ httpserver/Utils.h \ - httpserver/ConfigParser.h + httpserver/ConfigParser.h \ + httpserver/RequestParameters.h diff --git a/httpserver.pro.user b/httpserver.pro.user index 3e82bde..8782157 100644 --- a/httpserver.pro.user +++ b/httpserver.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/httpserver/DataVariantAbstract.h b/httpserver/DataVariantAbstract.h index c3e5f60..6b287d9 100644 --- a/httpserver/DataVariantAbstract.h +++ b/httpserver/DataVariantAbstract.h @@ -1,9 +1,7 @@ #pragma once #include "Socket.h" -#include "FileIncoming.h" - -#include +#include "RequestParameters.h" namespace HttpServer { @@ -26,24 +24,20 @@ namespace HttpServer /** * @param const Socket & - сокет, откуда можно достать остальные данные - * @param const std::chrono::milliseconds & - максимальное время ожидания данных (на сокете) * @param std::string & - первая часть полученных данных * @param const size_t - сколько осталось данных (в байтах) получить из сокета * @param const std::unordered_map & - дополнительные параметры, описывающие формат данных - * @param std::unordered_multimap & - данные в виде ключ->значение - * @param std::unordered_multimap & - имена файлов, в которые записаны данные + * @param request_data & - данные текущего запроса (заголовки, параметры, коллекции для хранения данных) * * @return bool - (true|false) - удачно ли были разобраны данные */ virtual bool parse ( - const Socket &, - const std::chrono::milliseconds &, + const Socket &sock, std::string &, const size_t, - const std::unordered_map &, - std::unordered_multimap &, - std::unordered_multimap & + std::unordered_map &contentParams, + struct request_parameters &rp ) = 0; }; }; \ No newline at end of file diff --git a/httpserver/DataVariantFormUrlencoded.cpp b/httpserver/DataVariantFormUrlencoded.cpp index 74b4637..82dd992 100644 --- a/httpserver/DataVariantFormUrlencoded.cpp +++ b/httpserver/DataVariantFormUrlencoded.cpp @@ -13,12 +13,10 @@ namespace HttpServer bool DataVariantFormUrlencoded::parse ( const Socket &sock, - const std::chrono::milliseconds &timeout, std::string &str, const size_t leftBytes, - const std::unordered_map ¶ms, - std::unordered_multimap &data, - std::unordered_multimap &files + std::unordered_map &contentParams, + struct request_parameters &rp ) { if (str.empty() ) @@ -40,7 +38,7 @@ namespace HttpServer std::string var_name = Utils::urlDecode(str.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos) ); // Сохранить параметр с пустым значением - data.emplace(std::move(var_name), ""); + rp.incoming_data.emplace(std::move(var_name), ""); } else { @@ -53,7 +51,7 @@ namespace HttpServer std::string var_value = Utils::urlDecode(str.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos) ); // Сохранить параметр и значение - data.emplace(std::move(var_name), std::move(var_value) ); + rp.incoming_data.emplace(std::move(var_name), std::move(var_value) ); } } diff --git a/httpserver/DataVariantFormUrlencoded.h b/httpserver/DataVariantFormUrlencoded.h index 5e3893a..86d8ad3 100644 --- a/httpserver/DataVariantFormUrlencoded.h +++ b/httpserver/DataVariantFormUrlencoded.h @@ -13,12 +13,10 @@ namespace HttpServer virtual bool parse ( const Socket &, - const std::chrono::milliseconds &, std::string &, const size_t, - const std::unordered_map &, - std::unordered_multimap &, - std::unordered_multimap & + std::unordered_map &contentParams, + struct request_parameters &rp ) override; }; }; \ No newline at end of file diff --git a/httpserver/DataVariantMultipartFormData.cpp b/httpserver/DataVariantMultipartFormData.cpp index c5b0280..1badbab 100644 --- a/httpserver/DataVariantMultipartFormData.cpp +++ b/httpserver/DataVariantMultipartFormData.cpp @@ -56,18 +56,16 @@ namespace HttpServer bool DataVariantMultipartFormData::parse ( const Socket &sock, - const std::chrono::milliseconds &timeout, std::string &str, const size_t leftBytes, - const std::unordered_map ¶ms, - std::unordered_multimap &data, - std::unordered_multimap &files + std::unordered_map &contentParams, + struct request_parameters &rp ) { // Проверить есть ли в параметрах разделитель блоков данных - auto it = params.find("boundary"); + auto it = contentParams.find("boundary"); - if (params.cend() == it) + if (contentParams.cend() == it) { return false; } @@ -101,7 +99,7 @@ namespace HttpServer if (std::string::npos == str_cur) { // Получить следующий кусок данных - if (false == append(sock, timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) { return false; } @@ -134,7 +132,7 @@ namespace HttpServer if (std::string::npos == headers_end) { // Получить следующий кусок данных - if (false == append(sock, timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) { return false; } @@ -293,7 +291,7 @@ namespace HttpServer str.erase(str.begin(), str.end() - data_end.length() ); // Получить следующий кусок данных - if (false == append(sock, timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) { return false; } @@ -306,7 +304,7 @@ namespace HttpServer file.write(str.data(), delimiter); // Добавить данные в список - files.emplace(it_name->second, FileIncoming(std::move(tmp_name), it_filetype->second, file.tellp() ) ); + rp.incoming_files.emplace(it_name->second, FileIncoming(std::move(tmp_name), it_filetype->second, file.tellp() ) ); file.close(); @@ -349,7 +347,7 @@ namespace HttpServer str.erase(str.begin(), str.end() - data_end.length() ); // Получить следующий кусок данных - if (false == append(sock, timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) { return false; } @@ -362,7 +360,7 @@ namespace HttpServer value.append(str.cbegin(), str.cbegin() + delimiter); // Добавить данные в список - data.emplace(it_name->second, std::move(value) ); + rp.incoming_data.emplace(it_name->second, std::move(value) ); // Если найден конец данных if (str.find(data_end, delimiter) == delimiter) @@ -401,7 +399,7 @@ namespace HttpServer str.erase(str.begin(), str.end() - data_end.length() ); // Получить следующий кусок данных - if (false == append(sock, timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) { return false; } diff --git a/httpserver/DataVariantMultipartFormData.h b/httpserver/DataVariantMultipartFormData.h index daadc63..75615d4 100644 --- a/httpserver/DataVariantMultipartFormData.h +++ b/httpserver/DataVariantMultipartFormData.h @@ -15,7 +15,8 @@ namespace HttpServer const Socket &, const std::chrono::milliseconds &, std::vector &, - std::string &, const std::string &, + std::string &, + const std::string &, const size_t &, size_t &, size_t & @@ -25,12 +26,10 @@ namespace HttpServer virtual bool parse ( const Socket &, - const std::chrono::milliseconds &, std::string &, const size_t, - const std::unordered_map &, - std::unordered_multimap &, - std::unordered_multimap & + std::unordered_map &contentParams, + struct request_parameters &rp ) override; }; }; \ No newline at end of file diff --git a/httpserver/DataVariantTextPlain.cpp b/httpserver/DataVariantTextPlain.cpp index 0134b9e..585b377 100644 --- a/httpserver/DataVariantTextPlain.cpp +++ b/httpserver/DataVariantTextPlain.cpp @@ -11,12 +11,10 @@ namespace HttpServer bool DataVariantTextPlain::parse ( const Socket &sock, - const std::chrono::milliseconds &timeout, std::string &str, const size_t leftBytes, - const std::unordered_map ¶ms, - std::unordered_multimap &data, - std::unordered_multimap &files + std::unordered_map &contentParams, + struct request_parameters &rp ) { if (str.empty() ) @@ -38,7 +36,7 @@ namespace HttpServer std::string var_name = str.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos); // Сохранить параметр с пустым значением - data.emplace(std::move(var_name), ""); + rp.incoming_data.emplace(std::move(var_name), ""); } else { @@ -51,7 +49,7 @@ namespace HttpServer std::string var_value = str.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos); // Сохранить параметр и значение - data.emplace(std::move(var_name), std::move(var_value) ); + rp.incoming_data.emplace(std::move(var_name), std::move(var_value) ); } } diff --git a/httpserver/DataVariantTextPlain.h b/httpserver/DataVariantTextPlain.h index 58cd4db..90f469b 100644 --- a/httpserver/DataVariantTextPlain.h +++ b/httpserver/DataVariantTextPlain.h @@ -13,12 +13,10 @@ namespace HttpServer virtual bool parse ( const Socket &, - const std::chrono::milliseconds &, std::string &, const size_t, - const std::unordered_map &, - std::unordered_multimap &, - std::unordered_multimap & + std::unordered_map &contentParams, + struct request_parameters &rp ) override; }; }; \ No newline at end of file diff --git a/httpserver/Event.cpp b/httpserver/Event.cpp index 218caf3..7e919c1 100644 --- a/httpserver/Event.cpp +++ b/httpserver/Event.cpp @@ -26,7 +26,7 @@ namespace HttpServer { std::unique_lock lck(mtx); - auto status = cv.wait_for(lck, ms); + auto const status = cv.wait_for(lck, ms); if (false == manualy) { @@ -40,7 +40,7 @@ namespace HttpServer { std::unique_lock lck(mtx); - auto status = cv.wait_until(lck, tp); + auto const status = cv.wait_until(lck, tp); if (false == manualy) { diff --git a/httpserver/RequestParameters.cpp b/httpserver/RequestParameters.cpp new file mode 100644 index 0000000..d3e1c39 --- /dev/null +++ b/httpserver/RequestParameters.cpp @@ -0,0 +1,21 @@ + +#include "RequestParameters.h" + +namespace HttpServer +{ + void request_parameters::clear() + { + incoming_headers.clear(); + incoming_params.clear(); + incoming_data.clear(); + incoming_files.clear(); + + outgoing_headers.clear(); + + method.clear(); + version.clear(); + uri_reference.clear(); + + timeout = std::chrono::milliseconds::zero(); + } +}; \ No newline at end of file diff --git a/httpserver/RequestParameters.h b/httpserver/RequestParameters.h new file mode 100644 index 0000000..0d3e209 --- /dev/null +++ b/httpserver/RequestParameters.h @@ -0,0 +1,31 @@ +#pragma once + +#include "FileIncoming.h" + +#include +#include + +namespace HttpServer +{ + struct request_parameters + { + std::unordered_map incoming_headers; + std::unordered_multimap incoming_params; + std::unordered_multimap incoming_data; + std::unordered_multimap incoming_files; + + std::unordered_map outgoing_headers; + + std::string method; + std::string version; + std::string uri_reference; + + std::chrono::milliseconds timeout; + + size_t keep_alive_count; + int connection_params; + int app_exit_code; + + void clear(); + }; +}; \ No newline at end of file diff --git a/httpserver/Server.cpp b/httpserver/Server.cpp index 7404c89..0c9f455 100644 --- a/httpserver/Server.cpp +++ b/httpserver/Server.cpp @@ -20,58 +20,47 @@ namespace HttpServer { - int Server::transferFilePart - ( - const Socket &clientSocket, - const std::chrono::milliseconds &timeout, - const std::string &fileName, - const time_t fileTime, - const size_t fileSize, + std::string Server::getMimeTypeByFileName(const std::string &fileName) const + { + const size_t ext_pos = fileName.rfind('.'); + std::string file_ext = std::string::npos != ext_pos ? fileName.substr(ext_pos + 1) : ""; + + std::locale loc; + Utils::tolower(file_ext, loc); + + auto it_mime = this->mimes_types.find(file_ext); + + return this->mimes_types.cend() != it_mime ? it_mime->second : "application/octet-stream"; + } + + std::vector > Server::getRanges( const std::string &rangeHeader, - const std::string &connectionHeader, - const std::string &dateHeader, - const bool headersOnly + const size_t posSymEqual, + const size_t fileSize, + std::string &resultRangeHeader, + size_t &contentLength ) const { - size_t delimiter = rangeHeader.find('='); - - if (std::string::npos == delimiter) - { - // HTTP 400 - std::string headers("HTTP/1.1 400 Bad Request\r\n"); - headers += connectionHeader + dateHeader + "\r\n"; + std::vector > ranges; - clientSocket.nonblock_send(headers, timeout); + contentLength = 0; - return 0; - } + size_t delimiter = posSymEqual; // rangeHeader.find('='); - std::string range_unit_name(rangeHeader.cbegin(), rangeHeader.cbegin() + delimiter); + const std::string range_unit_name(rangeHeader.cbegin(), rangeHeader.cbegin() + delimiter); - const std::unordered_map ranges_units { + static const std::unordered_map ranges_units { {"bytes", 1} }; auto it_unit = ranges_units.find(range_unit_name); - if (ranges_units.cend() == it_unit) + if (ranges_units.cend() == it_unit) { - // HTTP 416 - std::string headers("HTTP/1.1 416 Requested Range Not Satisfiable\r\n"); - headers += connectionHeader + dateHeader + "\r\n"; - - clientSocket.nonblock_send(headers, timeout); - - return 0; + return ranges; } - const size_t range_unit = it_unit->second; - - std::vector > ranges; - - std::string content_range_header("bytes "); - - size_t content_length = 0; + const size_t &range_unit = it_unit->second; for (size_t str_pos; std::string::npos != delimiter; ) { @@ -105,9 +94,9 @@ namespace HttpServer const size_t length = range_end - range_begin + 1; - content_length += length; + contentLength += length; - content_range_header += std::to_string(range_begin) + '-' + std::to_string(range_end) + ','; + resultRangeHeader += std::to_string(range_begin) + '-' + std::to_string(range_end) + ','; ranges.emplace_back(std::tuple {range_begin, length}); } @@ -116,9 +105,9 @@ namespace HttpServer { const size_t length = fileSize - range_begin; - content_length += length; + contentLength += length; - content_range_header += std::to_string(range_begin) + '-' + std::to_string(fileSize - 1) + ','; + resultRangeHeader += std::to_string(range_begin) + '-' + std::to_string(fileSize - 1) + ','; ranges.emplace_back(std::tuple {range_begin, length}); } @@ -134,15 +123,57 @@ namespace HttpServer range_end = fileSize - range_begin - 1; - content_length += length; + contentLength += length; - content_range_header += std::to_string(range_begin) + '-' + std::to_string(range_end) + ','; + resultRangeHeader += std::to_string(range_begin) + '-' + std::to_string(range_end) + ','; ranges.emplace_back(std::tuple {range_begin, length}); } } } + if (false == ranges.empty() ) + { + resultRangeHeader.back() = '/'; + + resultRangeHeader = "bytes " + resultRangeHeader + std::to_string(fileSize); + } + + return ranges; + } + + int Server::transferFilePart + ( + const Socket &clientSocket, + const std::chrono::milliseconds &timeout, + const std::string &fileName, + const time_t fileTime, + const size_t fileSize, + const std::string &rangeHeader, + const std::string &connectionHeader, + const std::string &dateHeader, + const bool headersOnly + ) const + { + const size_t pos_sym_equal = rangeHeader.find('='); + + if (std::string::npos == pos_sym_equal) + { + // HTTP 400 + std::string headers("HTTP/1.1 400 Bad Request\r\n"); + headers += connectionHeader + dateHeader + "\r\n"; + + clientSocket.nonblock_send(headers, timeout); + + return 0; + } + + std::string content_range_header; + + size_t content_length; + + const std::vector > ranges = this->getRanges(rangeHeader, pos_sym_equal, fileSize, content_range_header, content_length); + if (0 == content_length) { // HTTP 416 @@ -154,10 +185,6 @@ namespace HttpServer return 0; } - content_range_header.back() = '/'; - - content_range_header += std::to_string(fileSize); - // Ranges transfer std::ifstream file(fileName, std::ifstream::binary); @@ -174,22 +201,14 @@ namespace HttpServer return 0; } - const size_t ext_pos = fileName.rfind('.'); - std::string file_ext = std::string::npos != ext_pos ? fileName.substr(ext_pos + 1) : ""; - - std::locale loc; - Utils::tolower(file_ext, loc); - - auto it_mime = this->mimes_types.find(file_ext); - - std::string file_mime_type = this->mimes_types.cend() != it_mime ? it_mime->second : "application/octet-stream"; + const std::string file_mime_type = this->getMimeTypeByFileName(fileName); std::string headers("HTTP/1.1 206 Partial Content\r\n"); headers += "Content-Type: " + file_mime_type + "\r\n" + "Content-Length: " + std::to_string(content_length) + "\r\n" + "Accept-Ranges: bytes\r\n" + "Content-Range: " + content_range_header + "\r\n" - + "Last-Modified: " + Utils::getDatetimeStringValue(fileTime, true) + "\r\n" + + "Last-Modified: " + Utils::getDatetimeAsString(fileTime, true) + "\r\n" + connectionHeader + dateHeader + "\r\n"; // Отправить заголовки @@ -208,7 +227,9 @@ namespace HttpServer std::vector buf(length < 512 * 1024 ? length : 512 * 1024); - file.seekg(std::get<0>(range), file.beg); + const size_t position = std::get<0>(range); + + file.seekg(position, file.beg); size_t send_size_left = length; @@ -232,7 +253,7 @@ namespace HttpServer file.close(); - return 0; + return 1; } /** @@ -241,16 +262,14 @@ namespace HttpServer int Server::transferFile ( const Socket &clientSocket, - const std::chrono::milliseconds &timeout, const std::string &fileName, - const std::unordered_map &inHeaders, - const std::unordered_map &outHeaders, const std::string &connectionHeader, - const bool headersOnly + const bool headersOnly, + struct request_parameters &rp ) const { // Get current time in GMT - const std::string date_header = "Date: " + Utils::getDatetimeStringValue() + "\r\n"; + const std::string date_header = "Date: " + Utils::getDatetimeAsString() + "\r\n"; time_t file_time; size_t file_size; @@ -262,16 +281,16 @@ namespace HttpServer std::string headers("HTTP/1.1 404 Not Found\r\n"); headers += connectionHeader + date_header + "\r\n"; - clientSocket.nonblock_send(headers, timeout); + clientSocket.nonblock_send(headers, rp.timeout); return 0; } // Check for If-Modified header - auto it_modified = inHeaders.find("If-Modified-Since"); + auto it_modified = rp.incoming_headers.find("If-Modified-Since"); // Если найден заголовок проверки изменения файла (проверить, изменялся ли файл) - if (inHeaders.cend() != it_modified) + if (rp.incoming_headers.cend() != it_modified) { const time_t time_in_request = Utils::stringTimeToTimestamp(it_modified->second); @@ -281,18 +300,18 @@ namespace HttpServer std::string headers("HTTP/1.1 304 Not Modified\r\n"); headers += connectionHeader + date_header + "\r\n"; - clientSocket.nonblock_send(headers, timeout); + clientSocket.nonblock_send(headers, rp.timeout); return 0; } } - auto it_range = inHeaders.find("Range"); + auto it_range = rp.incoming_headers.find("Range"); // Range transfer - if (inHeaders.cend() != it_range) + if (rp.incoming_headers.cend() != it_range) { - return this->transferFilePart(clientSocket, timeout, fileName, file_time, file_size, it_range->second, connectionHeader, date_header, headersOnly); + return this->transferFilePart(clientSocket, rp.timeout, fileName, file_time, file_size, it_range->second, connectionHeader, date_header, headersOnly); } // File transfer @@ -306,30 +325,22 @@ namespace HttpServer std::string headers("HTTP/1.1 500 Internal Server Error\r\n"); headers += connectionHeader + date_header + "\r\n"; - clientSocket.nonblock_send(headers, timeout); + clientSocket.nonblock_send(headers, rp.timeout); return 0; } - const size_t ext_pos = fileName.rfind('.'); - std::string file_ext = std::string::npos != ext_pos ? fileName.substr(ext_pos + 1) : ""; - - std::locale loc; - Utils::tolower(file_ext, loc); - - auto it_mime = this->mimes_types.find(file_ext); - - std::string file_mime_type = this->mimes_types.cend() != it_mime ? it_mime->second : "application/octet-stream"; + const std::string file_mime_type = this->getMimeTypeByFileName(fileName); std::string headers("HTTP/1.1 200 OK\r\n"); headers += "Content-Type: " + file_mime_type + "\r\n" + "Content-Length: " + std::to_string(file_size) + "\r\n" + "Accept-Ranges: bytes\r\n" - + "Last-Modified: " + Utils::getDatetimeStringValue(file_time, true) + "\r\n" + + "Last-Modified: " + Utils::getDatetimeAsString(file_time, true) + "\r\n" + connectionHeader + date_header + "\r\n"; // Отправить заголовки - if (std::numeric_limits::max() == clientSocket.nonblock_send(headers, timeout) ) + if (std::numeric_limits::max() == clientSocket.nonblock_send(headers, rp.timeout) ) { file.close(); @@ -346,20 +357,20 @@ namespace HttpServer do { file.read(reinterpret_cast(buf.data() ), buf.size() ); - send_size = clientSocket.nonblock_send(buf, file.gcount(), timeout); + send_size = clientSocket.nonblock_send(buf, file.gcount(), rp.timeout); } while (false == file.eof() && false == file.fail() && std::numeric_limits::max() != send_size); } file.close(); - return 0; + return 1; } /** * Парсинг переданных параметров (URI) */ - bool Server::parseIncomingVars(std::unordered_multimap ¶ms, const std::string &uriParams) const + bool Server::parseIncomingVars(std::unordered_multimap ¶ms, const std::string &uriParams) { if (uriParams.length() ) { @@ -400,7 +411,7 @@ namespace HttpServer return false; } - void Server::sendStatus(const Socket &clientSocket, const std::chrono::milliseconds &timeout, const size_t statusCode) const + void Server::sendStatus(const Socket &clientSocket, const std::chrono::milliseconds &timeout, const size_t statusCode) { static const std::unordered_map statuses { {400, "Bad Request"}, @@ -421,15 +432,13 @@ namespace HttpServer } /** - * Метод для обработки запроса (запускается в отдельном потоке) + * Метод для обработки запроса */ int Server::threadRequestProc(Socket clientSocket) const { - int app_exit_code; + struct request_parameters rp; - bool connection_upgrade = false; - bool connection_keep_alive; - size_t keep_alive_count = 100; + rp.keep_alive_count = 100; const size_t buf_len = 4096; std::vector buf(buf_len); @@ -438,441 +447,497 @@ namespace HttpServer do { - app_exit_code = EXIT_FAILURE; + rp.app_exit_code = EXIT_FAILURE; - std::unordered_map incoming_headers; - std::unordered_multimap incoming_params; - std::unordered_multimap incoming_data; - std::unordered_multimap incoming_files; + // Подготовить параметры для получения данных + rp.timeout = std::chrono::milliseconds(5000); - std::unordered_map outgoing_headers; + if (false == getRequest(clientSocket, buf, str_buf, rp) ) + { + break; + } - std::string method; - std::string version; - std::string uri_reference; + if (int error_code = getRequestHeaders(str_buf, rp) ) + { + this->sendStatus(clientSocket, rp.timeout, error_code); - // Подготовить параметры для получения данных - std::chrono::milliseconds timeout(500); + break; + } - // Получить данные запроса от клиента - const size_t recv_size = clientSocket.nonblock_recv(buf, timeout); + const ServerApplicationSettings *app_sets = getApplicationSettings(rp); - if (std::numeric_limits::max() == recv_size && str_buf.empty() ) + // Если приложение не найдено + if (nullptr == app_sets) { - #ifdef DEBUG - #ifdef WIN32 - std::cout << "Error: " << WSAGetLastError() << std::endl; - #elif POSIX - std::cout << "Error: " << errno << std::endl; - #endif - #endif + // HTTP 404 Not Found + this->sendStatus(clientSocket, rp.timeout, 404); + break; } - if (recv_size) // Если данные были получены + if (int error_code = getRequestData(clientSocket, str_buf, *app_sets, rp) ) { - str_buf.append(buf.cbegin(), buf.cbegin() + recv_size); + this->sendStatus(clientSocket, rp.timeout, error_code); + + break; } - if (false == str_buf.empty() ) + runApplication(clientSocket, *app_sets, rp); + + for (auto &it : rp.incoming_files) { - // Поиск конца заголовков (пустая строка) - size_t headers_end = str_buf.find("\r\n\r\n"); + remove(it.second.getName().c_str() ); + } - // Если найден конец заголовков - if (std::string::npos != headers_end) - { - headers_end += 2; + if (EXIT_SUCCESS == rp.app_exit_code) + { + this->getConnectionParams(rp); - size_t str_cur = 0; - // Поиск конца первого заголовка - size_t str_end = str_buf.find("\r\n"); + this->xSendfile(clientSocket, rp); + } + else + { + rp.connection_params = CONNECTION_CLOSED; + } - // Если не найден конец заголовка - if (std::string::npos == str_end) - { - sendStatus(clientSocket, timeout, 400); - break; - } + rp.clear(); + } + while (isConnectionKeepAlive(rp) ); - // Установка конца строки (для поиска) - str_buf[str_end] = '\0'; + if (false == isConnectionUpgrade(rp) ) + { + // Wait for send all data to client + clientSocket.nonblock_send_sync(); - // Разделить метод запроса и параметры запроса - size_t delimiter = str_buf.find(' ', str_cur); + clientSocket.shutdown(); + clientSocket.close(); + } - // Получить метод запроса (GET, POST, PUT, DELETE, ...) - method = str_buf.substr(str_cur, delimiter - str_cur); - // Сохранить метод и параметры запроса - incoming_headers[method] = str_buf.substr(delimiter + 1, str_end - delimiter - 1); + return rp.app_exit_code; + } - delimiter += 1; - // Найти окончание URI - size_t uri_end = str_buf.find(' ', delimiter); + bool Server::getRequest(Socket clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp) + { + // Получить данные запроса от клиента + const size_t recv_size = clientSocket.nonblock_recv(buf, rp.timeout); - // Если окончание не найдено - if (std::string::npos == uri_end) - { - uri_end = str_end; - // то версия протокола HTTP - 0.9 - version = "0.9"; - } - else // Если окончание найдено - { - str_buf[uri_end] = '\0'; - const size_t ver_beg = uri_end + 6; // Пропустить "HTTP/" + if (std::numeric_limits::max() == recv_size && str_buf.empty() ) + { + #ifdef DEBUG + #ifdef WIN32 + std::cout << "Error: " << WSAGetLastError() << std::endl; + #elif POSIX + std::cout << "Error: " << errno << std::endl; + #endif + #endif + return false; + } - if (ver_beg < str_end) - { - // Получить версию протокола HTTP - version = str_buf.substr(ver_beg, str_end - ver_beg); - } - } + if (recv_size) // Если данные были получены + { + str_buf.append(buf.cbegin(), buf.cbegin() + recv_size); + } - // Поиск именованных параметров запросов (переменных ?) - size_t params_pos = str_buf.find('?', delimiter); + return true; + } - // Сохранить полную ссылку URI (без параметров) - uri_reference = (std::string::npos == params_pos) ? str_buf.substr(delimiter) : str_buf.substr(delimiter, params_pos - delimiter); + int Server::getRequestHeaders(std::string &str_buf, struct request_parameters &rp) const + { + // Если запрос пустой + if (str_buf.empty() ) + { + // HTTP 400 Bad Request + return 400; + } - if (std::string::npos != params_pos) - { - // Извлекаем параметры запроса из URI - if (false == parseIncomingVars(incoming_params, str_buf.substr(params_pos + 1, uri_end) ) ) - { - // HTTP 400 Bad Request - this->sendStatus(clientSocket, timeout, 400); - break; - } - } + // Поиск конца заголовков (пустая строка) + size_t headers_end = str_buf.find("\r\n\r\n"); - // Переход к обработке следующего заголовка - str_cur = str_end + 2; - // Поиск конца заголовка - str_end = str_buf.find("\r\n", str_cur); - // Установка конца заголовка - str_buf[str_end] = '\0'; + // Если найден конец заголовков + if (std::string::npos == headers_end) + { + // HTTP 400 Bad Request + return 400; + } - // Цикл извлечения заголовков запроса - for (; str_cur != headers_end; str_end = str_buf.find("\r\n", str_cur), str_buf[str_end] = '\0') - { - // Поиск разделителя названия заголовка и его значения - delimiter = str_buf.find(':', str_cur); + headers_end += 2; - // Если разделитель найден в текущей строке - if (delimiter < str_end) - { - std::string header_name = str_buf.substr(str_cur, delimiter - str_cur); - std::string header_value = str_buf.substr(delimiter + 1, str_end - delimiter - 1); + size_t str_cur = 0; + // Поиск конца первого заголовка + size_t str_end = str_buf.find("\r\n"); - // Удалить лишние пробелы в начале и в конце строки - Utils::trim(header_value); + // Если не найден конец заголовка + if (std::string::npos == str_end) + { + // HTTP 400 Bad Request + return 400; + } - // Сохранить заголовок и его значение - incoming_headers.emplace(std::move(header_name), std::move(header_value) ); - } + // Установка конца строки (для поиска) + str_buf[str_end] = '\0'; - // Перейти к следующей строке - str_cur = str_end + 2; - } + // Разделить метод запроса и параметры запроса + size_t delimiter = str_buf.find(' ', str_cur); - str_buf.erase(str_buf.begin(), str_buf.begin() + headers_end + 2); + // Получить метод запроса (GET, POST, PUT, DELETE, ...) + rp.method = str_buf.substr(str_cur, delimiter - str_cur); + // Сохранить метод и параметры запроса + rp.incoming_headers[rp.method] = str_buf.substr(delimiter + 1, str_end - delimiter - 1); - // Получить доменное имя (или адрес) назначения запроса - auto it_host = incoming_headers.find("Host"); + delimiter += 1; + // Найти окончание URI + size_t uri_end = str_buf.find(' ', delimiter); - // Если имя задано - продолжить обработку запроса - if (incoming_headers.cend() != it_host) - { - // Поиск разделителя, за которым помещается номер порта (сокета), если указан - size_t delimiter = it_host->second.find(':'); + // Если окончание не найдено + if (std::string::npos == uri_end) + { + uri_end = str_end; + // то версия протокола HTTP - 0.9 + rp.version = "0.9"; + } + else // Если окончание найдено + { + str_buf[uri_end] = '\0'; + const size_t ver_beg = uri_end + 6; // Пропустить "HTTP/" - // Получить имя (или адрес) - const std::string host = it_host->second.substr(0, delimiter); + if (ver_beg < str_end) + { + // Получить версию протокола HTTP + rp.version = str_buf.substr(ver_beg, str_end - ver_beg); + } + } - // Получить номер порта - const int port = (std::string::npos != delimiter) ? std::strtol(it_host->second.substr(delimiter + 1).c_str(), nullptr, 10) : 80; + // Поиск именованных параметров запросов (переменных ?) + const size_t params_pos = str_buf.find('?', delimiter); - // Поиск настроек приложения по имени - ServerApplicationSettings *app_sets = this->apps_tree.find(host); + // Сохранить полную ссылку URI (без параметров) + rp.uri_reference = (std::string::npos == params_pos) ? str_buf.substr(delimiter) : str_buf.substr(delimiter, params_pos - delimiter); - // Если приложение найдено - if (app_sets && app_sets->port == port) - { - // Определить вариант данных запроса (заодно проверить, есть ли данные) - auto it = incoming_headers.find("Content-Type"); + if (std::string::npos != params_pos) + { + // Извлекаем параметры запроса из URI + if (false == parseIncomingVars(rp.incoming_params, str_buf.substr(params_pos + 1, uri_end) ) ) + { + // HTTP 400 Bad Request + return 400; + } + } - if (incoming_headers.cend() != it) - { - // Параметры - std::unordered_map content_params; + // Переход к обработке следующего заголовка + str_cur = str_end + 2; + // Поиск конца заголовка + str_end = str_buf.find("\r\n", str_cur); + // Установка конца заголовка + str_buf[str_end] = '\0'; - // Получить значение заголовка - std::string &header_value = it->second; + // Цикл извлечения заголовков запроса + for (; str_cur != headers_end; str_end = str_buf.find("\r\n", str_cur), str_buf[str_end] = '\0') + { + // Поиск разделителя названия заголовка и его значения + delimiter = str_buf.find(':', str_cur); - // Определить, содержит ли тип данных запроса дополнительные параметры - delimiter = header_value.find(';'); + // Если разделитель найден в текущей строке + if (delimiter < str_end) + { + std::string header_name = str_buf.substr(str_cur, delimiter - str_cur); + std::string header_value = str_buf.substr(delimiter + 1, str_end - delimiter - 1); - std::string data_variant_name; // Название варианта данных запроса + // Удалить лишние пробелы в начале и в конце строки + Utils::trim(header_value); - // Если есть дополнительные параметры - извлекаем их - if (std::string::npos != delimiter) - { - data_variant_name = header_value.substr(0, delimiter); - Utils::trim(data_variant_name); - - for (size_t str_param_cur = delimiter + 1, str_param_end = 0; std::string::npos != str_param_end; str_param_cur = str_param_end + 1) - { - str_param_end = header_value.find(';', str_param_cur); - delimiter = header_value.find('=', str_param_cur); - - if (delimiter >= str_param_end) - { - std::string param_name = header_value.substr(str_param_cur, std::string::npos != str_param_end ? str_param_end - str_param_cur : std::string::npos); - Utils::trim(param_name); - content_params.emplace(std::move(param_name), ""); - } - else - { - std::string param_name = header_value.substr(str_param_cur, delimiter - str_param_cur); - Utils::trim(param_name); - - ++delimiter; - - std::string param_value = header_value.substr(delimiter, std::string::npos != str_param_end ? str_param_end - delimiter : std::string::npos); - Utils::trim(param_value); - - content_params.emplace(std::move(param_name), std::move(param_value) ); - } - } - } - else - { - data_variant_name = header_value; - } + // Сохранить заголовок и его значение + rp.incoming_headers.emplace(std::move(header_name), std::move(header_value) ); + } - // Поиск варианта данных по имени типа - auto variant = this->variants.find(data_variant_name); + // Перейти к следующей строке + str_cur = str_end + 2; + } - // Если сервер поддерживает формат полученных данных - if (this->variants.cend() != variant) - { - DataVariantAbstract *data_variant = variant->second; - - // Получить длину запроса в байтах - size_t data_length = 0; - - auto it_len = incoming_headers.find("Content-Length"); - - if (incoming_headers.cend() != it_len) - { - data_length = std::strtoull(it_len->second.c_str(), nullptr, 10); - } - - // Если размер запроса не превышает лимит (если лимит был установлен) - if (data_length <= app_sets->request_max_size || 0 == app_sets->request_max_size) - { - // Сколько осталось получить данных - size_t left_bytes = 0; - - std::string data_buf; - - if (data_length >= str_buf.length() ) - { - left_bytes = data_length - str_buf.length(); - - data_buf.swap(str_buf); - } - else - { - data_buf.assign(str_buf.cbegin(), str_buf.cbegin() + data_length); - str_buf.erase(str_buf.begin(), str_buf.begin() + data_length); - } - - // Разобрать данные на составляющие - if (false == data_variant->parse(clientSocket, timeout, data_buf, left_bytes, content_params, incoming_data, incoming_files) ) - { - for (auto &it : incoming_files) - { - remove(it.second.getName().c_str() ); - } - - // HTTP 400 Bad Request - this->sendStatus(clientSocket, timeout, 400); - - break; - } - - if (false == data_buf.empty() ) - { - str_buf.swap(data_buf); - } - } - else - { - // HTTP 413 Request Entity Too Large - this->sendStatus(clientSocket, timeout, 413); - - break; - } - } - else - { - // HTTP 400 Bad Request - this->sendStatus(clientSocket, timeout, 400); + str_buf.erase(str_buf.begin(), str_buf.begin() + headers_end + 2); - break; - } - } + return 0; + } - Utils::raw_pair *raw_pair_params = nullptr; - Utils::raw_pair *raw_pair_headers = nullptr; - Utils::raw_pair *raw_pair_data = nullptr; - Utils::raw_fileinfo *raw_fileinfo_files = nullptr; - - Utils::stlUnorderedMultimapToRawPairs(&raw_pair_params, incoming_params); - Utils::stlUnorderedMapToRawPairs(&raw_pair_headers, incoming_headers); - Utils::stlUnorderedMultimapToRawPairs(&raw_pair_data, incoming_data); - Utils::filesIncomingToRawFilesInfo(&raw_fileinfo_files, incoming_files); - - server_request request { - clientSocket.get_handle(), - method.c_str(), - uri_reference.c_str(), - app_sets->root_dir.c_str(), - incoming_params.size(), - raw_pair_params, - incoming_headers.size(), - raw_pair_headers, - incoming_data.size(), - raw_pair_data, - incoming_files.size(), - raw_fileinfo_files - }; - - server_response response { - clientSocket.get_handle(), 0, nullptr - }; - - // Попытаться - try - { - // Запустить приложение - app_exit_code = app_sets->application_call(&request, &response); - } - catch (...) - { - app_exit_code = EXIT_FAILURE; - } + void Server::runApplication(Socket clientSocket, const ServerApplicationSettings &appSets, struct request_parameters &rp) + { + Utils::raw_pair *raw_pair_params = nullptr; + Utils::raw_pair *raw_pair_headers = nullptr; + Utils::raw_pair *raw_pair_data = nullptr; + Utils::raw_fileinfo *raw_fileinfo_files = nullptr; + + Utils::stlUnorderedMultimapToRawPairs(&raw_pair_params, rp.incoming_params); + Utils::stlUnorderedMapToRawPairs(&raw_pair_headers, rp.incoming_headers); + Utils::stlUnorderedMultimapToRawPairs(&raw_pair_data, rp.incoming_data); + Utils::filesIncomingToRawFilesInfo(&raw_fileinfo_files, rp.incoming_files); + + server_request request { + clientSocket.get_handle(), + rp.method.c_str(), + rp.uri_reference.c_str(), + appSets.root_dir.c_str(), + rp.incoming_params.size(), + raw_pair_params, + rp.incoming_headers.size(), + raw_pair_headers, + rp.incoming_data.size(), + raw_pair_data, + rp.incoming_files.size(), + raw_fileinfo_files + }; - if (EXIT_SUCCESS == app_exit_code) - { - Utils::rawPairsToStl(outgoing_headers, response.headers, response.headers_count); - } + server_response response { + clientSocket.get_handle(), 0, nullptr + }; - try - { - app_sets->application_clear(response.headers, response.headers_count); - } - catch (...) {} + // Попытаться + try + { + // Запустить приложение + rp.app_exit_code = appSets.application_call(&request, &response); + } + catch (...) + { + rp.app_exit_code = EXIT_FAILURE; + } - Utils::destroyRawPairs(raw_pair_params, incoming_params.size() ); - Utils::destroyRawPairs(raw_pair_headers, incoming_headers.size() ); - Utils::destroyRawPairs(raw_pair_data, incoming_data.size() ); - Utils::destroyRawFilesInfo(raw_fileinfo_files, incoming_files.size() ); - } - else - { - // HTTP 404 Not Found - this->sendStatus(clientSocket, timeout, 404); - } - } - else - { - // HTTP 400 Bad Request - this->sendStatus(clientSocket, timeout, 400); - } + if (EXIT_SUCCESS == rp.app_exit_code) + { + Utils::rawPairsToStl(rp.outgoing_headers, response.headers, response.headers_count); + } + + // Очистить заголовки сформированные приложением + try + { + appSets.application_clear(response.headers, response.headers_count); + } + catch (...) {} + + Utils::destroyRawPairs(raw_pair_params, rp.incoming_params.size() ); + Utils::destroyRawPairs(raw_pair_headers, rp.incoming_headers.size() ); + Utils::destroyRawPairs(raw_pair_data, rp.incoming_data.size() ); + Utils::destroyRawFilesInfo(raw_fileinfo_files, rp.incoming_files.size() ); + } + + int Server::getRequestData(Socket clientSocket, std::string &str_buf, const ServerApplicationSettings &appSets, struct request_parameters &rp) const + { + // Определить вариант данных запроса (заодно проверить, есть ли данные) + auto it = rp.incoming_headers.find("Content-Type"); + + if (rp.incoming_headers.cend() == it) + { + return 0; + } + + // Параметры + std::unordered_map content_params; + + // Получить значение заголовка + const std::string &header_value = it->second; + + // Определить, содержит ли тип данных запроса дополнительные параметры + size_t delimiter = header_value.find(';'); + + std::string data_variant_name; // Название варианта данных запроса + + // Если есть дополнительные параметры - извлекаем их + if (std::string::npos != delimiter) + { + data_variant_name = header_value.substr(0, delimiter); + Utils::trim(data_variant_name); + + for (size_t str_param_cur = delimiter + 1, str_param_end = 0; std::string::npos != str_param_end; str_param_cur = str_param_end + 1) + { + str_param_end = header_value.find(';', str_param_cur); + delimiter = header_value.find('=', str_param_cur); + + if (delimiter >= str_param_end) + { + std::string param_name = header_value.substr(str_param_cur, std::string::npos != str_param_end ? str_param_end - str_param_cur : std::string::npos); + Utils::trim(param_name); + content_params.emplace(std::move(param_name), ""); } else { - // HTTP 400 Bad Request - this->sendStatus(clientSocket, timeout, 400); + std::string param_name = header_value.substr(str_param_cur, delimiter - str_param_cur); + Utils::trim(param_name); + + ++delimiter; + + std::string param_value = header_value.substr(delimiter, std::string::npos != str_param_end ? str_param_end - delimiter : std::string::npos); + Utils::trim(param_value); + + content_params.emplace(std::move(param_name), std::move(param_value) ); } } - else // Если запрос пустой - { - // HTTP 400 Bad Request - this->sendStatus(clientSocket, timeout, 400); + } + else + { + data_variant_name = header_value; + } - break; - } + // Поиск варианта данных по имени типа + auto variant = this->variants.find(data_variant_name); + + // Если сервер не поддерживает формат полученных данных + if (this->variants.cend() == variant) + { + // HTTP 400 Bad Request + return 400; + } + + DataVariantAbstract *data_variant = variant->second; + + // Получить длину запроса в байтах + size_t data_length = 0; - for (auto it : incoming_files) + auto it_len = rp.incoming_headers.find("Content-Length"); + + if (rp.incoming_headers.cend() != it_len) + { + data_length = std::strtoull(it_len->second.c_str(), nullptr, 10); + } + + // Если размер запроса превышает лимит (если лимит был установлен) + if (data_length > appSets.request_max_size && 0 != appSets.request_max_size) + { + // HTTP 413 Request Entity Too Large + return 413; + } + + // Сколько осталось получить данных + size_t left_bytes = 0; + + std::string data_buf; + + if (data_length >= str_buf.length() ) + { + left_bytes = data_length - str_buf.length(); + + data_buf.swap(str_buf); + } + else + { + data_buf.assign(str_buf.cbegin(), str_buf.cbegin() + data_length); + str_buf.erase(str_buf.begin(), str_buf.begin() + data_length); + } + + // Разобрать данные на составляющие + if (false == data_variant->parse(clientSocket, data_buf, left_bytes, content_params, rp) ) + { + for (auto &it : rp.incoming_files) { remove(it.second.getName().c_str() ); } - connection_keep_alive = false; + // HTTP 400 Bad Request + return 400; + } - if (EXIT_SUCCESS == app_exit_code) - { - auto it_in_connection = incoming_headers.find("Connection"); - auto it_out_connection = outgoing_headers.find("Connection"); + if (false == data_buf.empty() ) + { + str_buf.swap(data_buf); + } - if (incoming_headers.cend() != it_in_connection && outgoing_headers.cend() != it_out_connection) - { - std::locale loc; + return 0; + } - std::string connection_in = it_in_connection->second; - Utils::tolower(connection_in, loc); + const ServerApplicationSettings *Server::getApplicationSettings(const struct request_parameters &rp) const + { + // Получить доменное имя (или адрес) назначения запроса + auto it_host = rp.incoming_headers.find("Host"); - std::string connection_out = it_out_connection->second; - Utils::tolower(connection_out, loc); + // Если имя задано - продолжить обработку запроса + if (rp.incoming_headers.cend() != it_host) + { + // Поиск разделителя, за которым помещается номер порта, если указан + size_t delimiter = it_host->second.find(':'); - if ("keep-alive" == connection_in) - { - if ("keep-alive" == connection_out) - { - --keep_alive_count; + // Получить имя (или адрес) + const std::string host = it_host->second.substr(0, delimiter); - connection_keep_alive = (0 < keep_alive_count); - } - } - else if ("upgrade" == connection_in) - { - if ("upgrade" == connection_out) - { - connection_upgrade = true; - } - } - } + // Получить номер порта + const int port = (std::string::npos != delimiter) ? std::strtol(it_host->second.substr(delimiter + 1).c_str(), nullptr, 10) : 80; - auto it_x_sendfile = outgoing_headers.find("X-Sendfile"); + // Поиск настроек приложения по имени + const ServerApplicationSettings *app_sets = this->apps_tree.find(host); - if (outgoing_headers.cend() != it_x_sendfile) - { - const std::string connection_header = connection_keep_alive ? "Connection: Keep-Alive\r\nKeep-Alive: timeout=5; max=" + std::to_string(keep_alive_count) + "\r\n" : "Connection: Close\r\n"; + // Если приложение найдено + if (app_sets && app_sets->port == port) + { + return app_sets; + } + } + + return nullptr; + } - const bool headers_only = ("head" == method); + void Server::xSendfile(Socket clientSocket, struct request_parameters &rp) const + { + auto it_x_sendfile = rp.outgoing_headers.find("X-Sendfile"); - this->transferFile(clientSocket, timeout, it_x_sendfile->second, incoming_headers, outgoing_headers, connection_header, headers_only); - } - } + if (rp.outgoing_headers.cend() != it_x_sendfile) + { + const std::string connection_header = isConnectionKeepAlive(rp) ? "Connection: Keep-Alive\r\nKeep-Alive: timeout=5; max=" + std::to_string(rp.keep_alive_count) + "\r\n" : "Connection: Close\r\n"; + + const bool headers_only = ("head" == rp.method); + + this->transferFile(clientSocket, it_x_sendfile->second, connection_header, headers_only, rp); } - while (connection_keep_alive); + } + + void Server::getConnectionParams(struct request_parameters &rp) + { + rp.connection_params = CONNECTION_CLOSED; - if (false == connection_upgrade) + auto it_in_connection = rp.incoming_headers.find("Connection"); + auto it_out_connection = rp.outgoing_headers.find("Connection"); + + if (rp.incoming_headers.cend() != it_in_connection && rp.outgoing_headers.cend() != it_out_connection) { - // Wait for send all data to client - clientSocket.nonblock_send_sync(); + std::locale loc; - clientSocket.shutdown(); - clientSocket.close(); + std::string connection_in = it_in_connection->second; + Utils::tolower(connection_in, loc); + + std::string connection_out = it_out_connection->second; + Utils::tolower(connection_out, loc); + + if ("keep-alive" == connection_in) + { + if ("keep-alive" == connection_out) + { + --rp.keep_alive_count; + + if (0 < rp.keep_alive_count) + { + rp.connection_params |= CONNECTION_KEEP_ALIVE; + } + } + } + else if ("upgrade" == connection_in) + { + if ("upgrade" == connection_out) + { + rp.connection_params |= CONNECTION_UPGRADE; + } + } } + } + + bool Server::isConnectionKeepAlive(const struct request_parameters &rp) + { + return (rp.connection_params & CONNECTION_KEEP_ALIVE) > 0; + } - return app_exit_code; + bool Server::isConnectionUpgrade(const struct request_parameters &rp) + { + return (rp.connection_params & CONNECTION_UPGRADE) > 0; } + /** + * Метод для обработки запросов (запускается в отдельном потоке) + * извлекает сокет клиенты из очереди и передаёт его на обслуживание + */ void Server::threadRequestCycle(std::queue &sockets) const { while (true) @@ -915,7 +980,7 @@ namespace HttpServer } /** - * Цикл обработки очереди запросов + * Цикл управления количеством рабочих потоков */ int Server::cycleQueue(std::queue &sockets) { @@ -1016,9 +1081,9 @@ namespace HttpServer } - void Server::addDataVariant(DataVariantAbstract *postVariant) + void Server::addDataVariant(DataVariantAbstract *dataVariant) { - this->variants.emplace(postVariant->getName(), postVariant); + this->variants.emplace(dataVariant->getName(), dataVariant); } bool Server::updateModule(Module &module, std::unordered_set &applications, const size_t moduleIndex) @@ -1490,7 +1555,7 @@ namespace HttpServer int Server::command_start(const int argc, const char *argv[]) { - std::string pid_file_name = "httpserver.pid"; + const std::string pid_file_name = "httpserver.pid"; // TODO: // Проверить, существует ли файл и открыт ли он уже на запись - значит сервер уже запущен - нужно завершить текущий (this) процесс diff --git a/httpserver/Server.h b/httpserver/Server.h index 9301abe..ec8caed 100644 --- a/httpserver/Server.h +++ b/httpserver/Server.h @@ -1,16 +1,5 @@ #pragma once -#include - -#include - -#include -#include -#include -#include -#include -#include - #include "SocketList.h" #include "DataVariantAbstract.h" #include "ServerApplicationsTree.h" @@ -18,6 +7,13 @@ #include "Module.h" #include "Event.h" +#include +#include +#include +#include +#include +#include + namespace HttpServer { class Server @@ -47,24 +43,67 @@ namespace HttpServer sig_atomic_t process_flag; sig_atomic_t restart_flag; + protected: + static const int CONNECTION_CLOSED = 0; + static const int CONNECTION_KEEP_ALIVE = 1; + static const int CONNECTION_UPGRADE = 2; + protected: int cycleQueue(std::queue &); - void sendStatus(const Socket &, const std::chrono::milliseconds &, const size_t) const; + int threadRequestProc(Socket) const; + + static bool getRequest(Socket clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp); + + int getRequestHeaders(std::string &str_buf, struct request_parameters &rp) const; + + static void runApplication(Socket clientSocket, const ServerApplicationSettings &appSets, struct request_parameters &rp); + + int getRequestData(Socket clientSocket, std::string &str_buf, const ServerApplicationSettings &appSets, struct request_parameters &rp) const; + + const ServerApplicationSettings *getApplicationSettings(const struct request_parameters &rp) const; + + static void getConnectionParams(struct request_parameters &rp); + + void xSendfile(Socket clientSocket, struct request_parameters &rp) const; + + static bool isConnectionKeepAlive(const struct request_parameters &rp); + static bool isConnectionUpgrade(const struct request_parameters &rp); + void threadRequestCycle(std::queue &) const; - int transferFilePart(const Socket &, const std::chrono::milliseconds &, const std::string &, const time_t, const size_t, const std::string &, const std::string &, const std::string &, const bool) const; - int transferFile( + std::string getMimeTypeByFileName(const std::string &fileName) const; + + std::vector > getRanges( + const std::string &rangeHeader, + const size_t posSymEqual, + const size_t fileSize, + std::string &resultRangeHeader, + size_t &contentLength + ) const; + + int transferFilePart( const Socket &, const std::chrono::milliseconds &, const std::string &, - const std::unordered_map &, - const std::unordered_map &, + const time_t, + const size_t, + const std::string &, + const std::string &, const std::string &, const bool ) const; - bool parseIncomingVars(std::unordered_multimap &, const std::string &) const; + int transferFile( + const Socket &, + const std::string &, + const std::string &, + const bool, + struct request_parameters &rp + ) const; + + static bool parseIncomingVars(std::unordered_multimap &, const std::string &); + static void sendStatus(const Socket &, const std::chrono::milliseconds &, const size_t); bool init(); int run(); @@ -73,7 +112,7 @@ namespace HttpServer System::native_processid_type getPidFromFile() const; void updateModules(); - bool updateModule(Module &, std::unordered_set &, const size_t); + bool updateModule(Module &, std::unordered_set &, const size_t); private: void addDataVariant(DataVariantAbstract *); diff --git a/httpserver/ServerApplicationsTree.cpp b/httpserver/ServerApplicationsTree.cpp index 4aa041f..668c72c 100644 --- a/httpserver/ServerApplicationsTree.cpp +++ b/httpserver/ServerApplicationsTree.cpp @@ -5,7 +5,7 @@ namespace HttpServer { ServerApplicationsTree::ServerApplicationsTree(): app_sets(nullptr) { - + } ServerApplicationsTree::~ServerApplicationsTree() @@ -27,7 +27,7 @@ namespace HttpServer ServerApplicationsTree *sub; - if (list.cend() != it) + if (list.cend() != it) { sub = it->second; } @@ -79,7 +79,7 @@ namespace HttpServer addApplication(name_parts, sets); } - ServerApplicationSettings *ServerApplicationsTree::find(std::vector &nameParts) const + const ServerApplicationSettings *ServerApplicationsTree::find(std::vector &nameParts) const { if (nameParts.empty() ) { @@ -111,7 +111,7 @@ namespace HttpServer } } - ServerApplicationSettings *ServerApplicationsTree::find(const std::string &name) const + const ServerApplicationSettings *ServerApplicationsTree::find(const std::string &name) const { std::vector name_parts; @@ -142,14 +142,16 @@ namespace HttpServer void ServerApplicationsTree::collectApplicationSettings(std::unordered_set &set) const { - for (auto l : list) + for (auto &node : list) { - if (nullptr != l.second->app_sets) + ServerApplicationsTree *tree = node.second; + + if (nullptr != tree->app_sets) { - set.emplace(l.second->app_sets); + set.emplace(tree->app_sets); } - l.second->collectApplicationSettings(set); + tree->collectApplicationSettings(set); } } diff --git a/httpserver/ServerApplicationsTree.h b/httpserver/ServerApplicationsTree.h index f420d95..3efdb70 100644 --- a/httpserver/ServerApplicationsTree.h +++ b/httpserver/ServerApplicationsTree.h @@ -27,8 +27,8 @@ namespace HttpServer void addApplication(const std::string &, ServerApplicationSettings *); void addApplication(std::vector &, ServerApplicationSettings *); - ServerApplicationSettings *find(const std::string &) const; - ServerApplicationSettings *find(std::vector &) const; + const ServerApplicationSettings *find(const std::string &) const; + const ServerApplicationSettings *find(std::vector &) const; void collectApplicationSettings(std::unordered_set &) const; diff --git a/httpserver/SocketList.cpp b/httpserver/SocketList.cpp index e8dc976..6e17842 100644 --- a/httpserver/SocketList.cpp +++ b/httpserver/SocketList.cpp @@ -73,7 +73,7 @@ namespace HttpServer #ifdef WIN32 WSAPOLLFD event = { sock.get_handle(), - POLLRDNORM | POLLHUP, + POLLRDNORM, 0 }; @@ -86,7 +86,7 @@ namespace HttpServer reinterpret_cast(sock.get_handle() ) }; - size_t result = ::epoll_ctl(this->obj_list, EPOLL_CTL_ADD, sock.get_handle(), &event); + const size_t result = ::epoll_ctl(this->obj_list, EPOLL_CTL_ADD, sock.get_handle(), &event); if (std::numeric_limits::max() == result) { @@ -120,7 +120,7 @@ namespace HttpServer return false; #elif POSIX - size_t result = ::epoll_ctl(this->obj_list, EPOLL_CTL_DEL, sock.get_handle(), nullptr); + const size_t result = ::epoll_ctl(this->obj_list, EPOLL_CTL_DEL, sock.get_handle(), nullptr); if (std::numeric_limits::max() == result) { @@ -140,7 +140,7 @@ namespace HttpServer if (is_created() ) { #ifdef WIN32 - size_t count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), ~0); + const size_t count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), ~0); if (SOCKET_ERROR == count) { @@ -170,7 +170,7 @@ namespace HttpServer return false == sockets.empty(); #elif POSIX - size_t count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); + const size_t count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); if (std::numeric_limits::max() == count) { @@ -215,7 +215,7 @@ namespace HttpServer } #ifdef WIN32 - size_t count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), ~0); + const size_t count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), ~0); if (SOCKET_ERROR == count) { @@ -238,7 +238,7 @@ namespace HttpServer return false == sockets.empty(); #elif POSIX - size_t count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); + const size_t count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); if (std::numeric_limits::max() == count) { diff --git a/httpserver/System.cpp b/httpserver/System.cpp index f5491ca..446789c 100644 --- a/httpserver/System.cpp +++ b/httpserver/System.cpp @@ -61,7 +61,7 @@ namespace System #ifdef WIN32 std::vector buf(MAX_PATH + 1); - size_t len = ::GetTempPath(MAX_PATH + 1, buf.data() ); + const size_t len = ::GetTempPath(MAX_PATH + 1, buf.data() ); return std::string(buf.cbegin(), buf.cbegin() + len); #elif POSIX diff --git a/httpserver/Utils.cpp b/httpserver/Utils.cpp index 500115c..6e3e9ec 100644 --- a/httpserver/Utils.cpp +++ b/httpserver/Utils.cpp @@ -8,7 +8,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) { @@ -20,7 +20,7 @@ namespace Utils char *stlStringToPChar(const std::string &str) { - size_t length = str.length(); + const size_t length = str.length(); char *s = nullptr; if (length) @@ -226,7 +226,7 @@ namespace Utils 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]; diff --git a/httpserver/Utils.h b/httpserver/Utils.h index d19c3ef..2afdbca 100644 --- a/httpserver/Utils.h +++ b/httpserver/Utils.h @@ -77,7 +77,7 @@ namespace Utils time_t stringTimeToTimestamp(const std::string &); - std::string getDatetimeStringValue(const ::time_t tTime = ~0, const bool isGmtTime = false); + std::string getDatetimeAsString(const ::time_t tTime = ~0, const bool isGmtTime = false); size_t getNumberLength(const size_t number); From e53e45b6dbd962f6e0154409bad0a268d3093d05 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Fri, 13 Nov 2015 23:11:41 +0300 Subject: [PATCH 07/50] Reorganization of the directory structure Added project builds for Visual Studio Added missing code in win32 branch Successful build project in Visual Studio --- httpserver.pro | 66 ---- httpserver.sln | 195 ------------ httpserver.userprefs | 39 --- httpserver/.gitignore | 2 - httpserver/httpserver.cproj | 88 ------ projects/msvs/httpserver.sln | 28 ++ projects/msvs/httpserver.v12.suo | Bin 0 -> 150528 bytes projects/msvs/httpserver.vcxproj | 292 ++++++++++++++++++ projects/msvs/httpserver.vcxproj.filters | 139 +++++++++ projects/msvs/httpserver.vcxproj.user | 6 + .../qt-creator/deployment.pri | 0 projects/qt-creator/httpserver.pro | 70 +++++ .../qt-creator/httpserver.pro.user | 32 +- apps.conf => samples/apps.conf | 0 main.conf => samples/main.conf | 0 mimes.conf => samples/mimes.conf | 0 {httpserver => src}/ConfigParser.cpp | 19 +- {httpserver => src}/ConfigParser.h | 0 {httpserver => src}/DataVariantAbstract.h | 0 .../DataVariantFormUrlencoded.cpp | 0 .../DataVariantFormUrlencoded.h | 0 .../DataVariantMultipartFormData.cpp | 2 +- .../DataVariantMultipartFormData.h | 0 {httpserver => src}/DataVariantTextPlain.cpp | 0 {httpserver => src}/DataVariantTextPlain.h | 0 {httpserver => src}/Event.cpp | 0 {httpserver => src}/Event.h | 0 {httpserver => src}/FileIncoming.cpp | 2 +- {httpserver => src}/FileIncoming.h | 0 {httpserver => src}/Main.cpp | 3 - {httpserver => src}/Main.h | 3 - {httpserver => src}/Module.cpp | 0 {httpserver => src}/Module.h | 0 {httpserver => src}/RawData.h | 0 {httpserver => src}/RequestParameters.cpp | 0 {httpserver => src}/RequestParameters.h | 0 {httpserver => src}/Server.cpp | 25 +- {httpserver => src}/Server.h | 0 .../ServerApplicationDefaultSettings.h | 0 .../ServerApplicationSettings.h | 0 .../ServerApplicationsTree.cpp | 4 +- {httpserver => src}/ServerApplicationsTree.h | 0 {httpserver => src}/ServerRequest.h | 0 {httpserver => src}/ServerResponse.h | 0 {httpserver => src}/SignalsHandles.cpp | 4 + {httpserver => src}/SignalsHandles.h | 5 +- {httpserver => src}/Socket.cpp | 8 +- {httpserver => src}/Socket.h | 0 {httpserver => src}/SocketList.cpp | 49 +-- {httpserver => src}/SocketList.h | 15 +- {httpserver => src}/System.cpp | 44 ++- {httpserver => src}/System.h | 4 +- {httpserver => src}/Utils.cpp | 122 ++------ {httpserver => src}/Utils.h | 11 +- 54 files changed, 699 insertions(+), 578 deletions(-) delete mode 100644 httpserver.pro delete mode 100644 httpserver.sln delete mode 100644 httpserver.userprefs delete mode 100644 httpserver/.gitignore delete mode 100644 httpserver/httpserver.cproj create mode 100644 projects/msvs/httpserver.sln create mode 100644 projects/msvs/httpserver.v12.suo create mode 100644 projects/msvs/httpserver.vcxproj create mode 100644 projects/msvs/httpserver.vcxproj.filters create mode 100644 projects/msvs/httpserver.vcxproj.user rename deployment.pri => projects/qt-creator/deployment.pri (100%) create mode 100644 projects/qt-creator/httpserver.pro rename httpserver.pro.user => projects/qt-creator/httpserver.pro.user (95%) rename apps.conf => samples/apps.conf (100%) rename main.conf => samples/main.conf (100%) rename mimes.conf => samples/mimes.conf (100%) rename {httpserver => src}/ConfigParser.cpp (96%) rename {httpserver => src}/ConfigParser.h (100%) rename {httpserver => src}/DataVariantAbstract.h (100%) rename {httpserver => src}/DataVariantFormUrlencoded.cpp (100%) rename {httpserver => src}/DataVariantFormUrlencoded.h (100%) rename {httpserver => src}/DataVariantMultipartFormData.cpp (99%) rename {httpserver => src}/DataVariantMultipartFormData.h (100%) rename {httpserver => src}/DataVariantTextPlain.cpp (100%) rename {httpserver => src}/DataVariantTextPlain.h (100%) rename {httpserver => src}/Event.cpp (100%) rename {httpserver => src}/Event.h (100%) rename {httpserver => src}/FileIncoming.cpp (95%) rename {httpserver => src}/FileIncoming.h (100%) rename {httpserver => src}/Main.cpp (95%) rename {httpserver => src}/Main.h (52%) rename {httpserver => src}/Module.cpp (100%) rename {httpserver => src}/Module.h (100%) rename {httpserver => src}/RawData.h (100%) rename {httpserver => src}/RequestParameters.cpp (100%) rename {httpserver => src}/RequestParameters.h (100%) rename {httpserver => src}/Server.cpp (98%) rename {httpserver => src}/Server.h (100%) rename {httpserver => src}/ServerApplicationDefaultSettings.h (100%) rename {httpserver => src}/ServerApplicationSettings.h (100%) rename {httpserver => src}/ServerApplicationsTree.cpp (96%) rename {httpserver => src}/ServerApplicationsTree.h (100%) rename {httpserver => src}/ServerRequest.h (100%) rename {httpserver => src}/ServerResponse.h (100%) rename {httpserver => src}/SignalsHandles.cpp (97%) rename {httpserver => src}/SignalsHandles.h (77%) rename {httpserver => src}/Socket.cpp (97%) rename {httpserver => src}/Socket.h (100%) rename {httpserver => src}/SocketList.cpp (81%) rename {httpserver => src}/SocketList.h (66%) rename {httpserver => src}/System.cpp (71%) rename {httpserver => src}/System.h (95%) rename {httpserver => src}/Utils.cpp (70%) rename {httpserver => src}/Utils.h (69%) diff --git a/httpserver.pro b/httpserver.pro deleted file mode 100644 index a43e9af..0000000 --- a/httpserver.pro +++ /dev/null @@ -1,66 +0,0 @@ -TEMPLATE = app -CONFIG += console -CONFIG -= app_bundle -CONFIG -= qt - -DEFINES += POSIX - -CONFIG(debug, debug|release):DEFINES += DEBUG - -QMAKE_CXXFLAGS += -std=c++1y - -CONFIG(release, debug|release) -{ - QMAKE_CFLAGS_RELEASE -= -O - QMAKE_CFLAGS_RELEASE -= -O1 - QMAKE_CFLAGS_RELEASE *= -O2 -# QMAKE_CFLAGS_RELEASE *= -O3 -} - -LIBS += -ldl -pthread - -SOURCES += \ - httpserver/Main.cpp \ - httpserver/DataVariantFormUrlencoded.cpp \ - httpserver/DataVariantMultipartFormData.cpp \ - httpserver/DataVariantTextPlain.cpp \ - httpserver/Event.cpp \ - httpserver/FileIncoming.cpp \ - httpserver/Module.cpp \ - httpserver/Server.cpp \ - httpserver/ServerApplicationsTree.cpp \ - httpserver/SignalsHandles.cpp \ - httpserver/Socket.cpp \ - httpserver/SocketList.cpp \ - httpserver/System.cpp \ - httpserver/Utils.cpp \ - httpserver/ConfigParser.cpp \ - httpserver/RequestParameters.cpp - -include(deployment.pri) -qtcAddDeployment() - -HEADERS += \ - httpserver/DataVariantAbstract.h \ - httpserver/DataVariantFormUrlencoded.h \ - httpserver/DataVariantMultipartFormData.h \ - httpserver/DataVariantTextPlain.h \ - httpserver/Event.h \ - httpserver/FileIncoming.h \ - httpserver/Main.h \ - httpserver/Module.h \ - httpserver/RawData.h \ - httpserver/Server.h \ - httpserver/ServerApplicationDefaultSettings.h \ - httpserver/ServerApplicationSettings.h \ - httpserver/ServerApplicationsTree.h \ - httpserver/ServerRequest.h \ - httpserver/ServerResponse.h \ - httpserver/SignalsHandles.h \ - httpserver/Socket.h \ - httpserver/SocketList.h \ - httpserver/System.h \ - httpserver/Utils.h \ - httpserver/ConfigParser.h \ - httpserver/RequestParameters.h - diff --git a/httpserver.sln b/httpserver.sln deleted file mode 100644 index a73b4ea..0000000 --- a/httpserver.sln +++ /dev/null @@ -1,195 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{2857B73E-F847-4B02-9238-064979017E93}") = "httpserver", "httpserver\httpserver.cproj", "{81D9D9DB-4DE0-40E5-9CC0-6643C2695370}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {81D9D9DB-4DE0-40E5-9CC0-6643C2695370}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {81D9D9DB-4DE0-40E5-9CC0-6643C2695370}.Debug|Any CPU.Build.0 = Debug|Any CPU - {81D9D9DB-4DE0-40E5-9CC0-6643C2695370}.Release|Any CPU.ActiveCfg = Release|Any CPU - {81D9D9DB-4DE0-40E5-9CC0-6643C2695370}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - StartupItem = httpserver\httpserver.cproj - Policies = $0 - $0.TextStylePolicy = $1 - $1.inheritsSet = null - $1.scope = text/x-c++src - $0.TextStylePolicy = $2 - $2.FileWidth = 120 - $2.TabsToSpaces = False - $2.EolMarker = Unix - $2.inheritsSet = VisualStudio - $2.inheritsScope = text/plain - $2.scope = text/plain - $0.TextStylePolicy = $3 - $3.inheritsSet = null - $3.scope = text/x-chdr - $0.StandardHeader = $4 - $4.Text = - $4.IncludeInNewFiles = True - $0.NameConventionPolicy = $5 - $5.Rules = $6 - $6.NamingRule = $7 - $7.Name = Namespaces - $7.AffectedEntity = Namespace - $7.VisibilityMask = VisibilityMask - $7.NamingStyle = PascalCase - $7.IncludeInstanceMembers = True - $7.IncludeStaticEntities = True - $6.NamingRule = $8 - $8.Name = Types - $8.AffectedEntity = Class, Struct, Enum, Delegate - $8.VisibilityMask = VisibilityMask - $8.NamingStyle = PascalCase - $8.IncludeInstanceMembers = True - $8.IncludeStaticEntities = True - $6.NamingRule = $9 - $9.Name = Interfaces - $9.RequiredPrefixes = $10 - $10.String = I - $9.AffectedEntity = Interface - $9.VisibilityMask = VisibilityMask - $9.NamingStyle = PascalCase - $9.IncludeInstanceMembers = True - $9.IncludeStaticEntities = True - $6.NamingRule = $11 - $11.Name = Attributes - $11.RequiredSuffixes = $12 - $12.String = Attribute - $11.AffectedEntity = CustomAttributes - $11.VisibilityMask = VisibilityMask - $11.NamingStyle = PascalCase - $11.IncludeInstanceMembers = True - $11.IncludeStaticEntities = True - $6.NamingRule = $13 - $13.Name = Event Arguments - $13.RequiredSuffixes = $14 - $14.String = EventArgs - $13.AffectedEntity = CustomEventArgs - $13.VisibilityMask = VisibilityMask - $13.NamingStyle = PascalCase - $13.IncludeInstanceMembers = True - $13.IncludeStaticEntities = True - $6.NamingRule = $15 - $15.Name = Exceptions - $15.RequiredSuffixes = $16 - $16.String = Exception - $15.AffectedEntity = CustomExceptions - $15.VisibilityMask = VisibilityMask - $15.NamingStyle = PascalCase - $15.IncludeInstanceMembers = True - $15.IncludeStaticEntities = True - $6.NamingRule = $17 - $17.Name = Methods - $17.AffectedEntity = Methods - $17.VisibilityMask = VisibilityMask - $17.NamingStyle = PascalCase - $17.IncludeInstanceMembers = True - $17.IncludeStaticEntities = True - $6.NamingRule = $18 - $18.Name = Static Readonly Fields - $18.AffectedEntity = ReadonlyField - $18.VisibilityMask = Internal, Protected, Public - $18.NamingStyle = PascalCase - $18.IncludeInstanceMembers = False - $18.IncludeStaticEntities = True - $6.NamingRule = $19 - $19.Name = Fields (Non Private) - $19.AffectedEntity = Field - $19.VisibilityMask = Internal, Protected, Public - $19.NamingStyle = PascalCase - $19.IncludeInstanceMembers = True - $19.IncludeStaticEntities = True - $6.NamingRule = $20 - $20.Name = ReadOnly Fields (Non Private) - $20.AffectedEntity = ReadonlyField - $20.VisibilityMask = Internal, Protected, Public - $20.NamingStyle = PascalCase - $20.IncludeInstanceMembers = True - $20.IncludeStaticEntities = False - $6.NamingRule = $21 - $21.Name = Fields (Private) - $21.AllowedPrefixes = $22 - $22.String = _ - $22.String = m_ - $21.AffectedEntity = Field, ReadonlyField - $21.VisibilityMask = Private - $21.NamingStyle = CamelCase - $21.IncludeInstanceMembers = True - $21.IncludeStaticEntities = False - $6.NamingRule = $23 - $23.Name = Static Fields (Private) - $23.AffectedEntity = Field - $23.VisibilityMask = Private - $23.NamingStyle = CamelCase - $23.IncludeInstanceMembers = False - $23.IncludeStaticEntities = True - $6.NamingRule = $24 - $24.Name = ReadOnly Fields (Private) - $24.AllowedPrefixes = $25 - $25.String = _ - $25.String = m_ - $24.AffectedEntity = ReadonlyField - $24.VisibilityMask = Private - $24.NamingStyle = CamelCase - $24.IncludeInstanceMembers = True - $24.IncludeStaticEntities = False - $6.NamingRule = $26 - $26.Name = Constant Fields - $26.AffectedEntity = ConstantField - $26.VisibilityMask = VisibilityMask - $26.NamingStyle = PascalCase - $26.IncludeInstanceMembers = True - $26.IncludeStaticEntities = True - $6.NamingRule = $27 - $27.Name = Properties - $27.AffectedEntity = Property - $27.VisibilityMask = VisibilityMask - $27.NamingStyle = PascalCase - $27.IncludeInstanceMembers = True - $27.IncludeStaticEntities = True - $6.NamingRule = $28 - $28.Name = Events - $28.AffectedEntity = Event - $28.VisibilityMask = VisibilityMask - $28.NamingStyle = PascalCase - $28.IncludeInstanceMembers = True - $28.IncludeStaticEntities = True - $6.NamingRule = $29 - $29.Name = Enum Members - $29.AffectedEntity = EnumMember - $29.VisibilityMask = VisibilityMask - $29.NamingStyle = PascalCase - $29.IncludeInstanceMembers = True - $29.IncludeStaticEntities = True - $6.NamingRule = $30 - $30.Name = Parameters - $30.AffectedEntity = Parameter - $30.VisibilityMask = VisibilityMask - $30.NamingStyle = CamelCase - $30.IncludeInstanceMembers = True - $30.IncludeStaticEntities = True - $6.NamingRule = $31 - $31.Name = Type Parameters - $31.RequiredPrefixes = $32 - $32.String = T - $31.AffectedEntity = TypeParameter - $31.VisibilityMask = VisibilityMask - $31.NamingStyle = PascalCase - $31.IncludeInstanceMembers = True - $31.IncludeStaticEntities = True - $0.VersionControlPolicy = $33 - $33.inheritsSet = Mono - $0.ChangeLogPolicy = $34 - $34.UpdateMode = None - $34.MessageStyle = $35 - $35.LineAlign = 0 - $34.inheritsSet = Mono - EndGlobalSection -EndGlobal diff --git a/httpserver.userprefs b/httpserver.userprefs deleted file mode 100644 index bb5c0ba..0000000 --- a/httpserver.userprefs +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/httpserver/.gitignore b/httpserver/.gitignore deleted file mode 100644 index 1746e32..0000000 --- a/httpserver/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -bin -obj diff --git a/httpserver/httpserver.cproj b/httpserver/httpserver.cproj deleted file mode 100644 index d579a4d..0000000 --- a/httpserver/httpserver.cproj +++ /dev/null @@ -1,88 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {81D9D9DB-4DE0-40E5-9CC0-6643C2695370} - Bin - CPP - - - - - - true - bin\Debug - DEBUG MONODEVELOP POSIX - . - httpserver - Bin - -std=c++11 - -lpthread -ldl - --start - All - - - bin\Release - MONODEVELOP POSIX - . - 3 - httpserver - Bin - -std=c++11 - -lpthread -ldl - --start - All - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/projects/msvs/httpserver.sln b/projects/msvs/httpserver.sln new file mode 100644 index 0000000..08ef7dc --- /dev/null +++ b/projects/msvs/httpserver.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}") = "httpserver", "httpserver.vcxproj", "{A7023B84-DA18-3E3E-A9AE-B87F45CAC37F}" +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 + {A7023B84-DA18-3E3E-A9AE-B87F45CAC37F}.Debug|Win32.ActiveCfg = Debug|Win32 + {A7023B84-DA18-3E3E-A9AE-B87F45CAC37F}.Debug|Win32.Build.0 = Debug|Win32 + {A7023B84-DA18-3E3E-A9AE-B87F45CAC37F}.Debug|x64.ActiveCfg = Debug|x64 + {A7023B84-DA18-3E3E-A9AE-B87F45CAC37F}.Debug|x64.Build.0 = Debug|x64 + {A7023B84-DA18-3E3E-A9AE-B87F45CAC37F}.Release|Win32.ActiveCfg = Release|Win32 + {A7023B84-DA18-3E3E-A9AE-B87F45CAC37F}.Release|Win32.Build.0 = Release|Win32 + {A7023B84-DA18-3E3E-A9AE-B87F45CAC37F}.Release|x64.ActiveCfg = Release|x64 + {A7023B84-DA18-3E3E-A9AE-B87F45CAC37F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/projects/msvs/httpserver.v12.suo b/projects/msvs/httpserver.v12.suo new file mode 100644 index 0000000000000000000000000000000000000000..b99d32d0d7643c634b09b5ce85c5ccb1046e1f2e GIT binary patch literal 150528 zcmeHQ37lS4b^pS?C_5NHAP{!QFv(;kvdknC0we@7AqhAVCNqwY64T1^WNL`<`HJgBVPIVu9^}zt1=SaMkbL@@R9|3$6V7{&Y z-;Vc=02~S6^p67^4LAlc9&jw+IKc6M696XyP6C_^I0bMjU;>~4a2lWyFcB~b&;;N- zkycXy(*V-}GXSRpW&+*;I0JAd;4Hw|fM!4oU>0CDpcOC&a1LND;9S6Yfb#+K0P_JC z02Tl)1Y87I2xtQ=0$dDO3|InK3b+JtDd3%ecEGy;mjRXmE(de~mIFEgU4U-D3cyOh zD!^*M8o(8R9zZXk56}-709*+e1PlR&0c!#40P6viBueupz*T_FfGq&>|22TEfROV4 zi(`(yiSqw3j!g!@QH1=H7jl&UG0Nf9$se!#X8yyGm;ApK=OP}_Nk{m%Gd`!>@(|qj z#B<89$T;7BTlw9Um$Ge0+=bJ<9)m0G{(6Jnn9N#_zs))CUDHb&*fU zdEW)kX-D{6fP5j(`A9z72SB?(8QLFk0DwGl5P&w}5CD0H-zUEuR(@WK{?D)Av|MPv(|9md`pU*}A^SS7MJ{SGZ z=hXjvl;ihd{&$r9r_HzLzZUyXn{Us*ZU0GU0os2)_t}5>4(-1@k3Z%;|2#jB#qfN_ zZMVYR@I%N&)gSP`$B>7P1n_*-{E|K=eHI>-?B8s7Kk_~E?d1PsF+RtYBl(TwJBQ<~ zn_e~Vx4@I?hj-NrPizp6>is8w=X>YvHTeIuh4gKCEW)@$7vCd{?C|3_-{!Rb$4MF)+4s+Ky1^2*oPQ2Kr1mK@58Gu#AJi`q!-U!jHW{V zDbMspsvUn7zDr+~$6}msQN#m1h{O63Gqpvdufy1#cs9~;492J5lSTh9wxh4bV>ZTE z4oP2GzUn2oO3MDK#Fd)w$N!JR`1GsB0;;`!UKMfXA@eNyr`GvD8t1BZ{L}H>Jm;U| zW|{vP7{AE*XI`Sn`JaaIW&Y=a&%5x~4LNH=hM^CV){jTNGZ>RK{48;R|F`pgwewHk zLr&BJe(!|+TZz&7AqRaJc^;m1;Bj^&3mx)R@8j_`jK4R|G_icPw&-eUX;+u;NuG1aTeak0nFk{dc^%|? zIr2JZmh;Hie9ZDYem8D^=0om#!TYQO*tXfv{mjW`_rFiYxXeNFh>zcbk-H)HS3vUm zBl}Mu*v7>CPX15E_{dj9a|IV@4N z558B^(b3n{(>>JCIWRDD_UY{x4)(9XMhPnsWbr0H4+g7ja z>*yJpo6m3KXpb$8DbrRyA#d`S{fRNNPjAHERn5~HCpEQ9pFCl9^Tg>Bnp&G$Cp6D! zZk^CFecGJKQ)V^KYMM4@%Vx#CVO{5j0bJYWTCZ`{=FL~lZfu>{JZ09@2`x=iW=xpe zI(g!R87&Jiy=%bVw7+8e=nGKl7Dp8ngL~S4`oD~4ne*d>rhU(TpT6p~ah5 zao~~iHRo-c|5xO%|0RGnLAv2`Ke$2M_!(Ck$G0>lAX`g#@Zgj{EpRq^eNJ;=G4XsO-)m$%$PK3)}-c1 zleX+3KbTmxfv)`*4*qzNbU0X?qd}yj7xP8%j&qP)W1)-U1kCI8p*Xk1raUKORX!et z_irsf=j%6*Vki)|KQ-9@$p6S<|EFNy^R)l0F=z3An9s=3{yVaRQ;&Ew;2U|`e_D_% z{)cV~20B7iuQPh0VUQN`WmZ&WjWQ-!l}{FCr`mg{GK*n7+8jLUzm`JV&IIFwIY@!?W@ znrHrp*PbQ+a|y;zlmA-tKUwI%6yq12|9PS87wiE4*`yIxAdp&#aGGUxlQp96_QfCd zJo&kwZF}XHN8fhI)bG9XWb%oSuBOKw;D4s$Z(^B=_wBOFHy7=5^aWeL*7}7bmofWM z`!!rX8vl7H3Q*h2DU+HgKC=F4jQVMLk-noA{eL!2bVK=MOA+PvL~Oz;kg5HSTy;@Q zr2ivJ{dom`&Ke|-YObI4vb2NxcN{)E7C;8Z!-&U4_(t{mzcK1zPCF^bKL#Hj2dH-Z zHTdp5OpteU8I0CLiy`3eS&jH^6d=u~&fR_N@0(=|r9l&1#{tED2!1n-u4fq?t z-vV9+FyrxefWHU)1AtNM4*)*|{1f1x0sjJc1@I%lj{!dc{43z!06zu%JK$Bo&j4&+ z`32xV0RIX2CE&jRzXJR>;MaiP0R9K?zkuHYeg}9B@H!x3RLlYMZCvXxSPr(j&rAOQUoQ(_@JDu3s!K|}g>A4V}4FMmiehzs~%K9hy>Tm$@ z@O&ll)=7A0zw*14#+P1*N_A+|f1~{0{y1N?^+nHF#uF)MkNPt@ z!I?eyY!T$P7oWCc#my#I)5-W=BUa-yfN#zF@p53P^Z|@{C%)$|Jo-wF9TIxX%7z{(H1hz-Lc$_Qt!znhjp&tl_4Qu~h zpb)uzHnQ#Q$ga~?v1gH?jp9YW;-O%8i99Zk_^La?j(pz%t|q5-V{O`6{AVWzOER?T z?Cv(4ei?8rQU=?A+wurY;$$qG!R$I<7LM2K*gB63FOGPE;rLeHi=JfMdH>{#^JX^xRk`XXlKu zqKksgSCWfN_JDCLbrw6iR{|Jk8T`(J9(b}an$eSUsp$8W%yq5BH4ty{3799kJ{az* zGn(O<&{yh=Xlm&ALEti&J1*1#gODfwH#A^3F8NIOYaGUXEcbD1x07wy384r0sEu^z zj<%ia)WgZCT}EgJ9o;CDx{Ek5*I9%;WSx&)mnP$`ynPmEbZxMCb@jaX3Zx5jp&t&0 zhsv1v+oo`3q>b`Vi>Op$CU-^d*!d-`31fXM_p#C>&EQ~XOUygc5AWtoL?aG>Yr;k3 zI$N%lX@$SZY_ZPM<-n^*+PV0-R#0enK5z`@xd`oy_E`_!TAYcu{5iPxXzixm^luu^ z9?o>`j$E^RK9A8a)zmld1r*Q0nt>4e&;#zMe?O@?%H^2sq2`!6gVHpqxg^iaH3lZ8 zFB0OtffH@**wpdU#gMI~m+I0Jp6L;3l*(SX=}wF3p5RnqIIyN!80N zJ}u4V{0l+F^*EF9<_-4y;_TV1b2Zret@FVc>xoQPG8!!>*C`p^+Ts}MyDk7%{Nz>l zX+kBr2|KZA-KPzCXU3(h59!Q*5S(>?FnT3*f@)a5EfA}`33!Ifcc_kVJ%*%?5d2mE zzaruW7eAfXxxnXvVDp+q4wfL!VjL@x>%l>1HpzjE3t1UuzGkDR2FWc|i}YF90dAID z_$7qegWV`aR*$3`g?k5ZrK0j7`*iZphonVICJ#u8v;dap&i~2U`4Jc=ACH}#C+xXn zMZwt3U2yJjnP=5`cE;Jri)7qL*#`jiWMNIF$z)xrSBA?OGQn9i^diXda4JXCzP!2( zF>a;hQRpoUszG!fxnGx5Sk%r+9?W!R2(MiS9K+eKq!w2E4DVkBe8Ta*(1bH7ae?Ms zhOj%V!Rle~{^O}URH+-L(r0PfEJ-E4;7As(>rM=EUw)MuZnUB5TfCnI>`f+bphc+ZK%blUT(w zfUcI4NR%t~o(YC!HXqVl0e3g%%(FLu**M#8q^|A;e7?Xdh+mV7wdvb$1OA3s^OoJwH3!c0Z^osR_;n#=`G;2aQQ#= z{S4*OJM2WeYy^JcyomUG>I!sM$F>KR&vdMee9i+l^_eBIYwreE?lKu}K5ZRqR_VGc zbHuvb4hbzX`iyH}pZ_IsXVN30j#&-}C&x*;>W&nuZS1INA?7_?zRAXq(&NkM7=D}z zyuwvU{gQ02cI8}hm!Kj$E;On$G~(_>;k*&G5k?9$KW?x&8`$LA4?7vz;>qxyWgirO zKkRMblyFpV<5|;P)??*t-Un>L@rcfe;b5`b8dt9eKH>CFQjQiNGuwr{zhK%K<+&6; z?l5)>@^(d5?(Di9YbEv7hs(Wh1|V5xwV}Pw$4$WW(cFD!e?*e2GO@~Tm;DXkrf@kz#oDcSl8cfnT~`9PBG+|jX$FsW#w@W-r%uQFg?1q_R7e&(goIXJtl( zyRq;t;avM?_RbFHN842M?J*(Q-wy$^;=6hod9T0(FV-j|B|oZp)=pn--%J_Sx*7Z0|KV3FAJT`?!9Mom^FBXwUWd+=-1{ z-j%&O?m8b%7tI1j>}BUIEzI3G?L7ZyfJ?Z{OPp)dt=~-Gb#Jg4jeEdJzvVp8&h6#; z2{0^1H>TBYD1o~}((7++f$i%V9OS+5% zi|N23oW^$jAbZbPO8A3-BE4%j0yUYq+2GA^`3j9y+?002iB9l(`%Xa(r6@BS`;yxHJ^eVRa{;pGjL%8Z( z+~Z2GQTTmU&d}+Yp>P#}>M>4s$29=cr!w)9ScF=v#mHWx+IM?(rLJOEuab0r8?Xks|)Y9(u+uEDB2zPl+r19%?#;sJenAdnN<1-yt0LWTk*c0 zr<#mM-s^CCfKewfTnl|u!aY3l%V}$t&s^^zICr>8pY1RByXI8q+OglB;J0u+AU+G= z*E!;Ky&L$|Uo2x+mRwJroW4JBF2WOHl|uJEQ%`7T;1iA$;~LSg|B_TYAC#+~waDTr zaXxPX{fhLq4Xw0)i#YWGr*Ixbd`^?O5uIgLh?$+^ZX?W=aMdC)9tVuWX_};Eb7Pj| zZq}Cpzi^&<5T#rWdAn%O%T-|#$wp1tcdgOwBz^W0w0JG!uAo!;P*W6O#4jbGV zfK?2`Q@Xc?dLXtpVtDSu7_G=TwO7l!^GaHL0`P1d&8ew!%bID^O_<)nE}Z!lTt$)E zF&_VuvUdRTk89&HYwy|M=k`;9N4WlDe@09FfHQ$jo_C{cK`voVB$xg!Y|g~3(5m+b z<8k#b?FzPfzJ|kBL{SR!m`a=X0?#6=N8~NviU(I~h|HY^Y{TV&g=%U0DJm6Tz>F8+ z`L?32#mW|Uk)h|tl>y|w`vBphX_roMpUGhKDPR6k z>9f|TbFt5nzt4g$;W}MLri;%O`gMFeFb`MrPsaI`x+Ja#ZbfG8M(#EijrKPMV`_V9 zl`|6G2Bt-N;*~nqqp&-F@-w`^OKJ#+A;G;ymU7r$ggT#G}c( zt9Neh$21~}#K z_4>U^UA5JY_)PY+H=OkvW;0yADejfGmn4#|EXRKVEW`Qc=~xCXn=-`(X%#2jalXQ~+O0*t~{ zP?A0g499owH8_0?I6YBE@@wuSlU}Kn$n$_5BF9{rZ|>O0 z=;$2GA?J}5jZWvTRCB;7^aGf?+F0h6U4c;%HkQ$&T|cJ1-wC+XQ(nf*D!nJU(}?k9 zjc>USSFpZJ#X(>nu6sPG4PB4gUQH-kaSzb8{v^iUCETX1+L@z(cQ|jy;GjECw_{}m zbG<7dOXLBqP0k>_r+vL?qYS5E_U%03~sX-M#L$Bk3Pq=zw5+4&e$ldLfPQL_Cg^Or3#-e}G0V~r9 zePpne+?8~y%x|4V^Sk% z){hjG*iC<7=-P`b2xqtBUTP(*4Sw&6BxJU=hQVG7QK{#l(r49EIF4~8J*#}NE+|!# z*4?}#{maCexiQ6W5YiOR%Db9Bc_&VLb;KWoas!zpDy>Q-Gq*VME7;e{h|%9s0&--m zjnSgkw%(OcbEu%5UuqugwN#;i?j@H)B@! zi5GJtxIUb8V{+{_YUTMEpDOtf%$P)m3N& z`!56gA~R2}4pN`A6*ByEfgS<*!M7e@qUIWKOe)wQ|8JHG~w&*x5!>Z4rE3M3

wdiJFbf`Uz7x$pSNS2Z1a;Q1)@3J%~^I)$wUjVG+KK9a0HUU_K%fq>OC31*cB@=#V zEZByoOFC`Tslcv?tg4Nb;V!v%lhEyypmb9&t#ZCsuzM1;yEb3+Bh+4goHIL`6Iz@M9K!LCD|c}nF@%mo)sdeDX5n%G%0sd~#$G!l)LH_*E;9ag z{e0T82SJV_q=2w+9- zwyh1`V`u3K(8Bg&kH%P!<~~-MXYbk$(L~9brSeZpv?hhor|jZ(G-fW(J%px3`?au3 zJ$(>_YY3@u8sPEV$4ryHk!Q}xr@P+ItxXc^4nVjZsp@ez3n26M?t-v!*I0@y zz6@;YsbipWEmS@AXMy*QusQaxcRqlj68HQ~cfITdgP6UM0?<32hyDt65 zz^=$X0N3aAXWyt7hN08L#i2=`N~|Qa%Jg%TyWbVm+N5Kq7|jPp;W#d7|4bED?iD2~ ziNqyo*+sPb~P^t@BrpRoCdfEQSWUzE%F<7@Z!#F@iI^*(vlRkOyXZ39LdQm?i4l_YJ^>byR9nmx!Y z&c!3EkL=^HGoBv-rxn>-YA7VxV)ak@f!A;M`Rwk3^?|+nuc6=jfzfkyPCwb@g4Q*@PF>`Pd$?Sd z`*pbeSVv-vZMlz;#%qOC_T|UvwpWmdx;8 z0_^khKztd%u{i(IOw>v9aBL4mWMeO!{oYJxr<~QcdR3~$_U=%XcmE~Nejbp2_ez>% zX?`WX>&mgPY}vBDY4c#){srh<;|_iNueRW=xaM%#LA~aYXXB56S-6^cQqSqEBx8XS zF+<^~R*iNODSHM~TbxPC(s;*=%C2Xr4(^9@hl?ZZt9IjS<=$18ha%%z*UGqjA~W)r zpjxvSY`~fnzuuVb7-Q`(r%j zW^jHH(T~gV2A8d%$*ri|6}f(I10wuk#QNMpggef)0oLTQ-{Ul7?iOG-$(GX8(j==N z#r4YXzW3*epLyZl$s zjU08kx{9><4PbdDxl8k%EBBWjfN_fGzxUPEq(XHqa0=(8CONh_T1&-U&`rD{KH;AM zuP%b{ogf$C#rysGyQ1r;VbBIQK z40t?Lr<%vsGSn{b1k`6Ime%a-)dGh@`EAV@F^={ggX=M~lgja-;k37bYWe%we%qpX zm&rl-Dk*d39jQM1D>!1guEacr%QD!SOS2tp10$k zq=B4KzXyrNPm41BC zao_pO`0?jF`N|KsoUpvNEXr-A=_?L;?)B%6ocF+eU60*;Wt8sNvRkI^;@{mqUM#Bh(&@j2r*6Ei>3)tXv7?+Mix!OHTr z@Lo~Odrk&_O~qN#juT5eIe~N9_w4u2#)})uZ!AUB)r0$G@g8$m;QvaD>+T(6|1$af zSls`Oar>e8h>yu{B;TQ}<1U9hs=5AY=BwWSxc)KY@X4`&YRA6_-(}|;k7~xBVZQ49 zPx>E&PmTjrJ3jBLeoy&q*{pg}{w5>OyaIjzYa6^5O$%nT3+Gnda|T}JD{+h)lAgs# zc$~Gv@i1{=Q&gJ^O%q!$R*%PCrFVlW%(%V>a2?>i0Gdh4=Z%2(0d4}^47dfr{>a+^ zhX8H|+yUSnw_gYI-HFE!0m$120oX_X8s6Ur&-wYANBvR2)Z!R*m|k`DW5q)-7RqFp zX%%=^h#}0VIZiL@U%4`QztSUlK|Y@iXSowzOKw9#3n!-mByFINpkV#7w-QCjDH~BIt)M@+)w?l?CWQ+&=YmSnYyB(v#A*~h%k4c z;-0Dg<-_*Q-4jI^!-LU88ZMndF58_b$b`#d`7IYa|0{N{?os||Q6Bhf#@-|t=571X zxP$jS>xll_etZ5!&maCg#}Yi{u{{1Am(Cq?*-z)(eBQ5ie{IhjUOa)6r!-2>ZFl*5 zX%F;&4#tPO0C?)O@7eD&=6(TzGY?ajosan+EKh^V_+mu&BOS+Je9i~$LAB$vyO%bH z2Y28yJ6uUToTh2a_v8O@{ZW{I1U{&Cd|Uo5hGg}C-_6~yyUKTN)hIkZUi>w#-1p8)@zPG9CiO8v@9~__ljL;zcoBGK*Jf)w{W5sCfpD$f% zZb&H0{KSG^d-Kv8mux#_Vbhl5wr-pC;P*MSpe&DkFZ0p2BkcMhukvrg50x= z|0^9IM~vongsAQF_Y{q$E|IJO`Z|G3RfN%~R4Lq8WC$*!kM%}_nfUn9jhI{^rG1j@ zJZAoZI|LbAF9WXOs&966$5grOb&Pgb#g~9rxH^}3a7G1?8<`Oj(J7Vw9@rGQ?uy)3 zc~A8TkcRy0@FvD)EJx1OyWUGRaz?>2$j)un1(H3Q7XY(7_fnjUc)JnyO!rcZhfa_q zj9H%@B+RiA?EA>L3FBV20-OWY0Z#lRxTrW!8O2)g-jWt{Z3a!gs zBGTrJ7EtNIxH8=SJ4t@=`7^df{uAIAt{=wdZ`nJb2v5HRtcvKxcO~AY(+_}A5j)J8 zRZOz?j`G!Sflqx}rHkRQbisnVR%u`8g~tNQpu4sy={=i$Mr{jfc+*~ObR=*d%pGU) zn1rKd%mHZmK3G;+O*{^B8?Ludz2xS|>(Z45?4M;`;>p};kghvNnm2#cEL0Wwa`l6GLCYjFR~PARn*C-T9a2-UW~z9o3r0PUiR7sgr+{ zpC&UVJIL#60Tfy3l)ff*y0e2)waA|Xvm*T#-G3t8-~K6ZEHbty^>lr<>sxVlxuWKQ zU^+0K2T$g^G;gv5HBf3A$u=DfOpA#7T+d#)Z!Yi&H?ykgTzrz&Lp=z%&_^N*RX0<}+H<_Chcx55oMI|{JHjPs3PSDMt-y3bH0 zUz^dhbY>dGT6F|h<%H9u#LTWj+w&+MBWzWRs*h$>RtVKH8EOY-WYj^v+$qQOYT<5Z*=4J28^bwIJrN_T0pp- zPL*2QgH_G@PrxQzy+)#*)$ncn{Sk(KT#K|L_J55_AM5YK$O*C2)ZOVqDb%n-FiG=Y zb-tv7LNVb=og((crIbk?+(_0Zfyw8CX{4kF5`V|=RUh!wh)7oLGQL(CUIEOXDG+n@ zev-bEdll@N;yx_;3qyOZLN4-7PnGSJ_)p&emf>q)HmjxVZf zg_U6EOAoS=hJ)APwHw>NV@yct_voQ$^M-^Gzxa=i$KF8*s7TMO@ zrBgmV^TUz2Q`VwPSD7}Fy_%0_=DsZ9W;3o^wE}J|_$*)(&H~xh6x9+2lTPqek^Xp` zQmzkfYAfQ2`?+&DXc^9i+O#z5&E1tNqOG_eTzzKX?0zr91BZeK!pTNl=dilY=vK1$ z^MFmb`Ao;g)xYh)DqMY5vk(S9>7%Aqbo&a$T5SY=Mfz;2SCT&4mZ1Elw2Mc|hTG4E zWER;Mq28^*=NG`I$eJ;wk2@y!Am6dFTtE0v;1n(^Y3o$-yDvgFw3-@J3T?cMuGd~B z<#*fLUI_fc(XDbkx6I1AJrZ<2tFh^3KIZ|iM>F|*)p)hlXA-KxRPOw3FuoBOKTt;) zb3c^1^m4>vTNz1+fI<70K6q&mXu-njHGxbzNwNU$O zsGV|cyyjun2eq57HZlDtJ(do6AF#={r;~Ten2ZsI5#_U*?eFQl4dbS-z{%26V_%`k zFAPC$2CZxS7{(e%mF{ZB^7T{k%F?${!#>d%b=3|TRika?syi`S5i61_cP)q?`+i_o zPx{sHj9b|kyEqAB*HhMZ zIkK9vf1XIeIlysosz&hZ82`JjPUZFQ1_&4b#62uy>+E%0t-vQ-rX=YVxcM8uB+0yd zJt(em+9hjYnpbppzTrIY10Kq@9y2YMYWM5;Wh|MQ6N()QOv3Fj5uaVPdS?NTCo)M? zzLAD@5mcJRWNvOR%wo8_j_Pl>wv@~}k;7I3x5tCgRB^LcbTp$*$Q_I}!iVHar6JS| zWsQ>fd+r*K8-h|a&XJn!w09j4X;}>1itm^kggsh;_2aCfTgt@kMs|dZ+P7L+=kR()SZ!8LqMs_nOk*{LJ`$R~71AG$ zZ`A+M6%N!v_W;7>g%k@n|DrScx4@@JPt}cpP0n{VW-9bbu=p-vyaR1|J;Y}#((*bZ z`;I$>aS6dwx2I1jmQG)T zQy*};Gnl4V|7$L&liXoK{2pqWn}At3k1VMh?dUtHxjz96SB>b87~47sF6aP_TT0wb zfIDa~({DIK_YqKk!S)@@EPWWGJr``2vhaGE9!};{IH&!9BIi`%QFlH?qkI$Ch0}OR zj&tL|ZYULlf#i?TN-{9w|Q-Md3TGfq>jJ)0foSv;Cc{MqG zx5q4f&6CK(S8x^K;u5>=khHFbuAc%%Mfi2CsK>}INVHL`+ftw12MCw5b}1B>6gv`s z0eBTz$s%qeM?k`7r$MjXA52=*2eG?6)aw)~Yfp#Z`Cj0e=lwZbkmH#X`2+s`WOCT8 z7&BaVPBQaTsXyX+;1{l{KC)Nh({g^B(GJYhE113vXEk+{R&;c9gG1=|3(tHus3eX| zBaNUnd!pDL2yP3PkEj(}JEl4e7+*i4AMWk|wj}bsyWowkM>oQ_()oDJKALvy5!L_? zy}iVWioM5|xr^{1W|uuZrdwit`7G>YGS=Wx%yp4odZi9PpKOQ+puaQMu?E*sWd6*K zyej7azFjb;BX`J)9{3wzT7>5!E1&INK-!h1kehHeH}0#%tE~Q6CZ6vBY|7*tq}8Ix zRkA0jKeidd&JdJwyPNGT7(aWCpJ&m#obWo>0_YNc{SDT`rsGXI}n=lEyek+D`5WT0+$Y42lbl4uMtG?O4)I3Bnap&!KeQ|`MEn1t(PRC!REC@$|Q2p2{| zc8!)AY$xE7znF34a70@DZ()>O zF}yqo>{sP(^Ei*b?&KL5E!^tsxSaU%EbczloXf?4p4=(o>Kl`@npoB+)4)C3a=Bj` zwYuz;&nuIi@|WRyx})B>mGBX%=axlzG_LmP!5@D`4aon?P(hgz?X177od2e#ES1g% zmf@^;GTuw8z;e!(0k`5jHy>ZgzCkX3iAH0GVv*HswfX*P`_-UlxQtj*Z zN*@myEmEf`K7O5c67VY`zH;rB;r4TZ%jLQ254*-m34c6-P&=B9PD`n7T?eeg@zKaw zYgN|F-MfI_Gr7-Q^}1gxf=N4|xKgi4FTVc5TtP3cAlxcgTi5#ToGJS3hrlZTI6sZ9 z#$v93{^GrmNG;xRpcgiY_W?0oBH*Uk*?XGTsSS1q@2+J+^vQAJ;?`e49aOL^S+8$J0fxIXZ$!Y zyEl{M)h_wI9WZQ9+3#U}3m6vRVYxD3xN9BwKHbC0V;>A^!w+MWB7K3lyj6+={h5fB zxQcL5U{VToeIw~PACS$uRKw%sTn-5EB5jZB zr?@(S_{{-+;c9EHM`!p-Jh>ZzNj#~+>`5LYzT&*%G$!^})wXTBW zuYqI!wMxHa8^3xAMqHR_hSTDI*Yi6N=gr?&s3c265uXep_G8yaA2gJ?!gGPi3z@F4 z8Xwe8(k*kh<`5o2p-vxHz zq9Z%+6t_8~)oR$Aa20sXO=z{)@Bb0Et-vjR`xDoS_KM^99pj0`1VA>6oTi<`wz%2J z`SAIApfOe>N@Z1e7;6OC8P*GZVeX@)yt6lOS)RKd(R;6o4R|}oc_{aB()3k)Mygva zBDnrl=J^?oZdDG}2uA1Ucfci_G}*FE8v6WU#cc|tDO?nxbds)AdqtAW-4fswE|cs= z^Kq^lLYI(iLYQ2X)`6FYw-)HxYA+3M1>7BuZgGA#QL|qs(5{^d?84PbT-l=s=hjALHXDO# zsW{F2mBM#`T00^K)q(ZMYU4R4jesKKL)Sy3XXf4;mN<4}h8_*(8@PNU)ROpHV;A)& zTcVzNMqkpEb~G?vkvqor9oSUnj|PRpc>r<#ZO1wT{~ZZAa~}a@^JMe!l;~lTkL=#O zGchOO=%iZP<#6R1dpDI{;8tXOYi3pI@5%UfC@AfcJm%s@2{ruzG*C}O3F6KVS8coUE zy$XyT%bg0f&z;&DJ5SaU*+_QBkcx+Z`-}AWB-V0uhWJ(sfL)&Z8BL3NNx0%9eLthy zgHmK<33OMH{y5_LVrzb#QEhD_vOnFx=0w1b@Kx;l@CZMQ$5{2$qfohmtv=SXz`F<= zYM$0Osi|f9x7o+ z)8^<8R}Bvj40R8#>mF=a*STR}uz$_w*{8Q(h{x{E;i2}GtA|&uUEZ$WvY)oCUfI{t zGc>oOudAnfsA1LS%~#ECY@OIVW!BUQElpEqOqkp{dE$f_EmIpOG&N0~GGo%DS(BP4 zP1xQ!jzrxi`P1b7zdjcXk<>6xo{r{6L@ z9XoJ}TL)SRQ`-+!>-bgR8*U9(S_G!}{3GxQ=MyI*3)Az!>Ikc9vRjPs_h0`-h%*;EI7fG)h4+GC|8OkJ{zWTo(Tj9d* zfeVYwIBE3lj~ssm{ED1;H*1&7OA8&lF!M!9Gc~fV?51tr23V959r(S2w0GkxG55ro zFU{r5{!I3+IDe5mY4oKi&k+l-~J-V-ui=Xi081Un!Omj3E-%$J0W&9?L zU*sIRa_eT>IfqvOziq+j+S z{Xsa6ySfyqf$bf7jsO0BVDxaEQ&xSfyMb*HH9A+@8p{1IaH;*u9&c6gB7rCOq^^TRJ`hnMmREpHTYOxKm)JoJ7XrYHnbMeTI4(2oMTIxqI`n{>6 zS6V+_>9aJwmelaFzi_&C|2(*SX(kM-@z8`TkigB&OY`OM$Kw1?Wx{?m9!5O(lgv(3 zvKz@t=Ow^CTn|z*H$b`8l}%E4yarf>i@-I5GBU6J5irYE9ZKU>Tca&N2Qu%?#{a4} zm@B?E7-uOJbk7}Qg_yTqoC%M#Yc})GZfmL6?iX~XtKmP<8_xi;rvkLUZel)9Ux>zn}Ja{|G?%oUmvZ?`4hk^+-xQ} z&DFs!w+Ze3GU#mDv~wd^rP?aUz^$+yMXna!0FEDq&&BR5?*7;YC?a-nXV7Tvt-vLm z^{{75_IWgTG-IB^+48uq(yEf-dwZvaIiOHD-^b`B*_)~h-a2)Z^wG+FYk8l9VtOky z18r;Z|0xI?w`L@Jbk71Wt;uCi-D$`QE-1C)PBT+WldS$JHz#yQP~J^yX7NW|olFnl zbAWI)y|`4F9Zbl-ebB(&4J{05_t~T4rKCgtBK&; zy`e?U*zvAK=zUoa zyN^WtSk8I47$B+9UFxbg`)9zbK6_j=yKArLIUHR2P@VFEJ@1_FcLKtB!m}Vh{fG;O zqDS5>O0?@^z$4uH-z4u*MzmgPtkCPgDSzANmucnp$ryEO#@KDN_YmcsM<KBDc>EgNqK(9 z>b~k*yFU^bu?#eWC196DbgVx6_n=LF*V62|?v&rFZF_TlQ}t^GM)jNW^lg6_TN<;| z_7~2R*~RqnXO!auWC?{=F|D;kA@;=iMiBEtB+l;#+O~rs+7m&*E$F z`}V=#*6x2aO_g)K>3^`xq!FIaNS;yL|1ev7c!QfNb{`S{Bg5_^QJ^OI-~9ZK+O|m% z{ue&tV|ibd_IN1o+lhqVkLLig + + + + Debug + x64 + + + Release + Win32 + + + Debug + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {A7023B84-DA18-3E3E-A9AE-B87F45CAC37F} + httpserver + Qt4VSv1.0 + + + + release\ + false + MultiByte + Application + release\ + v120 + true + + + release\ + false + MultiByte + Application + release\ + v120 + true + + + debug\ + false + MultiByte + Application + debug\ + v120 + + + debug\ + false + MultiByte + Application + debug\ + v120 + + + + + + + + + + + + + + + + + + ..\..\build\$(Platform)\$(Configuration)\ + ..\..\build\$(Platform)\$(Configuration)\ + true + true + false + false + ..\..\build\$(Platform)\$(Configuration)\ + ..\..\build\$(Platform)\$(Configuration)\ + true + true + + + ..\..\build\$(Platform)\$(Configuration)\ + ..\..\build\$(Platform)\$(Configuration)\ + + + ..\..\build\$(Platform)\$(Configuration)\ + ..\..\build\$(Platform)\$(Configuration)\ + + + + %(AdditionalIncludeDirectories) + %(AdditionalOptions) + $(OutDir)asm\ + false + Sync + $(OutDir)obj\ + MaxSpeed + _CONSOLE;WIN32;NDEBUG;%(PreprocessorDefinitions) + false + ..\..\build\ + MultiThreadedDLL + true + false + Level3 + + + %(AdditionalDependencies) + "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) + true + false + true + false + $(OutDir)$(TargetName)$(TargetExt) + true + Console + true + + + Unsigned + None + 0 + + + _CONSOLE;WIN32;%(PreprocessorDefinitions) + + + + + %(AdditionalIncludeDirectories) + %(AdditionalOptions) + $(OutDir)asm\ + false + Sync + $(OutDir)obj\ + MaxSpeed + _CONSOLE;WIN32;NDEBUG;%(PreprocessorDefinitions) + false + ..\..\build\ + MultiThreadedDLL + true + false + Level3 + + + %(AdditionalDependencies) + "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) + true + false + true + false + $(OutDir)$(TargetName)$(TargetExt) + true + Console + true + + + Unsigned + None + 0 + + + _CONSOLE;WIN32;%(PreprocessorDefinitions) + + + + + %(AdditionalIncludeDirectories) + %(AdditionalOptions) + $(OutDir)asm\ + false + ProgramDatabase + Sync + $(OutDir)obj\ + _CONSOLE;WIN32;DEBUG;%(PreprocessorDefinitions) + false + ..\..\build\ + MultiThreadedDebugDLL + true + false + Level3 + Disabled + + + %(AdditionalDependencies) + "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) + true + true + true + $(OutDir)$(TargetName)$(TargetExt) + true + Console + true + + + Unsigned + None + 0 + + + _CONSOLE;WIN32;DEBUG;_DEBUG;%(PreprocessorDefinitions) + + + + + %(AdditionalIncludeDirectories) + %(AdditionalOptions) + $(OutDir)asm\ + false + ProgramDatabase + Sync + $(OutDir)obj\ + _CONSOLE;WIN32;DEBUG;%(PreprocessorDefinitions) + false + ..\..\build\ + MultiThreadedDebugDLL + true + false + Level3 + Disabled + + + %(AdditionalDependencies) + "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) + true + true + true + $(OutDir)$(TargetName)$(TargetExt) + true + Console + true + + + Unsigned + None + 0 + + + _CONSOLE;WIN32;DEBUG;_DEBUG;%(PreprocessorDefinitions) + + + + + \ No newline at end of file diff --git a/projects/msvs/httpserver.vcxproj.filters b/projects/msvs/httpserver.vcxproj.filters new file mode 100644 index 0000000..9f4bea1 --- /dev/null +++ b/projects/msvs/httpserver.vcxproj.filters @@ -0,0 +1,139 @@ + + + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + 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 + + + \ No newline at end of file diff --git a/projects/msvs/httpserver.vcxproj.user b/projects/msvs/httpserver.vcxproj.user new file mode 100644 index 0000000..89d2452 --- /dev/null +++ b/projects/msvs/httpserver.vcxproj.user @@ -0,0 +1,6 @@ + + + + false + + \ No newline at end of file diff --git a/deployment.pri b/projects/qt-creator/deployment.pri similarity index 100% rename from deployment.pri rename to projects/qt-creator/deployment.pri diff --git a/projects/qt-creator/httpserver.pro b/projects/qt-creator/httpserver.pro new file mode 100644 index 0000000..3c1b4de --- /dev/null +++ b/projects/qt-creator/httpserver.pro @@ -0,0 +1,70 @@ +TEMPLATE = app + +CONFIG += console c++11 +CONFIG -= app_bundle +CONFIG -= qt + +lessThan(QT_MAJOR_VERSION, 5) { + QMAKE_CXXFLAGS += -std=c++1y +} + +unix { + DEFINES += POSIX +} + +CONFIG(debug, debug|release):DEFINES += DEBUG + +CONFIG(release, debug|release) +{ + QMAKE_CFLAGS_RELEASE -= -O + QMAKE_CFLAGS_RELEASE -= -O1 + QMAKE_CFLAGS_RELEASE *= -O2 +# QMAKE_CFLAGS_RELEASE *= -O3 +} + +LIBS += -ldl -pthread + +SOURCES += \ + ../../src/ConfigParser.cpp \ + ../../src/DataVariantFormUrlencoded.cpp \ + ../../src/DataVariantMultipartFormData.cpp \ + ../../src/DataVariantTextPlain.cpp \ + ../../src/Event.cpp \ + ../../src/FileIncoming.cpp \ + ../../src/Main.cpp \ + ../../src/Module.cpp \ + ../../src/RequestParameters.cpp \ + ../../src/Server.cpp \ + ../../src/ServerApplicationsTree.cpp \ + ../../src/SignalsHandles.cpp \ + ../../src/Socket.cpp \ + ../../src/SocketList.cpp \ + ../../src/System.cpp \ + ../../src/Utils.cpp + +include(deployment.pri) +qtcAddDeployment() + +HEADERS += \ + ../../src/ConfigParser.h \ + ../../src/DataVariantAbstract.h \ + ../../src/DataVariantFormUrlencoded.h \ + ../../src/DataVariantMultipartFormData.h \ + ../../src/DataVariantTextPlain.h \ + ../../src/Event.h \ + ../../src/FileIncoming.h \ + ../../src/Main.h \ + ../../src/Module.h \ + ../../src/RawData.h \ + ../../src/RequestParameters.h \ + ../../src/Server.h \ + ../../src/ServerApplicationDefaultSettings.h \ + ../../src/ServerApplicationSettings.h \ + ../../src/ServerApplicationsTree.h \ + ../../src/ServerRequest.h \ + ../../src/ServerResponse.h \ + ../../src/SignalsHandles.h \ + ../../src/Socket.h \ + ../../src/SocketList.h \ + ../../src/System.h \ + ../../src/Utils.h diff --git a/httpserver.pro.user b/projects/qt-creator/httpserver.pro.user similarity index 95% rename from httpserver.pro.user rename to projects/qt-creator/httpserver.pro.user index 8782157..535e1d7 100644 --- a/httpserver.pro.user +++ b/projects/qt-creator/httpserver.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -61,11 +61,11 @@ Desktop Desktop {c77ee4a2-1c2a-4bac-9185-8378ec4ebf5d} - 1 + 0 0 0 - build/Debug + ../../build/Debug true @@ -76,6 +76,8 @@ true false + false + false true @@ -91,7 +93,7 @@ 2 - Сборка + Build ProjectExplorer.BuildSteps.Build @@ -110,7 +112,7 @@ 1 - Очистка + Clean ProjectExplorer.BuildSteps.Clean @@ -124,7 +126,7 @@ true - build/Release + ../../build/Release true @@ -135,6 +137,8 @@ true false + false + false true @@ -150,7 +154,7 @@ 2 - Сборка + Build ProjectExplorer.BuildSteps.Build @@ -169,7 +173,7 @@ 1 - Очистка + Clean ProjectExplorer.BuildSteps.Clean @@ -186,7 +190,7 @@ 0 - Установка + Deploy ProjectExplorer.BuildSteps.Deploy @@ -235,9 +239,9 @@ 2 httpserver - - Qt4ProjectManager.Qt4RunConfiguration:/media/projects/httpserver/httpserver.pro - --start + httpserver2 + Qt4ProjectManager.Qt4RunConfiguration:/media/projects/httpserver/projects/qt-creator/httpserver.pro + httpserver.pro false true @@ -258,10 +262,10 @@ ProjectExplorer.Project.Updater.FileVersion - 16 + 18 Version - 16 + 18 diff --git a/apps.conf b/samples/apps.conf similarity index 100% rename from apps.conf rename to samples/apps.conf diff --git a/main.conf b/samples/main.conf similarity index 100% rename from main.conf rename to samples/main.conf diff --git a/mimes.conf b/samples/mimes.conf similarity index 100% rename from mimes.conf rename to samples/mimes.conf diff --git a/httpserver/ConfigParser.cpp b/src/ConfigParser.cpp similarity index 96% rename from httpserver/ConfigParser.cpp rename to src/ConfigParser.cpp index adb8518..bb0ab25 100644 --- a/httpserver/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -29,7 +29,7 @@ namespace HttpServer std::streamsize file_size = file.tellg(); file.seekg(0, std::ifstream::beg); - std::streamsize file_size_max = 2048 * 1024; + const std::streamsize file_size_max = 2048 * 1024; if (file_size_max < file_size) { @@ -73,7 +73,7 @@ namespace HttpServer std::vector names; - std::string whitespace(" \t\n\v\f\r"); + const std::string whitespace(" \t\n\v\f\r"); const std::string &app_name = it_name->second; @@ -286,7 +286,7 @@ namespace HttpServer std::streamsize file_size = file.tellg(); file.seekg(0, std::ifstream::beg); - std::streamsize file_size_max = 2048 * 1024; + const std::streamsize file_size_max = 2048 * 1024; if (file_size_max < file_size) { @@ -297,13 +297,13 @@ namespace HttpServer return false; } - std::string whitespace(" \t\v\f\r"); + const std::string whitespace(" \t\v\f\r"); std::vector buf(file_size); file.read(reinterpret_cast(buf.data() ), file_size); - std::string str_buf(buf.cbegin(), buf.cend() ); + const std::string str_buf(buf.cbegin(), buf.cend() ); size_t cur_pos = 0; size_t end_pos = str_buf.find('\n', cur_pos); @@ -363,24 +363,23 @@ namespace HttpServer * Config - parse */ bool ConfigParser::loadConfig( - const std::string &conf, + const std::string &conf_file_name, std::unordered_map &settings, std::unordered_map &mimes_types, std::vector &modules, ServerApplicationsTree &apps_tree ) { - std::string file_name(conf); std::string str_buf; - if (false == includeConfigFile(file_name, str_buf) ) + if (false == includeConfigFile(conf_file_name, str_buf) ) { return false; } std::vector > applications; - std::string whitespace(" \t\n\v\f\r"); + const std::string whitespace(" \t\n\v\f\r"); size_t cur_pos = 0; size_t end_pos = str_buf.find(';', cur_pos); @@ -421,7 +420,7 @@ namespace HttpServer cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); size_t delimiter = str_buf.find_first_of(whitespace, cur_pos); - std::string block_type_name = str_buf.substr(cur_pos, delimiter - cur_pos); + const std::string block_type_name = str_buf.substr(cur_pos, delimiter - cur_pos); delimiter = str_buf.find_first_not_of(whitespace, delimiter); diff --git a/httpserver/ConfigParser.h b/src/ConfigParser.h similarity index 100% rename from httpserver/ConfigParser.h rename to src/ConfigParser.h diff --git a/httpserver/DataVariantAbstract.h b/src/DataVariantAbstract.h similarity index 100% rename from httpserver/DataVariantAbstract.h rename to src/DataVariantAbstract.h diff --git a/httpserver/DataVariantFormUrlencoded.cpp b/src/DataVariantFormUrlencoded.cpp similarity index 100% rename from httpserver/DataVariantFormUrlencoded.cpp rename to src/DataVariantFormUrlencoded.cpp diff --git a/httpserver/DataVariantFormUrlencoded.h b/src/DataVariantFormUrlencoded.h similarity index 100% rename from httpserver/DataVariantFormUrlencoded.h rename to src/DataVariantFormUrlencoded.h diff --git a/httpserver/DataVariantMultipartFormData.cpp b/src/DataVariantMultipartFormData.cpp similarity index 99% rename from httpserver/DataVariantMultipartFormData.cpp rename to src/DataVariantMultipartFormData.cpp index 1badbab..b94ba02 100644 --- a/httpserver/DataVariantMultipartFormData.cpp +++ b/src/DataVariantMultipartFormData.cpp @@ -191,7 +191,7 @@ namespace HttpServer // Разобрать значение заголовка данных на параметры std::unordered_map header_params; - std::string &header_value = it->second; + const std::string &header_value = it->second; size_t delimiter = header_value.find(';'); diff --git a/httpserver/DataVariantMultipartFormData.h b/src/DataVariantMultipartFormData.h similarity index 100% rename from httpserver/DataVariantMultipartFormData.h rename to src/DataVariantMultipartFormData.h diff --git a/httpserver/DataVariantTextPlain.cpp b/src/DataVariantTextPlain.cpp similarity index 100% rename from httpserver/DataVariantTextPlain.cpp rename to src/DataVariantTextPlain.cpp diff --git a/httpserver/DataVariantTextPlain.h b/src/DataVariantTextPlain.h similarity index 100% rename from httpserver/DataVariantTextPlain.h rename to src/DataVariantTextPlain.h diff --git a/httpserver/Event.cpp b/src/Event.cpp similarity index 100% rename from httpserver/Event.cpp rename to src/Event.cpp diff --git a/httpserver/Event.h b/src/Event.h similarity index 100% rename from httpserver/Event.h rename to src/Event.h diff --git a/httpserver/FileIncoming.cpp b/src/FileIncoming.cpp similarity index 95% rename from httpserver/FileIncoming.cpp rename to src/FileIncoming.cpp index 4f20f95..04b5975 100644 --- a/httpserver/FileIncoming.cpp +++ b/src/FileIncoming.cpp @@ -27,7 +27,7 @@ namespace HttpServer { std::ifstream file(file_name, std::ifstream::binary); - bool is_exists = file.good(); + const bool is_exists = file.good(); file.close(); diff --git a/httpserver/FileIncoming.h b/src/FileIncoming.h similarity index 100% rename from httpserver/FileIncoming.h rename to src/FileIncoming.h diff --git a/httpserver/Main.cpp b/src/Main.cpp similarity index 95% rename from httpserver/Main.cpp rename to src/Main.cpp index c180df4..346a59e 100644 --- a/httpserver/Main.cpp +++ b/src/Main.cpp @@ -2,9 +2,6 @@ #include "SignalsHandles.h" #include -#include -#include -#include int main(const int argc, const char *argv[]) { diff --git a/httpserver/Main.h b/src/Main.h similarity index 52% rename from httpserver/Main.h rename to src/Main.h index 5af3ec0..e2373d9 100644 --- a/httpserver/Main.h +++ b/src/Main.h @@ -5,7 +5,4 @@ #ifdef WIN32 #include std::thread threadMessageLoop; - char myWndClassName[] = "WndClassNameConstant"; #endif - -HttpServer::Server *globalServerPtr = nullptr; diff --git a/httpserver/Module.cpp b/src/Module.cpp similarity index 100% rename from httpserver/Module.cpp rename to src/Module.cpp diff --git a/httpserver/Module.h b/src/Module.h similarity index 100% rename from httpserver/Module.h rename to src/Module.h diff --git a/httpserver/RawData.h b/src/RawData.h similarity index 100% rename from httpserver/RawData.h rename to src/RawData.h diff --git a/httpserver/RequestParameters.cpp b/src/RequestParameters.cpp similarity index 100% rename from httpserver/RequestParameters.cpp rename to src/RequestParameters.cpp diff --git a/httpserver/RequestParameters.h b/src/RequestParameters.h similarity index 100% rename from httpserver/RequestParameters.h rename to src/RequestParameters.h diff --git a/httpserver/Server.cpp b/src/Server.cpp similarity index 98% rename from httpserver/Server.cpp rename to src/Server.cpp index 0c9f455..52b2084 100644 --- a/httpserver/Server.cpp +++ b/src/Server.cpp @@ -665,9 +665,9 @@ namespace HttpServer Utils::raw_pair *raw_pair_data = nullptr; Utils::raw_fileinfo *raw_fileinfo_files = nullptr; - Utils::stlUnorderedMultimapToRawPairs(&raw_pair_params, rp.incoming_params); - Utils::stlUnorderedMapToRawPairs(&raw_pair_headers, rp.incoming_headers); - Utils::stlUnorderedMultimapToRawPairs(&raw_pair_data, rp.incoming_data); + Utils::stlToRawPairs(&raw_pair_params, rp.incoming_params); + Utils::stlToRawPairs(&raw_pair_headers, rp.incoming_headers); + Utils::stlToRawPairs(&raw_pair_data, rp.incoming_data); Utils::filesIncomingToRawFilesInfo(&raw_fileinfo_files, rp.incoming_files); server_request request { @@ -902,9 +902,15 @@ namespace HttpServer std::string connection_out = it_out_connection->second; Utils::tolower(connection_out, loc); - if ("keep-alive" == connection_in) + auto const incoming_params = Utils::explode(connection_in, ','); + + auto const it = std::find(incoming_params.cbegin(), incoming_params.cend(), connection_out); + + if (incoming_params.cend() != it) { - if ("keep-alive" == connection_out) + const std::string &inc = *it; + + if ("keep-alive" == inc) { --rp.keep_alive_count; @@ -913,10 +919,7 @@ namespace HttpServer rp.connection_params |= CONNECTION_KEEP_ALIVE; } } - } - else if ("upgrade" == connection_in) - { - if ("upgrade" == connection_out) + else if ("upgrade" == inc) { rp.connection_params |= CONNECTION_UPGRADE; } @@ -926,12 +929,12 @@ namespace HttpServer bool Server::isConnectionKeepAlive(const struct request_parameters &rp) { - return (rp.connection_params & CONNECTION_KEEP_ALIVE) > 0; + return (rp.connection_params & CONNECTION_KEEP_ALIVE) == CONNECTION_KEEP_ALIVE; } bool Server::isConnectionUpgrade(const struct request_parameters &rp) { - return (rp.connection_params & CONNECTION_UPGRADE) > 0; + return (rp.connection_params & CONNECTION_UPGRADE) == CONNECTION_UPGRADE; } /** diff --git a/httpserver/Server.h b/src/Server.h similarity index 100% rename from httpserver/Server.h rename to src/Server.h diff --git a/httpserver/ServerApplicationDefaultSettings.h b/src/ServerApplicationDefaultSettings.h similarity index 100% rename from httpserver/ServerApplicationDefaultSettings.h rename to src/ServerApplicationDefaultSettings.h diff --git a/httpserver/ServerApplicationSettings.h b/src/ServerApplicationSettings.h similarity index 100% rename from httpserver/ServerApplicationSettings.h rename to src/ServerApplicationSettings.h diff --git a/httpserver/ServerApplicationsTree.cpp b/src/ServerApplicationsTree.cpp similarity index 96% rename from httpserver/ServerApplicationsTree.cpp rename to src/ServerApplicationsTree.cpp index 668c72c..a1ad336 100644 --- a/httpserver/ServerApplicationsTree.cpp +++ b/src/ServerApplicationsTree.cpp @@ -87,7 +87,7 @@ namespace HttpServer } else { - std::string part = nameParts.back(); + const std::string part = std::move(nameParts.back() ); nameParts.pop_back(); @@ -144,7 +144,7 @@ namespace HttpServer { for (auto &node : list) { - ServerApplicationsTree *tree = node.second; + const ServerApplicationsTree *tree = node.second; if (nullptr != tree->app_sets) { diff --git a/httpserver/ServerApplicationsTree.h b/src/ServerApplicationsTree.h similarity index 100% rename from httpserver/ServerApplicationsTree.h rename to src/ServerApplicationsTree.h diff --git a/httpserver/ServerRequest.h b/src/ServerRequest.h similarity index 100% rename from httpserver/ServerRequest.h rename to src/ServerRequest.h diff --git a/httpserver/ServerResponse.h b/src/ServerResponse.h similarity index 100% rename from httpserver/ServerResponse.h rename to src/ServerResponse.h diff --git a/httpserver/SignalsHandles.cpp b/src/SignalsHandles.cpp similarity index 97% rename from httpserver/SignalsHandles.cpp rename to src/SignalsHandles.cpp index 93a68b1..93eca62 100644 --- a/httpserver/SignalsHandles.cpp +++ b/src/SignalsHandles.cpp @@ -1,6 +1,10 @@  #include "SignalsHandles.h" +#include + +HttpServer::Server *globalServerPtr = nullptr; + void handlerSigTerm(int sig) { if (globalServerPtr) diff --git a/httpserver/SignalsHandles.h b/src/SignalsHandles.h similarity index 77% rename from httpserver/SignalsHandles.h rename to src/SignalsHandles.h index 88cba66..5f6a9b1 100644 --- a/httpserver/SignalsHandles.h +++ b/src/SignalsHandles.h @@ -1,6 +1,7 @@ #pragma once #include "Server.h" +#include "System.h" #ifdef WIN32 #include @@ -10,8 +11,4 @@ extern char myWndClassName[]; #endif -#include - -extern HttpServer::Server *globalServerPtr; - int bindSignalsHandles(HttpServer::Server *server); diff --git a/httpserver/Socket.cpp b/src/Socket.cpp similarity index 97% rename from httpserver/Socket.cpp rename to src/Socket.cpp index 7c05d1c..2cfd5c6 100644 --- a/httpserver/Socket.cpp +++ b/src/Socket.cpp @@ -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,14 +81,14 @@ namespace HttpServer int Socket::bind(const int port) const { - ::sockaddr_in sock_addr = { + const ::sockaddr_in sock_addr = { AF_INET, htons(port), ::htonl(INADDR_ANY), 0 }; - return ::bind(socket_handle, reinterpret_cast(&sock_addr), sizeof(sockaddr_in) ); + return ::bind(socket_handle, reinterpret_cast(&sock_addr), sizeof(sockaddr_in) ); } int Socket::listen() const diff --git a/httpserver/Socket.h b/src/Socket.h similarity index 100% rename from httpserver/Socket.h rename to src/Socket.h diff --git a/httpserver/SocketList.cpp b/src/SocketList.cpp similarity index 81% rename from httpserver/SocketList.cpp rename to src/SocketList.cpp index 6e17842..a9e3ec8 100644 --- a/httpserver/SocketList.cpp +++ b/src/SocketList.cpp @@ -63,6 +63,17 @@ namespace HttpServer } } + bool SocketList::is_created() const + { + #ifdef WIN32 + return INVALID_HANDLE_VALUE != this->obj_list; + #elif POSIX + return std::numeric_limits::max() != this->obj_list; + #else + #error "Undefine platform" + #endif + } + bool SocketList::addSocket(const Socket &sock) { if (false == is_created() ) @@ -149,9 +160,9 @@ namespace HttpServer for (size_t i = 0; i < this->poll_events.size(); ++i) { - WSAPOLLFD &event = this->poll_events[i]; + const WSAPOLLFD &event = this->poll_events[i]; - if (event.revents & POLLRDNORM) + if (POLLRDNORM == (event.revents & POLLRDNORM) ) { System::native_socket_type client_socket = ~0; @@ -179,9 +190,9 @@ namespace HttpServer for (size_t i = 0; i < count; ++i) { - epoll_event &event = this->epoll_events[i]; + const epoll_event &event = this->epoll_events[i]; - if (event.events & EPOLLIN) + if (EPOLLIN == (event.events & EPOLLIN) ) { System::native_socket_type client_socket = ~0; @@ -207,7 +218,7 @@ namespace HttpServer return false; } - bool SocketList::recv(std::vector &sockets, std::vector &disconnected) const + bool SocketList::recv(std::vector &sockets, std::vector &disconnected, std::chrono::milliseconds timeout) const { if (false == is_created() ) { @@ -215,7 +226,7 @@ namespace HttpServer } #ifdef WIN32 - const size_t count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), ~0); + const size_t count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), timeout.count() ); if (SOCKET_ERROR == count) { @@ -224,21 +235,21 @@ namespace HttpServer for (size_t i = 0; i < this->poll_events.size(); ++i) { - WSAPOLLFD &event = this->poll_events[i]; + const WSAPOLLFD &event = this->poll_events[i]; - if (event.revents & POLLHUP) + if (POLLRDNORM == (event.revents & POLLRDNORM) ) { - disconnected.emplace_back(Socket(event.fd) ); + sockets.emplace_back(Socket(event.fd) ); } - else if (event.revents & POLLRDNORM) + else if (POLLHUP == (event.revents & POLLHUP) ) { - sockets.emplace_back(Socket(event.fd) ); + disconnected.emplace_back(Socket(event.fd) ); } } - return false == sockets.empty(); + return false == sockets.empty() || false == disconnected.empty(); #elif POSIX - const size_t count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), ~0); + const size_t count = ::epoll_wait(this->obj_list, this->epoll_events.data(), this->epoll_events.size(), timeout.count() ); if (std::numeric_limits::max() == count) { @@ -247,19 +258,19 @@ namespace HttpServer for (size_t i = 0; i < count; ++i) { - epoll_event &event = this->epoll_events[i]; + const epoll_event &event = this->epoll_events[i]; - if (event.events & EPOLLRDHUP) + if (EPOLLIN == (event.events & EPOLLIN) ) { - disconnected.emplace_back(Socket(event.data.fd) ); + sockets.emplace_back(Socket(event.data.fd) ); } - else if (event.events & EPOLLIN) + else if (EPOLLRDHUP == (event.events & EPOLLRDHUP) ) { - sockets.emplace_back(Socket(event.data.fd) ); + disconnected.emplace_back(Socket(event.data.fd) ); } } - return false == sockets.empty(); + return false == sockets.empty() || false == disconnected.empty(); #else #error "Undefine platform" #endif diff --git a/httpserver/SocketList.h b/src/SocketList.h similarity index 66% rename from httpserver/SocketList.h rename to src/SocketList.h index c731ea5..259571a 100644 --- a/httpserver/SocketList.h +++ b/src/SocketList.h @@ -20,25 +20,16 @@ namespace HttpServer public: SocketList(); - bool create(const size_t = 0); + bool create(const size_t = 1); void destroy(); - inline bool is_created() const - { - #ifdef WIN32 - return INVALID_HANDLE_VALUE != this->obj_list; - #elif POSIX - return std::numeric_limits::max() != this->obj_list; - #else - #error "Undefine platform" - #endif - } + bool is_created() const; bool addSocket(const Socket &); bool removeSocket(const Socket &); bool accept(std::vector &sockets) const; - bool recv(std::vector &sockets, std::vector &errors) const; + bool recv(std::vector &sockets, std::vector &errors, std::chrono::milliseconds timeout = std::chrono::milliseconds(~0) ) const; }; }; \ No newline at end of file diff --git a/httpserver/System.cpp b/src/System.cpp similarity index 71% rename from httpserver/System.cpp rename to src/System.cpp index 446789c..8faf1b5 100644 --- a/httpserver/System.cpp +++ b/src/System.cpp @@ -1,6 +1,12 @@  #include "System.h" +#include + +#ifdef WIN32 + char myWndClassName[] = "WndClassNameConstant"; +#endif + namespace System { #ifdef WIN32 @@ -20,11 +26,11 @@ namespace System if (process_id == ed.process_id && ::GetConsoleWindow() != hWnd) { - char class_name[65] = {0}; + std::array class_name; - ::GetClassName(hWnd, class_name, 64); + ::GetClassName(hWnd, class_name.data(), class_name.size() - 1); - if (0 == ::strcmp(class_name, myWndClassName) ) + if (0 == ::strcmp(class_name.data(), myWndClassName) ) { ed.hWnd = hWnd; @@ -41,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) { @@ -59,9 +65,9 @@ namespace System std::string getTempDir() { #ifdef WIN32 - std::vector buf(MAX_PATH + 1); + std::array buf; - const size_t len = ::GetTempPath(MAX_PATH + 1, buf.data() ); + const size_t len = ::GetTempPath(buf.size(), buf.data() ); return std::string(buf.cbegin(), buf.cbegin() + len); #elif POSIX @@ -85,6 +91,31 @@ namespace System #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 @@ -97,6 +128,7 @@ namespace System if (false == ::GetFileSizeEx(hFile, reinterpret_cast<::PLARGE_INTEGER>(fileSize) ) ) { + ::CloseHandle(hFile); return false; } diff --git a/httpserver/System.h b/src/System.h similarity index 95% rename from httpserver/System.h rename to src/System.h index 13afd4e..9fd5d7e 100644 --- a/httpserver/System.h +++ b/src/System.h @@ -2,7 +2,7 @@ #ifdef WIN32 #include - extern char myWndClassName[]; + char myWndClassName[]; #ifdef SIGTERM #undef SIGTERM @@ -79,5 +79,7 @@ namespace System std::string getTempDir(); + bool isFileExists(const std::string &fileName); + bool getFileSizeAndTimeGmt(const std::string &, size_t *, time_t *); }; \ No newline at end of file diff --git a/httpserver/Utils.cpp b/src/Utils.cpp similarity index 70% rename from httpserver/Utils.cpp rename to src/Utils.cpp index 6e3e9ec..406f810 100644 --- a/httpserver/Utils.cpp +++ b/src/Utils.cpp @@ -1,6 +1,7 @@  #include "Utils.h" +#include #include #include @@ -18,6 +19,30 @@ 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) { const size_t length = str.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) @@ -197,21 +144,20 @@ namespace Utils } const size_t str_mon_length = 64; - char *s_mon = new char[str_mon_length]; - ::memset(s_mon, 0, str_mon_length); + std::vector s_mon(str_mon_length); struct ::tm tc = {0}; // Parse RFC 822 #ifdef WIN32 - if (~0 != ::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 (~0 != ::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.cend() != it_mon) { @@ -219,8 +165,6 @@ namespace Utils } } - delete[] s_mon; - tc.tm_isdst = -1; return ::mktime(&tc); @@ -228,7 +172,7 @@ namespace Utils std::string getDatetimeAsString(const ::time_t tTime, const bool isGmtTime) { - char buf[64]; + std::array buf; ::time_t cur_time = tTime; @@ -250,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/httpserver/Utils.h b/src/Utils.h similarity index 69% rename from httpserver/Utils.h rename to src/Utils.h index 2afdbca..e91e6ff 100644 --- a/httpserver/Utils.h +++ b/src/Utils.h @@ -25,6 +25,8 @@ namespace Utils void trim(std::string &); + std::vector explode(const std::string &str, const char sep); + inline std::string getUniqueName() { std::stringstream s; @@ -62,16 +64,9 @@ namespace Utils } } - 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); From f9e937f9bb1308554654153eaafdc70dfbd53abe Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Sat, 14 Nov 2015 14:12:09 +0300 Subject: [PATCH 08/50] Fixed: loading DLL dependencies for Windows For finding the module dependencies added the directory of loaded library --- projects/msvs/httpserver.v12.suo | Bin 150528 -> 151040 bytes src/Module.cpp | 32 ++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/projects/msvs/httpserver.v12.suo b/projects/msvs/httpserver.v12.suo index b99d32d0d7643c634b09b5ce85c5ccb1046e1f2e..a01464f212aa082826e6e4f4e0dcaea9f7c80f03 100644 GIT binary patch delta 886 zcmZ`%Ur19?7(d_Hb>7*WI_J#ml%;MB{|?b%U}4V6qI958#2z%4)bh`$YZOQ>kbH1~ z-lHBZp&GFVU$U;amx4X`;8P^oYe-nogG9845YoOoC-l;R-~GPt_x<^O=W@dHhVY_c z%IzSBCzp^6^Z~KAzrU~1nvXQG#i#Xj7^Xwb3LO+3HQqq!29&5H`YvGWI^XFdSc5J5 zmb5jYEl&G39Fl{+8Sw{eN-@@_b6IFLttTAk=Nk&rC0rd5>O}QrmLC*TQeTSn(hqgl z)S+YTmQm4(v9=ZKEO)6%ixHw0sz_b~aUrS6XbC1uK2h62+a*OLrEa!PtC?IpE^bp~ z@kHG;DhW!%x{!_0L0N-O%*P-vO>nspBC#f*bM?@Ej3GONm_^JXwC(57E+7DJw)eW1 zL$rcMJyfxKRj=zEDE2n75Yw8ZrjXHyPCvWv>J+s9b|C876vTAElP92?joGSI`Dg@K zqO6Nc*TAL@*G?PWRJMa)JnWLIB8oFW9l-jXwecxE9e~wSAW&6k3g_^(n;`L?8&J)+ zCeibCg2?0+S^a%(DW9!vNPMdo{Jdcnf-LmCk}WSWb-@rzbi$z|WS9iWb<#&sG0dOg51NiY-W=u+>uC`$X{1^4Ukx-H{sM^I1Qh@P delta 1064 zcmZuvT}+c_6z)0wTKdP&N~wrYl?>L-iUom~4j2qC8c14yn8WD>3jS3HUt(+AOl%hu zFARy;qrAhIrB=tqu7odxU3kG{7sSNru6DO9-kAjx9la1E^}L^7jWM3&$@@Of`+VoT z@A*#prak?meKORDCL=0LCWW`aST7U`QZ+NG83^=4)0eaAX~^K1Yvkdj9^YTUe$yg- zhv(q}nK15EZY_8a2YydGeDV{mDdIAm~AEuO7KapVJ2 zQD3K@o%>;(UY5SHZeq{n6>Y67YF6yLr&y;SPEpbwv&kdb1YJ5wd3Opb98O^cgdkp=gQV1mtRzxh;QyO+McC&KlTblTDGoM=vl;Nq@|? zm8oo=E*+)3KWYbQ+fdXFQ!)^v-R6)>zJ^sjavhla6f@xwEH%;baMP?h3OPT{?TUbi zbi!|$nuy|Nr=Ip(N_t~@@v@?Hkn-LX3{rB#MO;R0ZM)S0H#F$FSWcc_6WUPpmr7dw zJ5H0&Kc~lcykap3HmzlN#wvCK3?LGUEdzcRIb0^@F2?>eGXnn>O*R9li4* zSV6cXo^_xqzTXLP5ov>6^R4g?h!+ahXR4Q#jmA@Gwfd1*+5w%y-3B3Xw-qYHfQ9cE zQt-YwYr)Hz`iMRu*Z7O;48ia)z?f6nl=ayo0y4f{>NPi0!na3hWRX&}L2H0F0SB%5 zqDqa_cw8v4d19s={+w#TZfAi1o}3Ab>6Z9CjByIpm5cw{uu5e6&?8n_cp@xhHd41MR`p - namespace HttpServer { Module::Module(): lib_handle(nullptr) @@ -33,7 +31,35 @@ namespace HttpServer } #ifdef WIN32 - lib_handle = ::LoadLibrary(libPath.c_str() ); + const size_t pos_slash = libPath.rfind('\\'); + const size_t pos_slash_back = libPath.rfind('/'); + + size_t pos = std::string::npos; + + if (pos_slash != std::string::npos && pos_slash > pos_slash_back) + { + pos = pos_slash; + } + else if (pos_slash_back != std::string::npos) + { + pos = pos_slash_back; + } + + DLL_DIRECTORY_COOKIE cookie = nullptr; + + if (std::string::npos != pos) + { + std::wstring directory(libPath.cbegin(), libPath.cbegin() + pos + 1); + + cookie = ::AddDllDirectory(directory.data() ); + } + + lib_handle = ::LoadLibraryEx(libPath.c_str(), 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + + if (cookie) + { + ::RemoveDllDirectory(cookie); + } #elif POSIX lib_handle = ::dlopen(libPath.c_str(), RTLD_NOW | RTLD_LOCAL); #else From 04bcfac76e1ade729ce22131b06cc980829c303b Mon Sep 17 00:00:00 2001 From: awwit Date: Sat, 14 Nov 2015 14:22:23 +0300 Subject: [PATCH 09/50] Fix to POSIX system Returned to output error messages --- src/Module.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Module.cpp b/src/Module.cpp index 91722fb..6bd9816 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -1,6 +1,8 @@  #include "Module.h" +#include + namespace HttpServer { Module::Module(): lib_handle(nullptr) From 927ea1af382c0453d0b0eaa9b4984b92fbaa6554 Mon Sep 17 00:00:00 2001 From: awwit Date: Mon, 16 Nov 2015 01:29:21 +0300 Subject: [PATCH 10/50] Added parameter names in the header files (*.h) --- projects/qt-creator/httpserver.pro | 12 ++-- projects/qt-creator/httpserver.pro.user | 4 +- src/ConfigParser.cpp | 2 +- src/ConfigParser.h | 6 +- src/DataVariantAbstract.h | 14 ++--- src/DataVariantFormUrlencoded.h | 6 +- src/DataVariantMultipartFormData.h | 22 +++---- src/DataVariantTextPlain.h | 6 +- src/Event.cpp | 9 +-- src/Event.h | 8 +-- src/FileIncoming.cpp | 10 ++-- src/FileIncoming.h | 7 ++- src/Module.cpp | 20 +++---- src/Module.h | 16 +++--- src/Server.h | 40 ++++++------- src/ServerApplicationsTree.cpp | 76 ++++++++++++------------- src/ServerApplicationsTree.h | 10 ++-- src/Socket.cpp | 42 +++++++------- src/Socket.h | 32 +++++------ src/SocketList.cpp | 14 ++--- src/SocketList.h | 6 +- src/System.h | 2 +- src/Utils.h | 20 +++---- 23 files changed, 189 insertions(+), 195 deletions(-) diff --git a/projects/qt-creator/httpserver.pro b/projects/qt-creator/httpserver.pro index 3c1b4de..6efeaea 100644 --- a/projects/qt-creator/httpserver.pro +++ b/projects/qt-creator/httpserver.pro @@ -14,13 +14,13 @@ unix { CONFIG(debug, debug|release):DEFINES += DEBUG -CONFIG(release, debug|release) -{ - QMAKE_CFLAGS_RELEASE -= -O - QMAKE_CFLAGS_RELEASE -= -O1 - QMAKE_CFLAGS_RELEASE *= -O2 +#CONFIG(release, debug|release) +#{ +# QMAKE_CFLAGS_RELEASE -= -O +# QMAKE_CFLAGS_RELEASE -= -O1 +# QMAKE_CFLAGS_RELEASE -= -O2 # QMAKE_CFLAGS_RELEASE *= -O3 -} +#} LIBS += -ldl -pthread diff --git a/projects/qt-creator/httpserver.pro.user b/projects/qt-creator/httpserver.pro.user index 535e1d7..3f141bc 100644 --- a/projects/qt-creator/httpserver.pro.user +++ b/projects/qt-creator/httpserver.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/ConfigParser.cpp b/src/ConfigParser.cpp index bb0ab25..1886d2c 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -12,7 +12,7 @@ namespace HttpServer /** * Config - include file */ - bool ConfigParser::includeConfigFile(const std::string &fileName, std::string &strBuf, const std::size_t offset = 0) + bool ConfigParser::includeConfigFile(const std::string &fileName, std::string &strBuf, const std::size_t offset) { std::ifstream file(fileName); diff --git a/src/ConfigParser.h b/src/ConfigParser.h index 0b5812f..db92c20 100644 --- a/src/ConfigParser.h +++ b/src/ConfigParser.h @@ -12,11 +12,11 @@ namespace HttpServer class ConfigParser { private: - bool includeConfigFile(const std::string &, std::string &, const size_t); + bool includeConfigFile(const std::string &fileName, std::string &strBuf, const size_t offset = 0); bool addApplication( - const std::unordered_map &, - const ServerApplicationDefaultSettings &, + const std::unordered_map &app, + const ServerApplicationDefaultSettings &defaults, std::vector &modules, ServerApplicationsTree &apps_tree ); diff --git a/src/DataVariantAbstract.h b/src/DataVariantAbstract.h index 6b287d9..c6e7344 100644 --- a/src/DataVariantAbstract.h +++ b/src/DataVariantAbstract.h @@ -23,19 +23,19 @@ namespace HttpServer virtual ~DataVariantAbstract() = default; /** - * @param const Socket & - сокет, откуда можно достать остальные данные - * @param std::string & - первая часть полученных данных - * @param const size_t - сколько осталось данных (в байтах) получить из сокета - * @param const std::unordered_map & - дополнительные параметры, описывающие формат данных - * @param request_data & - данные текущего запроса (заголовки, параметры, коллекции для хранения данных) + * @param const Socket &sock - сокет, откуда можно достать остальные данные + * @param std::string &str - первая часть полученных данных + * @param const size_t leftBytes - сколько осталось данных (в байтах) получить из сокета + * @param const std::unordered_map &contentParams - дополнительные параметры, описывающие формат данных + * @param request_data &rp - данные текущего запроса (заголовки, параметры, коллекции для хранения данных) * * @return bool - (true|false) - удачно ли были разобраны данные */ virtual bool parse ( const Socket &sock, - std::string &, - const size_t, + std::string &str, + const size_t leftBytes, std::unordered_map &contentParams, struct request_parameters &rp ) = 0; diff --git a/src/DataVariantFormUrlencoded.h b/src/DataVariantFormUrlencoded.h index 86d8ad3..9b9d641 100644 --- a/src/DataVariantFormUrlencoded.h +++ b/src/DataVariantFormUrlencoded.h @@ -12,9 +12,9 @@ namespace HttpServer public: virtual bool parse ( - const Socket &, - std::string &, - const size_t, + const Socket &sock, + std::string & str, + const size_t leftBytes, std::unordered_map &contentParams, struct request_parameters &rp ) override; diff --git a/src/DataVariantMultipartFormData.h b/src/DataVariantMultipartFormData.h index 75615d4..bef44f1 100644 --- a/src/DataVariantMultipartFormData.h +++ b/src/DataVariantMultipartFormData.h @@ -12,22 +12,22 @@ namespace HttpServer protected: bool append ( - const Socket &, - const std::chrono::milliseconds &, - std::vector &, - std::string &, - const std::string &, - const size_t &, - size_t &, - size_t & + const Socket &sock, + const std::chrono::milliseconds &timeout, + std::vector &buf, + std::string &str_buf, + const std::string &data_end, + const size_t &leftBytes, + size_t &recv_len, + size_t &read_len ) const; public: virtual bool parse ( - const Socket &, - std::string &, - const size_t, + const Socket &sock, + std::string &str, + const size_t leftBytes, std::unordered_map &contentParams, struct request_parameters &rp ) override; diff --git a/src/DataVariantTextPlain.h b/src/DataVariantTextPlain.h index 90f469b..28c1bcc 100644 --- a/src/DataVariantTextPlain.h +++ b/src/DataVariantTextPlain.h @@ -12,9 +12,9 @@ namespace HttpServer public: virtual bool parse ( - const Socket &, - std::string &, - const size_t, + const Socket &sock, + std::string &str, + const size_t leftBytes, std::unordered_map &contentParams, struct request_parameters &rp ) override; diff --git a/src/Event.cpp b/src/Event.cpp index 7e919c1..ded36e6 100644 --- a/src/Event.cpp +++ b/src/Event.cpp @@ -52,7 +52,6 @@ namespace HttpServer void Event::notify() { - // std::unique_lock lck(mtx); signaled = true; cv.notify_all(); } @@ -61,8 +60,6 @@ namespace HttpServer { if (threadsCount) { - // std::unique_lock lck(mtx); - signaled = true; for (size_t i = 0; i < threadsCount; ++i) @@ -74,15 +71,11 @@ namespace HttpServer void Event::reset() { - // std::unique_lock lck(mtx); - signaled = false; } - bool Event::notifed() + bool Event::notifed() const { - // std::unique_lock lck(mtx); - return signaled; } }; \ No newline at end of file diff --git a/src/Event.h b/src/Event.h index f20cec5..5f40862 100644 --- a/src/Event.h +++ b/src/Event.h @@ -20,14 +20,14 @@ namespace HttpServer public: void wait(); - bool wait_for(const std::chrono::milliseconds &); - bool wait_until(const std::chrono::high_resolution_clock::time_point &); + bool wait_for(const std::chrono::milliseconds &ms); + bool wait_until(const std::chrono::high_resolution_clock::time_point &tp); void notify(); - void notify(const size_t); + void notify(const size_t threadsCount); void reset(); - bool notifed(); + bool notifed() const; }; }; \ No newline at end of file diff --git a/src/FileIncoming.cpp b/src/FileIncoming.cpp index 04b5975..1526735 100644 --- a/src/FileIncoming.cpp +++ b/src/FileIncoming.cpp @@ -11,16 +11,16 @@ 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 diff --git a/src/FileIncoming.h b/src/FileIncoming.h index 75df66c..6c6fa97 100644 --- a/src/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/src/Module.cpp b/src/Module.cpp index 6bd9816..ed10b38 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -15,14 +15,14 @@ namespace HttpServer open(libPath); } - Module::Module(const Module &module) : lib_handle(module.lib_handle) + Module::Module(const Module &obj) : lib_handle(obj.lib_handle) { } - Module::Module(Module &&module) : lib_handle(module.lib_handle) + Module::Module(Module &&obj) : lib_handle(obj.lib_handle) { - module.lib_handle = nullptr; + obj.lib_handle = nullptr; } bool Module::open(const std::string &libPath) @@ -143,27 +143,27 @@ namespace HttpServer return false; } - Module &Module::operator =(const Module &module) + Module &Module::operator =(const Module &obj) { - if (*this != module) + if (*this != obj) { close(); - lib_handle = module.lib_handle; + lib_handle = obj.lib_handle; } return *this; } - Module &Module::operator =(Module &&module) + Module &Module::operator =(Module &&obj) { - if (*this != module) + if (*this != obj) { close(); - lib_handle = module.lib_handle; + lib_handle = obj.lib_handle; - module.lib_handle = nullptr; + obj.lib_handle = nullptr; } return *this; diff --git a/src/Module.h b/src/Module.h index 010b960..295e6ac 100644 --- a/src/Module.h +++ b/src/Module.h @@ -26,8 +26,8 @@ namespace HttpServer public: Module(); Module(const std::string &libPath); - Module(const Module &module); - Module(Module &&module); + Module(const Module &obj); + Module(Module &&obj); ~Module() = default; @@ -42,17 +42,17 @@ namespace HttpServer bool find(const std::string &symbolName, void *(**addr)(void *) ) const; bool find(const char *symbolName, void *(**addr)(void *) ) const; - inline bool operator ==(const Module &module) const + inline bool operator ==(const Module &obj) const { - return lib_handle == module.lib_handle; + return lib_handle == obj.lib_handle; } - inline bool operator !=(const Module &module) const + inline bool operator !=(const Module &obj) const { - return lib_handle != module.lib_handle; + return lib_handle != obj.lib_handle; } - Module &operator =(const Module &); - Module &operator =(Module &&); + Module &operator =(const Module &obj); + Module &operator =(Module &&obj); }; }; \ No newline at end of file diff --git a/src/Server.h b/src/Server.h index ec8caed..66df32c 100644 --- a/src/Server.h +++ b/src/Server.h @@ -49,9 +49,9 @@ namespace HttpServer static const int CONNECTION_UPGRADE = 2; protected: - int cycleQueue(std::queue &); + int cycleQueue(std::queue &sockets); - int threadRequestProc(Socket) const; + int threadRequestProc(Socket clientSocket) const; static bool getRequest(Socket clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp); @@ -70,7 +70,7 @@ namespace HttpServer static bool isConnectionKeepAlive(const struct request_parameters &rp); static bool isConnectionUpgrade(const struct request_parameters &rp); - void threadRequestCycle(std::queue &) const; + void threadRequestCycle(std::queue &sockets) const; std::string getMimeTypeByFileName(const std::string &fileName) const; @@ -83,27 +83,27 @@ namespace HttpServer ) const; int transferFilePart( - const Socket &, - const std::chrono::milliseconds &, - const std::string &, - const time_t, - const size_t, - const std::string &, - const std::string &, - const std::string &, - const bool + const Socket &clientSocket, + const std::chrono::milliseconds &timeout, + const std::string &fileName, + const time_t fileTime, + const size_t fileSize, + const std::string &rangeHeader, + const std::string &connectionHeader, + const std::string &dateHeader, + const bool headersOnly ) const; int transferFile( - const Socket &, - const std::string &, - const std::string &, - const bool, + const Socket &clientSocket, + const std::string &fileName, + const std::string &connectionHeader, + const bool headersOnly, struct request_parameters &rp ) const; - static bool parseIncomingVars(std::unordered_multimap &, const std::string &); - static void sendStatus(const Socket &, const std::chrono::milliseconds &, const size_t); + static bool parseIncomingVars(std::unordered_multimap ¶ms, const std::string &uriParams); + static void sendStatus(const Socket &clientSocket, const std::chrono::milliseconds &timeout, const size_t statusCode); bool init(); int run(); @@ -112,10 +112,10 @@ namespace HttpServer System::native_processid_type getPidFromFile() const; void updateModules(); - bool updateModule(Module &, std::unordered_set &, const size_t); + bool updateModule(Module &module, std::unordered_set &applications, const size_t moduleIndex); private: - void addDataVariant(DataVariantAbstract *); + void addDataVariant(DataVariantAbstract *dataVariant); public: Server(); diff --git a/src/ServerApplicationsTree.cpp b/src/ServerApplicationsTree.cpp index a1ad336..e548925 100644 --- a/src/ServerApplicationsTree.cpp +++ b/src/ServerApplicationsTree.cpp @@ -13,6 +13,42 @@ namespace HttpServer clear(); } + void ServerApplicationsTree::addApplication(const std::string &name, ServerApplicationSettings *sets) + { + std::vector name_parts; + + size_t delimiter = name.find('.'); + + if (std::string::npos != delimiter) + { + size_t cur_pos = 0; + + while (std::string::npos != delimiter) + { + std::string part = name.substr(cur_pos, delimiter - cur_pos); + + if ("" == part) + { + part = "*"; + } + + name_parts.emplace_back(std::move(part) ); + cur_pos = delimiter + 1; + delimiter = name.find('.', cur_pos); + } + + // Emplace last part + std::string part = name.substr(cur_pos); + name_parts.emplace_back(std::move(part) ); + } + else + { + name_parts.emplace_back(name); + } + + addApplication(name_parts, sets); + } + void ServerApplicationsTree::addApplication(std::vector &nameParts, ServerApplicationSettings *sets) { if (nameParts.empty() ) @@ -43,7 +79,7 @@ namespace HttpServer } } - void ServerApplicationsTree::addApplication(const std::string &name, ServerApplicationSettings *sets) + const ServerApplicationSettings *ServerApplicationsTree::find(const std::string &name) const { std::vector name_parts; @@ -56,18 +92,11 @@ namespace HttpServer while (std::string::npos != delimiter) { std::string part = name.substr(cur_pos, delimiter - cur_pos); - - if ("" == part) - { - part = "*"; - } - name_parts.emplace_back(std::move(part) ); cur_pos = delimiter + 1; delimiter = name.find('.', cur_pos); } - // Emplace last part std::string part = name.substr(cur_pos); name_parts.emplace_back(std::move(part) ); } @@ -76,7 +105,7 @@ namespace HttpServer name_parts.emplace_back(name); } - addApplication(name_parts, sets); + return find(name_parts); } const ServerApplicationSettings *ServerApplicationsTree::find(std::vector &nameParts) const @@ -111,35 +140,6 @@ namespace HttpServer } } - const ServerApplicationSettings *ServerApplicationsTree::find(const std::string &name) const - { - std::vector name_parts; - - size_t delimiter = name.find('.'); - - if (std::string::npos != delimiter) - { - size_t cur_pos = 0; - - while (std::string::npos != delimiter) - { - std::string part = name.substr(cur_pos, delimiter - cur_pos); - name_parts.emplace_back(std::move(part) ); - cur_pos = delimiter + 1; - delimiter = name.find('.', cur_pos); - } - - std::string part = name.substr(cur_pos); - name_parts.emplace_back(std::move(part) ); - } - else - { - name_parts.emplace_back(name); - } - - return find(name_parts); - } - void ServerApplicationsTree::collectApplicationSettings(std::unordered_set &set) const { for (auto &node : list) diff --git a/src/ServerApplicationsTree.h b/src/ServerApplicationsTree.h index 3efdb70..cfb99bd 100644 --- a/src/ServerApplicationsTree.h +++ b/src/ServerApplicationsTree.h @@ -24,13 +24,13 @@ namespace HttpServer return list.empty(); } - void addApplication(const std::string &, ServerApplicationSettings *); - void addApplication(std::vector &, ServerApplicationSettings *); + void addApplication(const std::string &name, ServerApplicationSettings *sets); + void addApplication(std::vector &nameParts, ServerApplicationSettings *sets); - const ServerApplicationSettings *find(const std::string &) const; - const ServerApplicationSettings *find(std::vector &) const; + const ServerApplicationSettings *find(const std::string &name) const; + const ServerApplicationSettings *find(std::vector &nameParts) const; - void collectApplicationSettings(std::unordered_set &) const; + void collectApplicationSettings(std::unordered_set &set) const; void clear(); }; diff --git a/src/Socket.cpp b/src/Socket.cpp index 2cfd5c6..8d4eff0 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -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() @@ -139,7 +139,7 @@ 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 @@ -149,7 +149,7 @@ namespace HttpServer 0 }; - 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) ); } @@ -160,7 +160,7 @@ namespace HttpServer 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) ); } @@ -234,7 +234,7 @@ 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 @@ -244,7 +244,7 @@ namespace HttpServer 0 }; - if (1 == ::WSAPoll(&event, 1, timeWait.count() ) && event.revents & POLLRDNORM) + if (1 == ::WSAPoll(&event, 1, timeout.count() ) && event.revents & POLLRDNORM) { recv_len = ::recv(socket_handle, buf.data(), buf.size(), 0); } @@ -255,7 +255,7 @@ namespace HttpServer 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); } @@ -287,7 +287,7 @@ 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 @@ -297,7 +297,7 @@ namespace HttpServer 0 }; - 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); } @@ -308,7 +308,7 @@ namespace HttpServer 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); } @@ -318,7 +318,7 @@ 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 @@ -328,7 +328,7 @@ namespace HttpServer 0 }; - 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); } @@ -339,7 +339,7 @@ namespace HttpServer 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_NOSIGNAL); } @@ -372,19 +372,19 @@ namespace HttpServer #endif } - Socket &Socket::operator=(const Socket s) + Socket &Socket::operator=(const Socket &obj) { - socket_handle = s.socket_handle; + socket_handle = obj.socket_handle; return *this; } - bool Socket::operator ==(const Socket &sock) const + bool Socket::operator ==(const Socket &obj) const { - return this->socket_handle == sock.socket_handle; + return this->socket_handle == obj.socket_handle; } - bool Socket::operator !=(const Socket &sock) const + bool Socket::operator !=(const Socket &obj) const { - return this->socket_handle != sock.socket_handle; + return this->socket_handle != obj.socket_handle; } }; \ No newline at end of file diff --git a/src/Socket.h b/src/Socket.h index e4939fa..db2c9c3 100644 --- a/src/Socket.h +++ b/src/Socket.h @@ -39,9 +39,9 @@ namespace HttpServer 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; @@ -59,27 +59,27 @@ 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 = true) 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; @@ -88,9 +88,9 @@ namespace HttpServer return socket_handle; } - Socket &operator =(const Socket); + Socket &operator =(const Socket &obj); - bool operator ==(const Socket &sock) const; - bool operator !=(const Socket &sock) const; + bool operator ==(const Socket &obj) const; + bool operator !=(const Socket &obj) const; }; }; \ No newline at end of file diff --git a/src/SocketList.cpp b/src/SocketList.cpp index a9e3ec8..a21cc0f 100644 --- a/src/SocketList.cpp +++ b/src/SocketList.cpp @@ -14,30 +14,30 @@ namespace HttpServer #endif } - bool SocketList::create(const size_t listSize) + bool SocketList::create(const size_t startListSize) { destroy(); #ifdef WIN32 - obj_list = (HANDLE) 1; + this->obj_list = (HANDLE) 1; - if (listSize > 0) + if (startListSize > 0) { - poll_events.reserve(listSize); + this->poll_events.reserve(startListSize); } return true; #elif POSIX - this->obj_list = ::epoll_create(listSize); + this->obj_list = ::epoll_create(startListSize); if (std::numeric_limits::max() == this->obj_list) { return false; } - if (listSize > 0) + if (startListSize > 0) { - this->epoll_events.reserve(listSize); + this->epoll_events.reserve(startListSize); } return true; diff --git a/src/SocketList.h b/src/SocketList.h index 259571a..0e7888d 100644 --- a/src/SocketList.h +++ b/src/SocketList.h @@ -20,13 +20,13 @@ namespace HttpServer public: SocketList(); - bool create(const size_t = 1); + bool create(const size_t startListSize = 1); void destroy(); bool is_created() const; - bool addSocket(const Socket &); - bool removeSocket(const Socket &); + bool addSocket(const Socket &sock); + bool removeSocket(const Socket &sock); bool accept(std::vector &sockets) const; diff --git a/src/System.h b/src/System.h index 9fd5d7e..ef6445e 100644 --- a/src/System.h +++ b/src/System.h @@ -81,5 +81,5 @@ namespace System 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/Utils.h b/src/Utils.h index e91e6ff..a3fab0a 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -23,7 +23,7 @@ namespace Utils } } - void trim(std::string &); + void trim(std::string &str); std::vector explode(const std::string &str, const char sep); @@ -34,7 +34,7 @@ namespace Utils return s.str(); } - char *stlStringToPChar(const std::string &); + char *stlStringToPChar(const std::string &str); template void stlToRawPairs(Utils::raw_pair *raw[], const T &stl) @@ -64,20 +64,20 @@ namespace Utils } } - void filesIncomingToRawFilesInfo(Utils::raw_fileinfo *[], const std::unordered_multimap &); - void rawFilesInfoToFilesIncoming(std::unordered_multimap &, const Utils::raw_fileinfo [], const size_t); + 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 [], const size_t); - void destroyRawFilesInfo(Utils::raw_fileinfo [], const size_t); + 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 &); + 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 &, std::unordered_multimap &); + bool parseCookies(const std::string &cookieHeader, std::unordered_multimap &cookies); - std::string urlEncode(const std::string &); - std::string urlDecode(const std::string &); + std::string urlEncode(const std::string &str); + std::string urlDecode(const std::string &str); }; \ No newline at end of file From dce687b9803bb7cbd466fe2fd8064cd82b1029c7 Mon Sep 17 00:00:00 2001 From: awwit Date: Thu, 17 Dec 2015 19:31:42 +0300 Subject: [PATCH 11/50] Added function for convert bin-data to hex-string (and inversely) into Utils Changed realization of function Utils::getUniqueName() --- projects/qt-creator/httpserver.pro.user | 8 +- src/Utils.cpp | 122 +++++++++++++++++++++++- src/Utils.h | 15 +-- 3 files changed, 134 insertions(+), 11 deletions(-) diff --git a/projects/qt-creator/httpserver.pro.user b/projects/qt-creator/httpserver.pro.user index 3f141bc..2167779 100644 --- a/projects/qt-creator/httpserver.pro.user +++ b/projects/qt-creator/httpserver.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -61,7 +61,7 @@ Desktop Desktop {c77ee4a2-1c2a-4bac-9185-8378ec4ebf5d} - 1 + 0 0 0 @@ -241,11 +241,11 @@ httpserver httpserver2 Qt4ProjectManager.Qt4RunConfiguration:/media/projects/httpserver/projects/qt-creator/httpserver.pro - + --start httpserver.pro false true - + /media/projects/sites/servertest/httpserver/Debug 3768 false true 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 061621d959ea785d7baab8a4b1839b121c6c9726 Mon Sep 17 00:00:00 2001 From: awwit Date: Tue, 22 Dec 2015 00:31:20 +0300 Subject: [PATCH 12/50] Fixed: shutdown of applications when the server fails to initialize --- projects/qt-creator/httpserver.pro.user | 2 +- src/Server.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/projects/qt-creator/httpserver.pro.user b/projects/qt-creator/httpserver.pro.user index 2167779..c6c3f8e 100644 --- a/projects/qt-creator/httpserver.pro.user +++ b/projects/qt-creator/httpserver.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/src/Server.cpp b/src/Server.cpp index 52b2084..ad27d00 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -1151,7 +1151,7 @@ namespace HttpServer module.open(module_name); #elif POSIX - // HACK: for posix system - load new version shared library + // HACK: for posix system — load new version shared library size_t dir_pos = module_name.rfind('/'); size_t ext_pos = module_name.rfind('.'); @@ -1469,6 +1469,7 @@ namespace HttpServer if (this->server_sockets.empty() ) { std::cout << "Error: do not open any socket;" << std::endl; + clear(); return 2; } From 7fdd489f4cfac0065c12a4fc1bec16a1edcb5db1 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Tue, 22 Dec 2015 00:48:23 +0300 Subject: [PATCH 13/50] Fixed: correct cleaning of the structure before using --- projects/msvs/httpserver.vcxproj | 4 ++++ src/Utils.cpp | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/projects/msvs/httpserver.vcxproj b/projects/msvs/httpserver.vcxproj index 175b8af..368b17f 100644 --- a/projects/msvs/httpserver.vcxproj +++ b/projects/msvs/httpserver.vcxproj @@ -151,6 +151,7 @@ true false Level3 + true %(AdditionalDependencies) @@ -189,6 +190,7 @@ true false Level3 + true %(AdditionalDependencies) @@ -228,6 +230,7 @@ false Level3 Disabled + true %(AdditionalDependencies) @@ -266,6 +269,7 @@ false Level3 Disabled + true %(AdditionalDependencies) diff --git a/src/Utils.cpp b/src/Utils.cpp index ac34929..962140f 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -266,7 +266,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 From f54e4912bf2d3ddf615741f7ae5ecdca889496d1 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Tue, 22 Dec 2015 01:46:23 +0300 Subject: [PATCH 14/50] Removed unnecessary dependencies in source code --- projects/msvs/httpserver.v12.suo | Bin 151040 -> 151552 bytes src/Server.cpp | 2 +- src/Utils.cpp | 4 ++++ src/Utils.h | 8 +------- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/projects/msvs/httpserver.v12.suo b/projects/msvs/httpserver.v12.suo index a01464f212aa082826e6e4f4e0dcaea9f7c80f03..183c4bcd5a1d8f2e744eab2fe39cade25191118a 100644 GIT binary patch delta 1677 zcmb7ET}<0m6#t*o4_ctC6d1@y3#@|<+O7TfV=W(}&~5`Uf}&;*Y<#o>ap0OliN?6H z#6%OfW%L^FoK6~Dh%f52iT~HmCB`R%aeMP&K4^SU!;%pVM)2IyPJAHIll*$lJzw|S zbI!j@@9CG)`m4j5Vo8$rDa%?s56iKx6wd0`em`_B(Dg06&k~q~0k(lpvODNvPE@m( zRKw~PieN+CHiJqC1VMTR>guN|NZKaaBGi)n7jZ*g_ZV?wURO@s3_HH>=ItWxdS2EN zuOXBa3bTpAvcFk(6?SsZ!q~$iTUDVHQHDq@sG8F|D-P~;v#78re{<z3Vl`V0Ey z2}>qyxCPo3(&*MRn`K*oIj)72y zu%jzwT7VNQVH(nvkx9%?1j2E)VM;=nB`T8o5GgAOlIU(H^UEHCj!yKj95rNKmS2a| z{(iL>NiN#U68lHgn*5PHwAC|XbrjqzQT=ABHmtLe<-a+b|G+r1P4nZrQi>64wev2^ z5DTeX+B#A!s@P`TS3GzOE19vuE(R>cVx4@V6Av+GgHa4+qAI?4Ha_~@x#Ukj{;I!roL}&_UcP%?8ScPaz{g~4 z;%`uinV>bRO8KoBYt1i^F}AI1QhWB`(&s+J3^r~-s%-&|u|!)Ey4i*;2}fC?{o_ot z|NeFc{U<k-d;MDd9AniExt_oQhM8e$*8j z%41q=EGx9FmD*Pi?Bd~`&teCFWzX38H!765u?X(6bi~MwThPqc%R#4<>G3Vws*LK? z>1J*`f~9=Tg-$lU7UlOHP^!dy*a0xbA9!F$IpxQXRI5%vhK`^@i;-2a$)Je`Tp%l9 z8J>ZGsN|E}QdF9hT+)=}lpK8M(y>nu)>{6|-%0-$SpyYdrnC4ksANIh6~qcnuPnd%jwt;o z00%GjyzRydI6BRj+!$Pa0#V7j5rI29u%4R-u^H67cMyAc(2G;GeLknd?e=*CvK*2{ PD$~f!^otX-^ZkDViAEjm delta 1637 zcmb`{ZA@EL7zgls9&XERp|wJR0j221Ca+t|TI6M55k$Z;y5W48$UvAnMC`U!hf`Z& ziVh6Wqa24bA!Ol$A9T>felj7E7)^}P#Lq?(KbTCTiI6DCI{&9!3?}>NO@2Agx#zj( zzC7pL=%Oil)ifJ0*c3%^aJQDd5}ajoK`lljCfok1mLcbNtcZsx!W#G{9p#@}-P}bg zzmOJC4Y-DPHMsD(PHhXyzTjnD-5fe)JDerSPKcmUeqL1>2# z=!A#B4_$B+x*-6^;JBhhlpX{R!wGl<9)-u?aX1N2KrcKAeQ*l;VE~?jK^TJ5@H9LF z&%zlPhUZ`eo`+F*0fKNA&dFCik01nLcoANL3or&R!$o)nUWL~n0#QI!jeqRD`*O3B zpQG{Hl+=PGSyH}{UfPw1jx1uf-pV*1u`HmBcMe%V8E5XwTR{9F$O3(ps$H< z6@8I0Fgi4H`uxGcV6cG?>?`B0Vq4m-n6Kc>B7YY(+%5lEojmAUe z(}tx|;vUV$ZMnUc0u0JKTt!7`YJ`GM%5zA%UlVUO0}fP=Pbe(5J4l|#Vp%frkC;ArsIk08U@OP>j$=1 zj2@y)aj=G5%hmW3_kTMieyn1diEnDCo{5<*Y7{rTl#?pyvWwAjJ<)tM`^_SYgV|I1 zIdcZYC)F&ADdL!$6^NO`?1b=pnTL;O`x3q;T1)%1m3(T#hr6VSbsx2fpFC77KI@=7 tvF0V;yr0%=b0^zb-;K7Z&dv0jrpd4F;b-^di=r+vC;s%4g)RGu{sBmfw> #include #include -#include +#include namespace HttpServer { diff --git a/src/Utils.cpp b/src/Utils.cpp index 962140f..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 { 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 637f8c8a973ac2fc5b6cb0e8e340c4d2da0b14c2 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Tue, 22 Dec 2015 18:34:19 +0300 Subject: [PATCH 15/50] The code for unicode version of project was added --- projects/msvs/httpserver.v12.suo | Bin 151552 -> 154112 bytes src/Module.cpp | 15 ++++++++++-- src/SignalsHandles.h | 2 +- src/System.cpp | 38 +++++++++++++++++++++++++------ src/System.h | 2 +- 5 files changed, 46 insertions(+), 11 deletions(-) diff --git a/projects/msvs/httpserver.v12.suo b/projects/msvs/httpserver.v12.suo index 183c4bcd5a1d8f2e744eab2fe39cade25191118a..e88b32fe139fa6ed2e79842f69118d1b159eec4d 100644 GIT binary patch delta 3552 zcmeH}Yj9IV6vuP6X-LusNt)6Jlt)_nqA%J~5JDSlfEJ`Jf{I$8PzvQ`V@VKsr3Dq0 zRw0Wnz5xOCgCi1#d~vV{qF;0r9Y;TiIwLra!k}Zv0Tuk8+XPA}j*1`Mncv-W&+grO z_MAQE-nLz)wnL_EbXo0G3UoLLi&WC)&;vo3{k8k zeUjgf*_Y8S0UKoQ4d{meb9l@c?i0}`h2<3Vao`Wkj|uArqE8F!Oz3l|XKhT;8sR=2 z`V24v9!CJ5mtOpywM&Ji+ zARtzl8b18uz@#goUK8v#B#=KAgB&OhZlpy5AGsfZIUMw%fOV0%e-(5-FujAGjC&4x z}7We%nR^$OrtccvZk0e$^7fGy3a$n3?IXuoT&&RCz-yv`w zJH*0nij)nOgFnU@DcS+&HU}@n|8_;R!`_G&{YuY(kZ5)@?`Du%6Psj-UQbw_KFtd{6vG~!_o7EApdugHc+5NOYcH`P0 zeTn{PF0=OFh5Ri}W;Y+|q`@Sh;DI=SZ z4x7V>(aX75OtXK9^x0~(7yn}G2-q^HOpXwPrORg2bJgTI(OiQ!1TT!OCA~GQlipiq z>$Af*1G(Zq48l!)Um^PNR0&R=B`AVsY!1x?c^Q`W+v%e*N0-r!|Y^ zR_7RYylR^yT(n3Y9aa$-a@@%El|QmYvSGYFeh4%?!fhmvI8w60s%-Q*fJ^r%VD0&PaM7M@p+?uzF!fRy z8LWx3FC5JApYnY+$C7j4%U#u1EDvoQN}I^v4jVRs&EO%x9(e?80gr;mz~f*m=m4GI zNx&9uL%$safCM|hQ{ZW!z)tWCcpmV4ZZAOQGaYVkE^ntmsh3iMzS8GNT2f23NZ*}Ufb*@_E#hQC= z3K~70JT-HgaK!Xg^qL{NhPlja^FN9aM?139Yho10_0nAF%k@*e?8fy@=^M2*;7GCt zolU0(4SV-c=j&$z^`@%bTDYRw=z7_e?l7}sxVa_oNwrK9aq6CGk*!jvi8X5C3=wNL z_sr07CWx@CtYbu$d^>&8b;-;rHZH1nifl9dojs=A=p5$ZEI!e57M--mDQI_)%GWJa z56z)e)zD0N>e5S;EO%^Lug;q&Uaj3r=AdPFz`K7aiO`-znrD>d%a$q2bTWiI!|5cc zMX93aQLY|(oo*L}Tn-X3`^!ilx;3A?BII>a$9sp1=&Yb`)wyEofJ?cO;axWMWThxn z#hp|TDlm$ZIqFEI$V}n?$?xnVPri|!KK1bFZ#HBtTv@7lOIi3aWD=ver~Rkqx>ca+Lj@LASsn{4upp)eX!@6_n_9ktRl(DVa<|i; zSx5Gs<5Zjy4Jk7-TyuL%Y1+d|)5;!}n%Yaq9%Q0o-@EK?fN7_5s?#40e)j%m?wxz@ z+?n}}j-7HxhkRXqph6IYFjseF9ci=8anjqx^I6M^Oozy$tcBXi6jwi05+Y|r7Tush z(<|5pAr|pvlp)?@F(_5uV``L%WT>CY#7^YB6buF2MV=Q7x4O}gHsRih{EIvXOAzzsNEbX^F&=nqv{gry{> zh#9CE2dqMuDK(qOTIW~?I~s0bd&5o6*k)40T4L>_n)Tz?!dl|&Vij6P@H6ss5pA|i z5`~+dYv&g&;;3&46Y$`5V1FZQg2$i}HbWOY4o|=qcoMe4Q?L!5hVAeSbi)pC!A^J< zc7Yq7gXiG|L9h!iB6ta2hF4%W^uVj|8tj3+@H*^+{qP3732(vMZ~)$cci}xa2#4T( zI1ESN1Naa=f}`*;e1h?XPZ4|u$KZ4L0*=E8I0;|EDL4&h;4AnVzJYJyJ2(ry&mntNN1M3Rg+2_E2yZ7hNmNQE>= z2YynhHxFvp-$c#vhnLyUobHuBSS_t7%((wZlXqco?Td^2%c2^!EQ^`hl%n8k!#9g0 zC6~~7SUi_lDme{v`7W(TVb17C(!OQ_NF$Lr4yfafSMbHk|+*blDFAmF!C?kzyF7kbf}ER5W#(-iYC#n0wQx(%2<&ucx3K=1cUfK@&D)U|4i;qsty!J zyfXWx83w9%>ucyi;!kV*#{C;{zp?LmIb=%COOQhr0*HW{J|HqVf zfh_L%$5xp1GQKO32AV$ldw@2cP0~-JI!*i4d0ujq(KXaiu&bO_k}*~J75VvhKg6@2 zk;o)6m6l76I(jSXFvSwW#!^j`ZPlWcs~4@DGctinq@G4~6;N49fj-+{D40}~pFh;u zRhjnpB&;6U$3KvtrR}rmEVs-=FNJCOI*guNpkQg|7n>RE`792tm4K@qkA;+r{*Pd; z(Wo|z{;;r(r7==M9aRv6FU>3YekyA%m9tzbN)2^1SK2+D=JVSUGU93_>vWne5BDAG Ix{=b~04Zw2u>b%7 diff --git a/src/Module.cpp b/src/Module.cpp index ed10b38..e2fbff7 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -1,7 +1,11 @@  #include "Module.h" -#include +#ifdef WIN32 + #ifdef UNICODE + #include + #endif +#endif namespace HttpServer { @@ -55,8 +59,15 @@ namespace HttpServer cookie = ::AddDllDirectory(directory.data() ); } + + #ifdef UNICODE + std::wstring_convert> converter; + const std::wstring lib_path = converter.from_bytes(libPath); + #else + const std::string &lib_path = libPath; + #endif - lib_handle = ::LoadLibraryEx(libPath.c_str(), 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + lib_handle = ::LoadLibraryEx(lib_path.c_str(), 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); if (cookie) { diff --git a/src/SignalsHandles.h b/src/SignalsHandles.h index 5f6a9b1..59a9b36 100644 --- a/src/SignalsHandles.h +++ b/src/SignalsHandles.h @@ -8,7 +8,7 @@ #include extern std::thread threadMessageLoop; - extern char myWndClassName[]; + extern ::TCHAR myWndClassName[]; #endif int bindSignalsHandles(HttpServer::Server *server); diff --git a/src/System.cpp b/src/System.cpp index 8faf1b5..67bd452 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -4,7 +4,12 @@ #include #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 85189f7b3900f4b1376d0f704a2be84d1bdf003d Mon Sep 17 00:00:00 2001 From: awwit Date: Tue, 22 Dec 2015 19:08:11 +0300 Subject: [PATCH 16/50] The code of module.cpp was fixed for posix systems --- projects/qt-creator/httpserver.pro.user | 2 +- src/Module.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/projects/qt-creator/httpserver.pro.user b/projects/qt-creator/httpserver.pro.user index c6c3f8e..c51a8df 100644 --- a/projects/qt-creator/httpserver.pro.user +++ b/projects/qt-creator/httpserver.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/src/Module.cpp b/src/Module.cpp index e2fbff7..59ff813 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -5,6 +5,8 @@ #ifdef UNICODE #include #endif +#elif POSIX + #include #endif namespace HttpServer From a976f7a2ebb9b7f7cc0e0d1c535aa9bbe6d441dd Mon Sep 17 00:00:00 2001 From: awwit Date: Sat, 9 Jan 2016 01:04:07 +0300 Subject: [PATCH 17/50] Minor fixes --- projects/qt-creator/httpserver.pro.user | 2 +- src/ConfigParser.cpp | 8 ++-- src/DataVariantMultipartFormData.cpp | 14 +++--- src/DataVariantMultipartFormData.h | 2 +- src/Server.cpp | 16 +++---- src/Server.h | 2 +- src/SignalsHandles.cpp | 7 ++- src/Utils.cpp | 61 +++++++++++++------------ src/Utils.h | 10 +--- 9 files changed, 59 insertions(+), 63 deletions(-) diff --git a/projects/qt-creator/httpserver.pro.user b/projects/qt-creator/httpserver.pro.user index c51a8df..ff53254 100644 --- a/projects/qt-creator/httpserver.pro.user +++ b/projects/qt-creator/httpserver.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 1886d2c..1af4e31 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -42,8 +42,8 @@ namespace HttpServer if (file_size) { - std::vector buf(file_size); - file.read(reinterpret_cast(buf.data() ), file_size); + std::vector buf(file_size); + file.read(buf.data(), file_size); strBuf.insert(strBuf.begin() + offset, buf.cbegin(), buf.cend() ); } @@ -299,9 +299,9 @@ namespace HttpServer const std::string whitespace(" \t\v\f\r"); - std::vector buf(file_size); + std::vector buf(file_size); - file.read(reinterpret_cast(buf.data() ), file_size); + file.read(buf.data(), file_size); const std::string str_buf(buf.cbegin(), buf.cend() ); diff --git a/src/DataVariantMultipartFormData.cpp b/src/DataVariantMultipartFormData.cpp index b94ba02..f4d5008 100644 --- a/src/DataVariantMultipartFormData.cpp +++ b/src/DataVariantMultipartFormData.cpp @@ -15,7 +15,7 @@ namespace HttpServer ( const Socket &sock, const std::chrono::milliseconds &timeout, - std::vector &buf, + std::vector &buf, std::string &str_buf, const std::string &data_end, const size_t &leftBytes, @@ -86,7 +86,7 @@ namespace HttpServer const size_t buf_len = (leftBytes >= 512 * 1024) ? 512 * 1024 : leftBytes; // Создание буферов - std::vector buf(buf_len); + std::vector buf(buf_len); size_t str_cur; // Текущая позиция в буфере @@ -275,7 +275,7 @@ namespace HttpServer if (file.is_open() ) { // Смещение данных в буфере в начало -// str.assign(str.cbegin() + str_cur, str.cend() ); + // str.assign(str.cbegin() + str_cur, str.cend() ); str.erase(str.begin(), str.begin() + str_cur); // Поиск конца блока данных @@ -287,7 +287,7 @@ namespace HttpServer // Добавить данные к значению file.write(str.data(), str.length() - data_end.length() ); -// str.assign(str.cend() - data_end.length(), str.cend() ); + // str.assign(str.cend() - data_end.length(), str.cend() ); str.erase(str.begin(), str.end() - data_end.length() ); // Получить следующий кусок данных @@ -331,7 +331,7 @@ namespace HttpServer std::string value; // Смещение данных в буфере в начало -// str.assign(str.cbegin() + str_cur, str.cend() ); + // str.assign(str.cbegin() + str_cur, str.cend() ); str.erase(str.begin(), str.begin() + str_cur); // Поиск конца блока данных @@ -343,7 +343,7 @@ namespace HttpServer // Добавить данные к значению value.append(str.cbegin(), str.cend() - data_end.length() ); -// str.assign(str.cend() - data_end.length(), str.cend() ); + // str.assign(str.cend() - data_end.length(), str.cend() ); str.erase(str.begin(), str.end() - data_end.length() ); // Получить следующий кусок данных @@ -395,7 +395,7 @@ namespace HttpServer while (std::string::npos == str_cur) { -// str.assign(str.cend() - data_end.length(), str.cend() ); + // str.assign(str.cend() - data_end.length(), str.cend() ); str.erase(str.begin(), str.end() - data_end.length() ); // Получить следующий кусок данных diff --git a/src/DataVariantMultipartFormData.h b/src/DataVariantMultipartFormData.h index bef44f1..f1c9e54 100644 --- a/src/DataVariantMultipartFormData.h +++ b/src/DataVariantMultipartFormData.h @@ -14,7 +14,7 @@ namespace HttpServer ( const Socket &sock, const std::chrono::milliseconds &timeout, - std::vector &buf, + std::vector &buf, std::string &str_buf, const std::string &data_end, const size_t &leftBytes, diff --git a/src/Server.cpp b/src/Server.cpp index 72e0744..53518b4 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -26,7 +26,7 @@ namespace HttpServer std::string file_ext = std::string::npos != ext_pos ? fileName.substr(ext_pos + 1) : ""; std::locale loc; - Utils::tolower(file_ext, loc); + Utils::toLower(file_ext, loc); auto it_mime = this->mimes_types.find(file_ext); @@ -225,7 +225,7 @@ namespace HttpServer { const size_t length = std::get<1>(range); - std::vector buf(length < 512 * 1024 ? length : 512 * 1024); + std::vector buf(length < 512 * 1024 ? length : 512 * 1024); const size_t position = std::get<0>(range); @@ -242,7 +242,7 @@ namespace HttpServer buf.resize(send_size_left); } - file.read(reinterpret_cast(buf.data() ), buf.size() ); + file.read(buf.data(), buf.size() ); send_size = clientSocket.nonblock_send(buf, file.gcount(), timeout); send_size_left -= send_size; @@ -350,7 +350,7 @@ namespace HttpServer // Отправить файл if (false == headersOnly && file_size) { - std::vector buf(file_size < 512 * 1024 ? file_size : 512 * 1024); + std::vector buf(file_size < 512 * 1024 ? file_size : 512 * 1024); size_t send_size; @@ -441,7 +441,7 @@ namespace HttpServer rp.keep_alive_count = 100; const size_t buf_len = 4096; - std::vector buf(buf_len); + std::vector buf(buf_len); std::string str_buf; @@ -516,7 +516,7 @@ namespace HttpServer return rp.app_exit_code; } - bool Server::getRequest(Socket clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp) + bool Server::getRequest(Socket clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp) { // Получить данные запроса от клиента const size_t recv_size = clientSocket.nonblock_recv(buf, rp.timeout); @@ -897,10 +897,10 @@ namespace HttpServer std::locale loc; std::string connection_in = it_in_connection->second; - Utils::tolower(connection_in, loc); + Utils::toLower(connection_in, loc); std::string connection_out = it_out_connection->second; - Utils::tolower(connection_out, loc); + Utils::toLower(connection_out, loc); auto const incoming_params = Utils::explode(connection_in, ','); diff --git a/src/Server.h b/src/Server.h index 66df32c..3e1fb50 100644 --- a/src/Server.h +++ b/src/Server.h @@ -53,7 +53,7 @@ namespace HttpServer int threadRequestProc(Socket clientSocket) const; - static bool getRequest(Socket clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp); + static bool getRequest(Socket clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp); int getRequestHeaders(std::string &str_buf, struct request_parameters &rp) const; diff --git a/src/SignalsHandles.cpp b/src/SignalsHandles.cpp index 93eca62..31a134e 100644 --- a/src/SignalsHandles.cpp +++ b/src/SignalsHandles.cpp @@ -127,10 +127,9 @@ int bindSignalsHandles(HttpServer::Server *server) ::HINSTANCE hInstance = ::GetModuleHandle(nullptr); - ::WNDCLASSEX wcex = { - sizeof(::WNDCLASSEX) - }; + ::WNDCLASSEX wcex = {}; + wcex.cbSize = sizeof(::WNDCLASSEX); wcex.lpfnWndProc = WndProc; wcex.hInstance = hInstance; wcex.lpszClassName = myWndClassName; @@ -148,7 +147,7 @@ int bindSignalsHandles(HttpServer::Server *server) #elif POSIX - struct ::sigaction act = {0}; + struct ::sigaction act = {}; act.sa_handler = handlerSigInt; ::sigaction(SIGINT, &act, nullptr); 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 141a46e18e0c94384beed74216a58fd5430a4639 Mon Sep 17 00:00:00 2001 From: awwit Date: Sun, 10 Jan 2016 19:27:46 +0300 Subject: [PATCH 18/50] Minor fixes #2 --- projects/qt-creator/httpserver.pro | 8 +- projects/qt-creator/httpserver.pro.user | 4 +- src/ConfigParser.h | 6 +- src/DataVariantAbstract.h | 5 +- src/DataVariantMultipartFormData.cpp | 33 ++++--- src/DataVariantMultipartFormData.h | 6 +- src/Event.cpp | 8 +- src/Event.h | 2 +- src/Main.cpp | 15 ++- src/Main.h | 9 +- src/Server.cpp | 95 +++++++++---------- src/Server.h | 7 +- src/ServerApplicationsTree.h | 5 +- ...{SignalsHandles.cpp => SignalHandlers.cpp} | 46 ++++++--- src/SignalHandlers.h | 7 ++ src/SignalsHandles.h | 14 --- src/Socket.cpp | 55 +++++++---- src/Socket.h | 11 ++- src/SocketList.cpp | 42 ++++---- src/SocketList.h | 2 +- src/System.cpp | 9 +- 21 files changed, 198 insertions(+), 191 deletions(-) rename src/{SignalsHandles.cpp => SignalHandlers.cpp} (68%) create mode 100644 src/SignalHandlers.h delete mode 100644 src/SignalsHandles.h diff --git a/projects/qt-creator/httpserver.pro b/projects/qt-creator/httpserver.pro index 6efeaea..2497baa 100644 --- a/projects/qt-creator/httpserver.pro +++ b/projects/qt-creator/httpserver.pro @@ -36,11 +36,11 @@ SOURCES += \ ../../src/RequestParameters.cpp \ ../../src/Server.cpp \ ../../src/ServerApplicationsTree.cpp \ - ../../src/SignalsHandles.cpp \ ../../src/Socket.cpp \ ../../src/SocketList.cpp \ ../../src/System.cpp \ - ../../src/Utils.cpp + ../../src/Utils.cpp \ + ../../src/SignalHandlers.cpp include(deployment.pri) qtcAddDeployment() @@ -63,8 +63,8 @@ HEADERS += \ ../../src/ServerApplicationsTree.h \ ../../src/ServerRequest.h \ ../../src/ServerResponse.h \ - ../../src/SignalsHandles.h \ ../../src/Socket.h \ ../../src/SocketList.h \ ../../src/System.h \ - ../../src/Utils.h + ../../src/Utils.h \ + ../../src/SignalHandlers.h diff --git a/projects/qt-creator/httpserver.pro.user b/projects/qt-creator/httpserver.pro.user index ff53254..285b143 100644 --- a/projects/qt-creator/httpserver.pro.user +++ b/projects/qt-creator/httpserver.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/ConfigParser.h b/src/ConfigParser.h index db92c20..45b1976 100644 --- a/src/ConfigParser.h +++ b/src/ConfigParser.h @@ -12,16 +12,16 @@ namespace HttpServer class ConfigParser { private: - bool includeConfigFile(const std::string &fileName, std::string &strBuf, const size_t offset = 0); + static bool includeConfigFile(const std::string &fileName, std::string &strBuf, const size_t offset = 0); - bool addApplication( + static bool addApplication( const std::unordered_map &app, const ServerApplicationDefaultSettings &defaults, std::vector &modules, ServerApplicationsTree &apps_tree ); - bool parseMimes(const std::string &fileName, std::unordered_map &mimes_types); + static bool parseMimes(const std::string &fileName, std::unordered_map &mimes_types); public: bool loadConfig( diff --git a/src/DataVariantAbstract.h b/src/DataVariantAbstract.h index c6e7344..88c5581 100644 --- a/src/DataVariantAbstract.h +++ b/src/DataVariantAbstract.h @@ -11,10 +11,7 @@ namespace HttpServer std::string data_variant_name; public: - inline std::string getName() const - { - return data_variant_name; - }; + inline std::string getName() const { return data_variant_name; } public: /** diff --git a/src/DataVariantMultipartFormData.cpp b/src/DataVariantMultipartFormData.cpp index f4d5008..3b6b20e 100644 --- a/src/DataVariantMultipartFormData.cpp +++ b/src/DataVariantMultipartFormData.cpp @@ -20,11 +20,11 @@ namespace HttpServer const std::string &data_end, const size_t &leftBytes, size_t &recv_len, - size_t &read_len - ) const + size_t &recv_total_len + ) { // Завершаем работу, если уже получено байт сколько нужно - if (read_len >= leftBytes) + if (recv_total_len >= leftBytes) { return false; } @@ -39,7 +39,7 @@ namespace HttpServer } // Обновляем общее количество полученных данных - read_len += recv_len; + recv_total_len += recv_len; // Добавляем полученные данные к рабочему буферу str_buf.append(buf.cbegin(), buf.cbegin() + recv_len); @@ -63,7 +63,7 @@ namespace HttpServer ) { // Проверить есть ли в параметрах разделитель блоков данных - auto it = contentParams.find("boundary"); + auto const it = contentParams.find("boundary"); if (contentParams.cend() == it) { @@ -88,18 +88,17 @@ namespace HttpServer // Создание буферов std::vector buf(buf_len); - size_t str_cur; // Текущая позиция в буфере - size_t recv_len; // Прочитано байт при последнем извлечении данных из сокета - size_t read_len = 0; // Прочитано байт из сокета всего + size_t recv_total_len = 0; // Получено байт из сокета всего // Поиск разделителя блока данных - str_cur = str.find(block_delimiter); + // str_cur — текущая позиция в буфере + size_t str_cur = str.find(block_delimiter); if (std::string::npos == str_cur) { // Получить следующий кусок данных - if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, recv_total_len) ) { return false; } @@ -132,7 +131,7 @@ namespace HttpServer if (std::string::npos == headers_end) { // Получить следующий кусок данных - if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, recv_total_len) ) { return false; } @@ -251,17 +250,17 @@ namespace HttpServer } // Поиск имени блока данных - auto it_name = header_params.find("name"); + auto const it_name = header_params.find("name"); if (header_params.cend() != it_name) { // Если данные пришли из файла - auto it_filename = header_params.find("filename"); + auto const it_filename = header_params.find("filename"); if (header_params.cend() != it_filename) { // Найти тип файла - auto it_filetype = headers.find("Content-Type"); + auto const it_filetype = headers.find("Content-Type"); if (headers.cend() != it_filetype) { @@ -291,7 +290,7 @@ namespace HttpServer str.erase(str.begin(), str.end() - data_end.length() ); // Получить следующий кусок данных - if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, recv_total_len) ) { return false; } @@ -347,7 +346,7 @@ namespace HttpServer str.erase(str.begin(), str.end() - data_end.length() ); // Получить следующий кусок данных - if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, recv_total_len) ) { return false; } @@ -399,7 +398,7 @@ namespace HttpServer str.erase(str.begin(), str.end() - data_end.length() ); // Получить следующий кусок данных - if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, read_len) ) + if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, recv_total_len) ) { return false; } diff --git a/src/DataVariantMultipartFormData.h b/src/DataVariantMultipartFormData.h index f1c9e54..28628fa 100644 --- a/src/DataVariantMultipartFormData.h +++ b/src/DataVariantMultipartFormData.h @@ -10,7 +10,7 @@ namespace HttpServer DataVariantMultipartFormData(); protected: - bool append + static bool append ( const Socket &sock, const std::chrono::milliseconds &timeout, @@ -19,8 +19,8 @@ namespace HttpServer const std::string &data_end, const size_t &leftBytes, size_t &recv_len, - size_t &read_len - ) const; + size_t &recv_total_len + ); public: virtual bool parse diff --git a/src/Event.cpp b/src/Event.cpp index ded36e6..d4b3258 100644 --- a/src/Event.cpp +++ b/src/Event.cpp @@ -2,7 +2,7 @@ namespace HttpServer { - Event::Event(const bool _signaled, const bool _manualy): signaled(_signaled), manualy(_manualy) + Event::Event(const bool _signaled, const bool _manually): signaled(_signaled), manually(_manually) { } @@ -16,7 +16,7 @@ namespace HttpServer cv.wait(lck); } - if (false == manualy) + if (false == manually) { signaled = false; } @@ -28,7 +28,7 @@ namespace HttpServer auto const status = cv.wait_for(lck, ms); - if (false == manualy) + if (false == manually) { signaled = false; } @@ -42,7 +42,7 @@ namespace HttpServer auto const status = cv.wait_until(lck, tp); - if (false == manualy) + if (false == manually) { signaled = false; } diff --git a/src/Event.h b/src/Event.h index 5f40862..c9f1174 100644 --- a/src/Event.h +++ b/src/Event.h @@ -12,7 +12,7 @@ namespace HttpServer std::mutex mtx; std::condition_variable cv; std::atomic signaled; - bool manualy; + bool manually; public: Event(const bool _signaled = false, const bool _manualy = false); diff --git a/src/Main.cpp b/src/Main.cpp index 346a59e..a788f4e 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,5 +1,7 @@ + #include "Main.h" -#include "SignalsHandles.h" +#include "Server.h" +#include "SignalHandlers.h" #include @@ -17,20 +19,17 @@ int main(const int argc, const char *argv[]) if (1 < argc) { - auto command = commands.find(argv[1]); + auto const command = commands.find(argv[1]); - if (commands.cend() != command) + if (commands.cend() != command) { HttpServer::Server server; - if (bindSignalsHandles(&server) ) + if (bindSignalHandlers(&server) ) { exitcode = command->second(&server, argc, argv); - #ifdef WIN32 - System::sendSignal(GetCurrentProcessId(), SIGINT); - threadMessageLoop.join(); - #endif + stopSignalHandlers(); } } else diff --git a/src/Main.h b/src/Main.h index e2373d9..08ef4ef 100644 --- a/src/Main.h +++ b/src/Main.h @@ -1,8 +1,5 @@ #pragma once -#include "Server.h" - -#ifdef WIN32 - #include - std::thread threadMessageLoop; -#endif +/** + * Empty + */ \ No newline at end of file diff --git a/src/Server.cpp b/src/Server.cpp index 53518b4..90ec702 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -25,10 +25,10 @@ namespace HttpServer const size_t ext_pos = fileName.rfind('.'); std::string file_ext = std::string::npos != ext_pos ? fileName.substr(ext_pos + 1) : ""; - std::locale loc; + const std::locale loc; Utils::toLower(file_ext, loc); - auto it_mime = this->mimes_types.find(file_ext); + auto const it_mime = this->mimes_types.find(file_ext); return this->mimes_types.cend() != it_mime ? it_mime->second : "application/octet-stream"; } @@ -53,14 +53,14 @@ namespace HttpServer {"bytes", 1} }; - auto it_unit = ranges_units.find(range_unit_name); + auto const it_unit = ranges_units.find(range_unit_name); if (ranges_units.cend() == it_unit) { return ranges; } - const size_t &range_unit = it_unit->second; + const size_t range_unit = it_unit->second; for (size_t str_pos; std::string::npos != delimiter; ) { @@ -68,7 +68,7 @@ namespace HttpServer delimiter = rangeHeader.find(',', str_pos); - size_t range_pos = rangeHeader.find('-', str_pos); + const size_t range_pos = rangeHeader.find('-', str_pos); if (range_pos < delimiter) { @@ -221,7 +221,7 @@ namespace HttpServer if (false == headersOnly) { - for (auto &range : ranges) + for (auto const &range : ranges) { const size_t length = std::get<1>(range); @@ -287,7 +287,7 @@ namespace HttpServer } // Check for If-Modified header - auto it_modified = rp.incoming_headers.find("If-Modified-Since"); + auto const it_modified = rp.incoming_headers.find("If-Modified-Since"); // Если найден заголовок проверки изменения файла (проверить, изменялся ли файл) if (rp.incoming_headers.cend() != it_modified) @@ -306,7 +306,7 @@ namespace HttpServer } } - auto it_range = rp.incoming_headers.find("Range"); + auto const it_range = rp.incoming_headers.find("Range"); // Range transfer if (rp.incoming_headers.cend() != it_range) @@ -419,7 +419,7 @@ namespace HttpServer {413, "Request Entity Too Large"} }; - auto it = statuses.find(statusCode); + auto const it = statuses.find(statusCode); if (statuses.cend() != it) { @@ -484,7 +484,7 @@ namespace HttpServer runApplication(clientSocket, *app_sets, rp); - for (auto &it : rp.incoming_files) + for (auto const &it : rp.incoming_files) { remove(it.second.getName().c_str() ); } @@ -524,11 +524,7 @@ namespace HttpServer if (std::numeric_limits::max() == recv_size && str_buf.empty() ) { #ifdef DEBUG - #ifdef WIN32 - std::cout << "Error: " << WSAGetLastError() << std::endl; - #elif POSIX - std::cout << "Error: " << errno << std::endl; - #endif + std::cout << "Error: " << Socket::getLastError() << std::endl; #endif return false; } @@ -721,7 +717,7 @@ namespace HttpServer int Server::getRequestData(Socket clientSocket, std::string &str_buf, const ServerApplicationSettings &appSets, struct request_parameters &rp) const { // Определить вариант данных запроса (заодно проверить, есть ли данные) - auto it = rp.incoming_headers.find("Content-Type"); + auto const it = rp.incoming_headers.find("Content-Type"); if (rp.incoming_headers.cend() == it) { @@ -790,7 +786,7 @@ namespace HttpServer // Получить длину запроса в байтах size_t data_length = 0; - auto it_len = rp.incoming_headers.find("Content-Length"); + auto const it_len = rp.incoming_headers.find("Content-Length"); if (rp.incoming_headers.cend() != it_len) { @@ -824,7 +820,7 @@ namespace HttpServer // Разобрать данные на составляющие if (false == data_variant->parse(clientSocket, data_buf, left_bytes, content_params, rp) ) { - for (auto &it : rp.incoming_files) + for (auto const &it : rp.incoming_files) { remove(it.second.getName().c_str() ); } @@ -844,19 +840,21 @@ namespace HttpServer const ServerApplicationSettings *Server::getApplicationSettings(const struct request_parameters &rp) const { // Получить доменное имя (или адрес) назначения запроса - auto it_host = rp.incoming_headers.find("Host"); + auto const it_host = rp.incoming_headers.find("Host"); // Если имя задано - продолжить обработку запроса if (rp.incoming_headers.cend() != it_host) { + const std::string &host_header = it_host->second; + // Поиск разделителя, за которым помещается номер порта, если указан - size_t delimiter = it_host->second.find(':'); + const size_t delimiter = host_header.find(':'); // Получить имя (или адрес) - const std::string host = it_host->second.substr(0, delimiter); + const std::string host = host_header.substr(0, delimiter); // Получить номер порта - const int port = (std::string::npos != delimiter) ? std::strtol(it_host->second.substr(delimiter + 1).c_str(), nullptr, 10) : 80; + const int port = (std::string::npos != delimiter) ? std::strtol(host_header.substr(delimiter + 1).c_str(), nullptr, 10) : 80; // Поиск настроек приложения по имени const ServerApplicationSettings *app_sets = this->apps_tree.find(host); @@ -873,7 +871,7 @@ namespace HttpServer void Server::xSendfile(Socket clientSocket, struct request_parameters &rp) const { - auto it_x_sendfile = rp.outgoing_headers.find("X-Sendfile"); + auto const it_x_sendfile = rp.outgoing_headers.find("X-Sendfile"); if (rp.outgoing_headers.cend() != it_x_sendfile) { @@ -889,12 +887,12 @@ namespace HttpServer { rp.connection_params = CONNECTION_CLOSED; - auto it_in_connection = rp.incoming_headers.find("Connection"); - auto it_out_connection = rp.outgoing_headers.find("Connection"); + auto const it_in_connection = rp.incoming_headers.find("Connection"); + auto const it_out_connection = rp.outgoing_headers.find("Connection"); if (rp.incoming_headers.cend() != it_in_connection && rp.outgoing_headers.cend() != it_out_connection) { - std::locale loc; + const std::locale loc; std::string connection_in = it_in_connection->second; Utils::toLower(connection_in, loc); @@ -941,13 +939,13 @@ namespace HttpServer * Метод для обработки запросов (запускается в отдельном потоке) * извлекает сокет клиенты из очереди и передаёт его на обслуживание */ - void Server::threadRequestCycle(std::queue &sockets) const + void Server::threadRequestCycle(std::queue &sockets, Event &eventThreadCycle) const { while (true) { Socket clientSocket; - this->eventThreadCycle->wait(); + eventThreadCycle.wait(); if (false == this->process_flag) { @@ -964,7 +962,7 @@ namespace HttpServer if (sockets.empty() ) { - this->eventThreadCycle->reset(); + eventThreadCycle.reset(); this->eventNotFullQueue->notify(); } @@ -1009,9 +1007,10 @@ namespace HttpServer } this->threads_working_count = 0; - this->eventThreadCycle = new Event(false, true); - std::function &)> serverThreadRequestCycle = std::mem_fn(&Server::threadRequestCycle); + Event eventThreadCycle(false, true); + + std::function &, Event &)> serverThreadRequestCycle = std::mem_fn(&Server::threadRequestCycle); std::vector active_threads; active_threads.reserve(threads_max_count); @@ -1029,7 +1028,7 @@ namespace HttpServer { while (this->threads_working_count == active_threads.size() && active_threads.size() < threads_max_count && sockets.empty() == false) { - active_threads.emplace_back(serverThreadRequestCycle, this, std::ref(sockets) ); + active_threads.emplace_back(serverThreadRequestCycle, this, std::ref(sockets), std::ref(eventThreadCycle) ); } size_t notify_count = active_threads.size() - this->threads_working_count; @@ -1039,7 +1038,7 @@ namespace HttpServer notify_count = sockets.size(); } - this->eventThreadCycle->notify(notify_count); + eventThreadCycle.notify(notify_count); this->eventProcessQueue->wait(); } @@ -1047,7 +1046,7 @@ namespace HttpServer // Data clear - this->eventThreadCycle->notify(); + eventThreadCycle.notify(); if (false == active_threads.empty() ) { @@ -1074,8 +1073,6 @@ namespace HttpServer this->server_sockets.clear(); } - delete this->eventThreadCycle; - return 0; } @@ -1120,7 +1117,7 @@ namespace HttpServer module.close(); - auto app = *(same.cbegin() ); + auto const app = *(same.cbegin() ); const std::string &module_name = app->server_module; @@ -1153,8 +1150,8 @@ namespace HttpServer #elif POSIX // HACK: for posix system — load new version shared library - size_t dir_pos = module_name.rfind('/'); - size_t ext_pos = module_name.rfind('.'); + const size_t dir_pos = module_name.rfind('/'); + const size_t ext_pos = module_name.rfind('.'); std::string module_name_temp; @@ -1283,12 +1280,12 @@ namespace HttpServer std::unordered_set updated; - for (auto &app : applications) + for (auto const &app : applications) { const size_t module_index = app->module_index; // If module is not updated (not checked) - if (updated.end() == updated.find(module_index) ) + if (updated.cend() == updated.find(module_index) ) { if (false == app->server_module_update.empty() && app->server_module_update != app->server_module) { @@ -1428,7 +1425,7 @@ namespace HttpServer std::unordered_set ports; // Open applications sockets - for (auto &app : applications) + for (auto const &app : applications) { const int port = app->port; @@ -1437,11 +1434,11 @@ namespace HttpServer { Socket sock; - if (~0 != sock.open() ) + if (sock.open() ) { - if (~0 != sock.bind(port) ) + if (sock.bind(port) ) { - if (0 == sock.listen() ) + if (sock.listen() ) { sock.nonblock(true); @@ -1451,17 +1448,17 @@ namespace HttpServer } else { - std::cout << "Error: cannot listen socket " << port << "; errno " << errno << ";" << std::endl; + std::cout << "Error: cannot listen socket " << port << "; errno " << Socket::getLastError() << ";" << std::endl; } } else { - std::cout << "Error: cannot bind socket " << port << "; errno " << errno << ";" << std::endl; + std::cout << "Error: cannot bind socket " << port << "; errno " << Socket::getLastError() << ";" << std::endl; } } else { - std::cout << "Error: cannot open socket; errno " << errno << ";" << std::endl; + std::cout << "Error: cannot open socket; errno " << Socket::getLastError() << ";" << std::endl; } } } @@ -1477,7 +1474,7 @@ namespace HttpServer sockets_list.create(this->server_sockets.size() ); - for (auto &sock : this->server_sockets) + for (auto const &sock : this->server_sockets) { sockets_list.addSocket(sock); } diff --git a/src/Server.h b/src/Server.h index 3e1fb50..011bf38 100644 --- a/src/Server.h +++ b/src/Server.h @@ -33,10 +33,9 @@ namespace HttpServer Event *eventNotFullQueue; Event *eventProcessQueue; Event *eventUpdateModule; - Event *eventThreadCycle; - mutable std::atomic_size_t threads_working_count; - mutable std::mutex sockets_queue_mtx; + mutable std::atomic_size_t threads_working_count; + mutable std::mutex sockets_queue_mtx; // Флаг, означающий - активированы ли главные циклы сервера // (с помощью этого флага можно деактивировать циклы, чтобы завершить работу сервера) @@ -70,7 +69,7 @@ namespace HttpServer static bool isConnectionKeepAlive(const struct request_parameters &rp); static bool isConnectionUpgrade(const struct request_parameters &rp); - void threadRequestCycle(std::queue &sockets) const; + void threadRequestCycle(std::queue &sockets, Event &eventThreadCycle) const; std::string getMimeTypeByFileName(const std::string &fileName) const; diff --git a/src/ServerApplicationsTree.h b/src/ServerApplicationsTree.h index cfb99bd..84ce430 100644 --- a/src/ServerApplicationsTree.h +++ b/src/ServerApplicationsTree.h @@ -19,10 +19,7 @@ namespace HttpServer ServerApplicationsTree(); ~ServerApplicationsTree(); - inline bool empty() const - { - return list.empty(); - } + inline bool empty() const { return list.empty(); } void addApplication(const std::string &name, ServerApplicationSettings *sets); void addApplication(std::vector &nameParts, ServerApplicationSettings *sets); diff --git a/src/SignalsHandles.cpp b/src/SignalHandlers.cpp similarity index 68% rename from src/SignalsHandles.cpp rename to src/SignalHandlers.cpp index 31a134e..2afaa03 100644 --- a/src/SignalsHandles.cpp +++ b/src/SignalHandlers.cpp @@ -1,11 +1,20 @@  -#include "SignalsHandles.h" +#include "SignalHandlers.h" +#include "System.h" -#include +#ifdef WIN32 + #include + #include + + static std::thread threadMessageLoop; + extern ::TCHAR myWndClassName[]; +#endif -HttpServer::Server *globalServerPtr = nullptr; +#include -void handlerSigTerm(int sig) +static HttpServer::Server *globalServerPtr = nullptr; + +static void handlerSigTerm(const int sig) { if (globalServerPtr) { @@ -13,7 +22,7 @@ void handlerSigTerm(int sig) } } -void handlerSigInt(int sig) +static void handlerSigInt(const int sig) { if (globalServerPtr) { @@ -21,7 +30,7 @@ void handlerSigInt(int sig) } } -void handlerSigUsr1(int sig) +static void handlerSigUsr1(const int sig) { if (globalServerPtr) { @@ -30,7 +39,7 @@ void handlerSigUsr1(int sig) } } -void handlerSigUsr2(int sig) +static void handlerSigUsr2(const int sig) { if (globalServerPtr) { @@ -41,13 +50,12 @@ void handlerSigUsr2(int sig) } #ifdef WIN32 - /** * Note: PostQuitMessage(0) * It doesn't work in case the program was launched and was * attempted to finish under different remote sessions. */ -::LRESULT CALLBACK WndProc(::HWND hWnd, ::UINT message, ::WPARAM wParam, ::LPARAM lParam) +static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const ::WPARAM wParam, const ::LPARAM lParam) { switch (message) { @@ -88,9 +96,9 @@ ::LRESULT CALLBACK WndProc(::HWND hWnd, ::UINT message, ::WPARAM wParam, ::LPARA return 0; } -::WPARAM mainMessageLoop(::HINSTANCE hInstance, HttpServer::Event *pCreatedWindow) +static ::WPARAM mainMessageLoop(const ::HINSTANCE hInstance, HttpServer::Event *pCreatedWindow) { - ::HWND hWnd = ::CreateWindow(myWndClassName, nullptr, 0, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, nullptr, nullptr, hInstance, nullptr); + const ::HWND hWnd = ::CreateWindow(myWndClassName, nullptr, 0, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, nullptr, nullptr, hInstance, nullptr); pCreatedWindow->notify(); @@ -111,7 +119,7 @@ ::WPARAM mainMessageLoop(::HINSTANCE hInstance, HttpServer::Event *pCreatedWindo } #endif -int bindSignalsHandles(HttpServer::Server *server) +bool bindSignalHandlers(HttpServer::Server *server) { globalServerPtr = server; @@ -125,7 +133,7 @@ int bindSignalsHandles(HttpServer::Server *server) ::_set_abort_behavior(0, _WRITE_ABORT_MSG); - ::HINSTANCE hInstance = ::GetModuleHandle(nullptr); + const ::HINSTANCE hInstance = ::GetModuleHandle(nullptr); ::WNDCLASSEX wcex = {}; @@ -136,7 +144,7 @@ int bindSignalsHandles(HttpServer::Server *server) if (0 == ::RegisterClassEx(&wcex) ) { - return 0; + return false; } HttpServer::Event createdWindow; @@ -164,5 +172,13 @@ int bindSignalsHandles(HttpServer::Server *server) #error "Undefine platform" #endif - return 1; + return true; +} + +void stopSignalHandlers() +{ +#ifdef WIN32 + System::sendSignal(::GetCurrentProcessId(), SIGINT); + threadMessageLoop.join(); +#endif } \ No newline at end of file diff --git a/src/SignalHandlers.h b/src/SignalHandlers.h new file mode 100644 index 0000000..17bcc1e --- /dev/null +++ b/src/SignalHandlers.h @@ -0,0 +1,7 @@ +#pragma once + +#include "Server.h" + +bool bindSignalHandlers(HttpServer::Server *server); + +void stopSignalHandlers(); \ No newline at end of file diff --git a/src/SignalsHandles.h b/src/SignalsHandles.h deleted file mode 100644 index 59a9b36..0000000 --- a/src/SignalsHandles.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "Server.h" -#include "System.h" - -#ifdef WIN32 - #include - #include - - extern std::thread threadMessageLoop; - extern ::TCHAR myWndClassName[]; -#endif - -int bindSignalsHandles(HttpServer::Server *server); 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/SocketList.cpp b/src/SocketList.cpp index a21cc0f..ccfdd43 100644 --- a/src/SocketList.cpp +++ b/src/SocketList.cpp @@ -30,7 +30,7 @@ namespace HttpServer #elif POSIX this->obj_list = ::epoll_create(startListSize); - if (std::numeric_limits::max() == this->obj_list) + if (this->obj_list == ~0) { return false; } @@ -66,9 +66,9 @@ namespace HttpServer bool SocketList::is_created() const { #ifdef WIN32 - return INVALID_HANDLE_VALUE != this->obj_list; + return this->obj_list != INVALID_HANDLE_VALUE; #elif POSIX - return std::numeric_limits::max() != this->obj_list; + return this->obj_list != ~0; #else #error "Undefine platform" #endif @@ -97,9 +97,9 @@ namespace HttpServer reinterpret_cast(sock.get_handle() ) }; - const size_t 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 (std::numeric_limits::max() == result) + if (result == ~0) { return false; } @@ -131,9 +131,9 @@ namespace HttpServer return false; #elif POSIX - const size_t 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 (std::numeric_limits::max() == result) + if (result == ~0) { return false; } @@ -151,7 +151,7 @@ namespace HttpServer if (is_created() ) { #ifdef WIN32 - const size_t count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), ~0); + const int count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), ~0); if (SOCKET_ERROR == count) { @@ -162,7 +162,7 @@ namespace HttpServer { const WSAPOLLFD &event = this->poll_events[i]; - if (POLLRDNORM == (event.revents & POLLRDNORM) ) + if (event.revents & POLLRDNORM) { System::native_socket_type client_socket = ~0; @@ -181,18 +181,18 @@ namespace HttpServer return false == sockets.empty(); #elif POSIX - const size_t 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 (std::numeric_limits::max() == count) + if (count == ~0) { return false; } - for (size_t i = 0; i < count; ++i) + for (int i = 0; i < count; ++i) { const epoll_event &event = this->epoll_events[i]; - if (EPOLLIN == (event.events & EPOLLIN) ) + if (event.events & EPOLLIN) { System::native_socket_type client_socket = ~0; @@ -226,7 +226,7 @@ namespace HttpServer } #ifdef WIN32 - const size_t count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), timeout.count() ); + const int count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), timeout.count() ); if (SOCKET_ERROR == count) { @@ -237,11 +237,11 @@ namespace HttpServer { const WSAPOLLFD &event = this->poll_events[i]; - if (POLLRDNORM == (event.revents & POLLRDNORM) ) + if (event.revents & POLLRDNORM) { sockets.emplace_back(Socket(event.fd) ); } - else if (POLLHUP == (event.revents & POLLHUP) ) + else if (event.revents & POLLHUP) { disconnected.emplace_back(Socket(event.fd) ); } @@ -249,22 +249,22 @@ namespace HttpServer return false == sockets.empty() || false == disconnected.empty(); #elif POSIX - const size_t 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 (std::numeric_limits::max() == count) + if (count == ~0) { return false; } - for (size_t i = 0; i < count; ++i) + for (int i = 0; i < count; ++i) { const epoll_event &event = this->epoll_events[i]; - if (EPOLLIN == (event.events & EPOLLIN) ) + if (event.events & EPOLLIN) { sockets.emplace_back(Socket(event.data.fd) ); } - else if (EPOLLRDHUP == (event.events & EPOLLRDHUP) ) + else if (event.events & EPOLLRDHUP) { disconnected.emplace_back(Socket(event.data.fd) ); } diff --git a/src/SocketList.h b/src/SocketList.h index 0e7888d..c318157 100644 --- a/src/SocketList.h +++ b/src/SocketList.h @@ -11,7 +11,7 @@ namespace HttpServer HANDLE obj_list; mutable std::vector poll_events; #elif POSIX - size_t obj_list; + int obj_list; mutable std::vector epoll_events; #else #error "Undefine platform" 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 ec8d9770012b109452c881b6afc0d1cffdb3fc98 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Sun, 10 Jan 2016 19:38:32 +0300 Subject: [PATCH 19/50] Updated msvs project --- projects/msvs/httpserver.v12.suo | Bin 154112 -> 158720 bytes projects/msvs/httpserver.vcxproj | 4 ++-- projects/msvs/httpserver.vcxproj.filters | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/projects/msvs/httpserver.v12.suo b/projects/msvs/httpserver.v12.suo index e88b32fe139fa6ed2e79842f69118d1b159eec4d..4cac25849ccc06e4b6d89ec083c1763ae7cab329 100644 GIT binary patch delta 5492 zcmc(j3s{v!8pppG4u``N@BLT>1tjoYfDSpZo2FSwc3UK&vz~!5Z$(?ryZW(nfYek zZ)V>2d*_`QTAuT4dE2usbA(coBnrOo@9#$@5fA~imX7=qvbMg$Oly66Ms9xT(2Nsg zG#a|X*;2Zc+{*gsOxEq2#1g53-RHJxZM~w|6Yar3bS4;y@^CN$cmogM1vDT4=zx&> z4h%y%1fVDNrdwRDwFA zWPQTXaC3FMDzxHFVO)pN#Yn8)D{-D^aAiCi#B&1jM34jwAQ?F1QeDc9I@dfK?KyTC zv$uAFXq$%TsV?u$K=~H?^GthQYR`Xxyqqo8X9TQ72`~3oA+NT#_Osu6Pht1z)vU)` zZT9U|MxkNVmzJx(N@D&wRh@-#2dSF(qg1skCYx~W{Dl8aYjqr99~OqPE;ofL9z6+P zVR_N9?(bK%qzz}@`Sj@|Mf|J1UmaV)lA=RMl`IuJRUw>K^g=RNWAIE*$sf;Z zM_oGW3vMQpSYt>tNwf5YcvEvww21GRKkJ9nv^?>XN}r&g@_dL z<2cr*Z60dL>~h5=vT2h_kH zXuxow1pz<@0zoiv^evX{Nc;0BPRA6l4bLXx#Z6$1=~&I8PVDn? zT?*?%9T9b6LzL_EtTAIIn;ev7j_YRKG>J^K^u?(O+tI4M*>qot5}sEM&#RQ~hToas zNHvlqoM5xA0BU<-GP9+Ml^$O*gX>_Yu6ZONQ zdoIHN4~*_7G&9&CO(vTVtzKJS+q@OSZ3ElE6JQ7U1K0_6fhWOkum|h~Pl2bwGvHa! z4m!X-U;)p8=Rqg1f)~Jx;E&)X@G|%l*bfd!QnS>B!Ykk)=mv+ttKcwr4g49r4vv7o zfH%NVa18tv90w=Bo8Tlk1x|xA;4Sbrcn6#X?}GQh-@yCe1B@@7L*YF55PSqKfQ#T` z@OSVD_!N8wJ_lcbOW-p22j~I+1pfkGf?m)Ez5-u^e}gOFD)SF^oqVO2l1Re*Q0bz?{M|ad$k(~vE3VS_iAw{42vB>pBtWY<~y#_K* zu*Ea)walA+Fq*BpwTKNb40Xf$;z>)%F3aKNEq;9aG7`+^)gYD@>Y~uLgNHprmRa_< zhK91pc3Tra)kZXA8(aHuGYkJh&6n>WD$6~)k4)lK!PG9I@TWTWUHFLec-baW&f0(J z#aEw$+~$vzs%vrxpE|OgE#BE|3I8G`kgc36zpoFtey2t(u$H-zXM_3W5j4me6i#A2 zJBvt<%AufAR*>-a9ug|6z|TEGf~}<`kTvj%%jICa&v1TqK;i@6bQx;2>Fnw!~^|J@bu@L7tvW@6A!p_aL zPv(FJ)mYVA$wRpgE#tY0cC z=~{<`9^1y?GYu?7_*P1uvwm`g1bOk6LnPgruA+M=H%8M$YyDVq+?~G}Lz>LHRMrLF zbmK@zck%q=I9S1SmY5($+f=-CIEm-+sdNsDJgZ~J-`DWVAw*@ZPawzL*uf$LUwxYR z@XhJO$9gQ4rW0nIX5w4NQ`Jrdr9ARAV&;3sQ?>QOWHOhq1yePAk~=k63-ak!!q0lp zP@Zd`EBQ(T&9-(G&?dJL@H(UnEDbesfB6X(AQCT0r(=Ta>z6NIR*+bjlqXtTnk8O% z3r!RUDmn3pVmi^H5J%` z8>A*sVHaoqX+gBOjFsiOzsZ^R1}AlES0QbpF4h}lT$}Y| z8*%?>G*cW%i8)?O)dRQEXPX=4PNH ze#}61yepY@bt>p3N-p!uO4>@C$4`F3gC_9(lWB}17IWq)2D+N(Cp$dqr&PKVN|PU{ zk6Upa!9EknN;5UYpC2ft0m7^7w>n|$n#KhcH73)5yVel5I@b%}jc;{Y$KA|%C;VwV z=_Z%B|8huIi0{niX2saFul05DX#15lPBZi!HPU~etV5OSq;cPfbQim71bZcQp}X^@ zYEJF)wR@pgxvh3hTCBbOT4`=pux^(46!tXm&ROX$zskGH>1`}9b1XIyT(jf6RJI=V zHF4rT9qBpn(b;iA%KW1?gJo%AJONboq2ReNP$n;ZJ4LAl{x$wc@8uz6Ckg zmK@tW?8}LrH%_`PruknN)A)fL8p3mLN6cFlo$6skysO5+0{>ya|7sRV;VdUAfS`@|5;%xagwwR? zTQqvxan(kLB&~I(cA9vdJpR#XPU%cDosNU8>DZ}%XeUYA>6mIOnMSA5?>^j7pd{8# z+H|Hn^SOO{_U*U7mp#vQjpv7&qovDK3Wb7zhtt#3$mDV?@C0%oB~wm0OJF)@PyA0V3+omO$7CHv}b@!g4RSy(SOLsnCCCH$ zzybFMJU=_Wr;^!C`)jx7(Yi@ z#)P(fj>-Z7R$&95o3e-t>;V5wWx;JIC=ge|blL`kxFb=ot?F|L%cxBiQAQ3d<9@3D z<*u<0-oLFmQN>3~mLI;h2McECgez79k-W=1%#-8src8)k`R=9Yh&Q2HnT9TT1s5Ai zsMC;0)b+u(RyLI|Mq1cV;uv|xHbLMxMP6*COwnqZ=_*i+AVSeztT>#XZqx# zR&LE}>+jzx1gjO>d@Lymd5b|J&684*T|?r~DIBUSrKj0YQ@wf_s^P&VCz~pgpJ!w% z8(IyG)S^cyu^6BeriZee81cvPxK5hG)y>qT6}BRhgYj1@X)0e?MVIiecfbOla`*HO z&K^5lBiF_GR`6Rcj9gIXJG$r!X3jS-y(uob+wJZjlqKTa)Y{XR*FCdZ(5xIM#cGDn z!Y-`U^KP|?+05oxVIRS}6!QF6E+YAp)YS}?JrZ~x8(*uYA zwM6Ipeec;!elL`aaF3Ei`aJAZ6us$-=dCVTdOy4s|*NTZ*!*6~_ zjFM4FZ>sp@eG<$1KZ-e?Lv>P7A^mv>ZwR4ZA;ie)o%10aMd7-I+^gJ7?lXW!& z?@Sg=^WoD|KEcHcagX~*%`{=2yDm2Q7pGmDpzLT(1JG7G4NLTBI8*V)t6&^iE%=eACoOHR%I#BjER zQr4K6&u-Fa{-qLH3h%1sRy$m*#ZC?KkA#w!uoRsM`jAAFfv6P~2J;jD#b7FB@*Id{ z!8w!&XKY($t{A}%ZH(b-*V01CQA)=NZ?B+9$IIyL4&vXml%{u{3o&Ft$$_C)&AuU{Uxu_12w zaAn!CcPHY - + @@ -54,7 +54,7 @@ - + diff --git a/projects/msvs/httpserver.vcxproj.filters b/projects/msvs/httpserver.vcxproj.filters index 9f4bea1..322c10f 100644 --- a/projects/msvs/httpserver.vcxproj.filters +++ b/projects/msvs/httpserver.vcxproj.filters @@ -52,9 +52,6 @@ Source Files - - Source Files - Source Files @@ -67,6 +64,9 @@ Source Files + + Source Files + @@ -120,9 +120,6 @@ Header Files - - Header Files - Header Files @@ -135,5 +132,8 @@ Header Files + + Header Files + \ No newline at end of file From ba4c4d15b302056fab6709e00a4456e3bb376516 Mon Sep 17 00:00:00 2001 From: awwit Date: Sun, 31 Jan 2016 00:58:23 +0300 Subject: [PATCH 20/50] 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 5d15c75a58ae0d3644a5d144f6358b14a10088fd Mon Sep 17 00:00:00 2001 From: awwit Date: Mon, 21 Mar 2016 04:16:08 +0300 Subject: [PATCH 21/50] Modified signal processing for Win32 --- src/Module.cpp | 2 +- src/SignalHandlers.cpp | 59 ++++++++++++++++++++++++++++-------------- src/Utils.cpp | 8 +++--- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 59ff813..43e9c9e 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -84,7 +84,7 @@ namespace HttpServer if (nullptr == lib_handle) { #ifdef POSIX - std::cout << ::dlerror() << std::endl; + std::cout << ::dlerror() << std::endl; #endif return false; } diff --git a/src/SignalHandlers.cpp b/src/SignalHandlers.cpp index 2afaa03..0943424 100644 --- a/src/SignalHandlers.cpp +++ b/src/SignalHandlers.cpp @@ -62,7 +62,7 @@ static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const case SIGTERM: { handlerSigTerm(message); - ::PostMessage(hWnd, WM_QUIT, 0, 0); // Fuck ::PostQuitMessage(0); + ::PostMessage(hWnd, WM_QUIT, 0, 0); // Fuck ::PostQuitMessage(0); break; } @@ -70,7 +70,7 @@ static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const case SIGINT: { handlerSigInt(message); - ::PostMessage(hWnd, WM_QUIT, 0, 0); // Fuck ::PostQuitMessage(0); + ::PostMessage(hWnd, WM_QUIT, 0, 0); // Fuck ::PostQuitMessage(0); break; } @@ -89,7 +89,7 @@ static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const default: { - return ::DefWindowProc(hWnd, message, wParam, lParam); + return ::DefWindowProc(hWnd, message, wParam, lParam); } } @@ -107,17 +107,37 @@ static ::WPARAM mainMessageLoop(const ::HINSTANCE hInstance, HttpServer::Event * return 0; } - ::MSG msg; + ::MSG msg; - while (::GetMessage(&msg, hWnd, 0, 0) ) + while (::GetMessage(&msg, hWnd, 0, 0) ) { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); } return msg.wParam; } -#endif + +#ifdef _CONSOLE +static ::BOOL consoleSignalHandler(const ::DWORD ctrlType) +{ + switch (ctrlType) + { + case CTRL_CLOSE_EVENT: + handlerSigTerm(ctrlType); + std::this_thread::sleep_for(std::chrono::seconds(60) ); + return true; + + case CTRL_C_EVENT: + handlerSigInt(ctrlType); + return true; + + default: + return false; + } +} +#endif // _CONSOLE +#endif // WIN32 bool bindSignalHandlers(HttpServer::Server *server) { @@ -125,13 +145,12 @@ bool bindSignalHandlers(HttpServer::Server *server) #ifdef WIN32 - const int sig_int = 2; // SIGINT - const int sig_term = 15; // SIGTERM - - ::signal(sig_int, handlerSigInt); - ::signal(sig_term, handlerSigTerm); - - ::_set_abort_behavior(0, _WRITE_ABORT_MSG); +#ifdef _CONSOLE + ::SetConsoleCtrlHandler(reinterpret_cast(consoleSignalHandler), true); +#elif + ::signal(SIGINT, handlerSigInt); + ::signal(SIGTERM, handlerSigTerm); +#endif // _CONSOLE const ::HINSTANCE hInstance = ::GetModuleHandle(nullptr); @@ -142,7 +161,7 @@ bool bindSignalHandlers(HttpServer::Server *server) wcex.hInstance = hInstance; wcex.lpszClassName = myWndClassName; - if (0 == ::RegisterClassEx(&wcex) ) + if (0 == ::RegisterClassEx(&wcex) ) { return false; } @@ -158,16 +177,16 @@ bool bindSignalHandlers(HttpServer::Server *server) struct ::sigaction act = {}; act.sa_handler = handlerSigInt; - ::sigaction(SIGINT, &act, nullptr); + ::sigaction(SIGINT, &act, nullptr); act.sa_handler = handlerSigTerm; - ::sigaction(SIGTERM, &act, nullptr); + ::sigaction(SIGTERM, &act, nullptr); act.sa_handler = handlerSigUsr1; - ::sigaction(SIGUSR1, &act, nullptr); + ::sigaction(SIGUSR1, &act, nullptr); act.sa_handler = handlerSigUsr2; - ::sigaction(SIGUSR2, &act, nullptr); + ::sigaction(SIGUSR2, &act, nullptr); #else #error "Undefine platform" #endif 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 668a8272788a3748d93e83d79832766284e8eaef Mon Sep 17 00:00:00 2001 From: awwit Date: Tue, 26 Apr 2016 00:01:41 +0300 Subject: [PATCH 22/50] Added support of HTTPS (via gnutls) Added support of comments in the config-files Changed the build system on QBS (for Linux) --- README.md | 66 ++++- projects/qt-creator/deployment.pri | 191 -------------- projects/qt-creator/httpserver.pro | 70 ------ projects/qt-creator/httpserver.pro.user | 271 -------------------- projects/qt-creator/httpserver.qbs | 71 ++++++ samples/apps.conf | 17 +- src/ConfigParser.cpp | 316 ++++++++++++++++++------ src/ConfigParser.h | 2 +- src/DataVariantAbstract.h | 4 +- src/DataVariantFormUrlencoded.cpp | 2 +- src/DataVariantFormUrlencoded.h | 2 +- src/DataVariantMultipartFormData.cpp | 10 +- src/DataVariantMultipartFormData.h | 6 +- src/DataVariantTextPlain.cpp | 2 +- src/DataVariantTextPlain.h | 2 +- src/Server.cpp | 316 ++++++++++++++++++------ src/Server.h | 30 ++- src/ServerApplicationSettings.h | 11 +- src/ServerRequest.h | 7 +- src/ServerResponse.h | 3 +- src/SignalHandlers.cpp | 3 + 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/SocketList.cpp | 80 ++++++ src/SocketList.h | 1 + 31 files changed, 1178 insertions(+), 824 deletions(-) delete mode 100644 projects/qt-creator/deployment.pri delete mode 100644 projects/qt-creator/httpserver.pro delete mode 100644 projects/qt-creator/httpserver.pro.user create mode 100644 projects/qt-creator/httpserver.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 9dec03c..ecc999d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,67 @@ httpserver ========== -Http server on C++ +Http server is written on C++14 language. -For C++ server applications (*.so - linux, *.dll - windows) -See: https://github.com/awwit/httpserverapp +Dynamic libraries act as applications for the server +(* .so - linux, * .dll - windows). +Library connection takes place in the configuration file +[samples/apps.conf] [samples/apps.conf] +by using the parameter `server_module`. + +Sample application code: https://github.com/awwit/httpserverapp + +Features +-------- + +This http server support: + +* HTTP v1.1 +* HTTPS (TLS) +* Keep-Alive +* WebSocket +* Get-Parted requests +* X-Sendfile (header) + +Dependencies +------------ + +Common: + +* [gnutls](https://www.gnutls.org/) + +Linux: + +* dl +* pthread + +Build +----- + +Linux: + + git clone https://github.com/awwit/httpserver.git + cd httpserver + mkdir build + cd build + qbs build -f ./../projects/qt-creator/httpserver.qbs release + +Server start +------------ + + ./httpserver --start + +Configuration files must be located in the working (current) directory. + +Server configuration +-------------------- + +Server (and its applications) setting is made using config-files. +Examples of settings are located in the folder [samples][samples/]. + +License +======= + +The source codes are licensed under the +[AGPL](http://www.gnu.org/licenses/agpl.html), +the full text of the license is located in the [LICENSE][LICENSE] file. diff --git a/projects/qt-creator/deployment.pri b/projects/qt-creator/deployment.pri deleted file mode 100644 index 5f1749f..0000000 --- a/projects/qt-creator/deployment.pri +++ /dev/null @@ -1,191 +0,0 @@ -# This file was generated by an application wizard of Qt Creator. -# The code below handles deployment to Android and Maemo, aswell as copying -# of the application data to shadow build directories on desktop. -# It is recommended not to modify this file, since newer versions of Qt Creator -# may offer an updated version of it. - -defineTest(qtcAddDeployment) { -for(deploymentfolder, DEPLOYMENTFOLDERS) { - item = item$${deploymentfolder} - greaterThan(QT_MAJOR_VERSION, 4) { - itemsources = $${item}.files - } else { - itemsources = $${item}.sources - } - $$itemsources = $$eval($${deploymentfolder}.source) - itempath = $${item}.path - $$itempath= $$eval($${deploymentfolder}.target) - export($$itemsources) - export($$itempath) - DEPLOYMENT += $$item -} - -MAINPROFILEPWD = $$PWD - -android-no-sdk { - for(deploymentfolder, DEPLOYMENTFOLDERS) { - item = item$${deploymentfolder} - itemfiles = $${item}.files - $$itemfiles = $$eval($${deploymentfolder}.source) - itempath = $${item}.path - $$itempath = /data/user/qt/$$eval($${deploymentfolder}.target) - export($$itemfiles) - export($$itempath) - INSTALLS += $$item - } - - target.path = /data/user/qt - - export(target.path) - INSTALLS += target -} else:android { - for(deploymentfolder, DEPLOYMENTFOLDERS) { - item = item$${deploymentfolder} - itemfiles = $${item}.files - $$itemfiles = $$eval($${deploymentfolder}.source) - itempath = $${item}.path - $$itempath = /assets/$$eval($${deploymentfolder}.target) - export($$itemfiles) - export($$itempath) - INSTALLS += $$item - } - - x86 { - target.path = /libs/x86 - } else: armeabi-v7a { - target.path = /libs/armeabi-v7a - } else { - target.path = /libs/armeabi - } - - export(target.path) - INSTALLS += target -} else:win32 { - copyCommand = - for(deploymentfolder, DEPLOYMENTFOLDERS) { - source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) - source = $$replace(source, /, \\) - sourcePathSegments = $$split(source, \\) - target = $$OUT_PWD/$$eval($${deploymentfolder}.target)/$$last(sourcePathSegments) - target = $$replace(target, /, \\) - target ~= s,\\\\\\.?\\\\,\\, - !isEqual(source,$$target) { - !isEmpty(copyCommand):copyCommand += && - isEqual(QMAKE_DIR_SEP, \\) { - copyCommand += $(COPY_DIR) \"$$source\" \"$$target\" - } else { - source = $$replace(source, \\\\, /) - target = $$OUT_PWD/$$eval($${deploymentfolder}.target) - target = $$replace(target, \\\\, /) - copyCommand += test -d \"$$target\" || mkdir -p \"$$target\" && cp -r \"$$source\" \"$$target\" - } - } - } - !isEmpty(copyCommand) { - copyCommand = @echo Copying application data... && $$copyCommand - copydeploymentfolders.commands = $$copyCommand - first.depends = $(first) copydeploymentfolders - export(first.depends) - export(copydeploymentfolders.commands) - QMAKE_EXTRA_TARGETS += first copydeploymentfolders - } -} else:ios { - copyCommand = - for(deploymentfolder, DEPLOYMENTFOLDERS) { - source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) - source = $$replace(source, \\\\, /) - target = $CODESIGNING_FOLDER_PATH/$$eval($${deploymentfolder}.target) - target = $$replace(target, \\\\, /) - sourcePathSegments = $$split(source, /) - targetFullPath = $$target/$$last(sourcePathSegments) - targetFullPath ~= s,/\\.?/,/, - !isEqual(source,$$targetFullPath) { - !isEmpty(copyCommand):copyCommand += && - copyCommand += mkdir -p \"$$target\" - copyCommand += && cp -r \"$$source\" \"$$target\" - } - } - !isEmpty(copyCommand) { - copyCommand = echo Copying application data... && $$copyCommand - !isEmpty(QMAKE_POST_LINK): QMAKE_POST_LINK += ";" - QMAKE_POST_LINK += "$$copyCommand" - export(QMAKE_POST_LINK) - } -} else:unix { - maemo5 { - desktopfile.files = $${TARGET}.desktop - desktopfile.path = /usr/share/applications/hildon - icon.files = $${TARGET}64.png - icon.path = /usr/share/icons/hicolor/64x64/apps - } else:!isEmpty(MEEGO_VERSION_MAJOR) { - desktopfile.files = $${TARGET}_harmattan.desktop - desktopfile.path = /usr/share/applications - icon.files = $${TARGET}80.png - icon.path = /usr/share/icons/hicolor/80x80/apps - } else { # Assumed to be a Desktop Unix - copyCommand = - for(deploymentfolder, DEPLOYMENTFOLDERS) { - source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) - source = $$replace(source, \\\\, /) - macx { - target = $$OUT_PWD/$${TARGET}.app/Contents/Resources/$$eval($${deploymentfolder}.target) - } else { - target = $$OUT_PWD/$$eval($${deploymentfolder}.target) - } - target = $$replace(target, \\\\, /) - sourcePathSegments = $$split(source, /) - targetFullPath = $$target/$$last(sourcePathSegments) - targetFullPath ~= s,/\\.?/,/, - !isEqual(source,$$targetFullPath) { - !isEmpty(copyCommand):copyCommand += && - copyCommand += $(MKDIR) \"$$target\" - copyCommand += && $(COPY_DIR) \"$$source\" \"$$target\" - } - } - !isEmpty(copyCommand) { - copyCommand = @echo Copying application data... && $$copyCommand - copydeploymentfolders.commands = $$copyCommand - first.depends = $(first) copydeploymentfolders - export(first.depends) - export(copydeploymentfolders.commands) - QMAKE_EXTRA_TARGETS += first copydeploymentfolders - } - } - !isEmpty(target.path) { - installPrefix = $${target.path} - } else { - installPrefix = /opt/$${TARGET} - } - for(deploymentfolder, DEPLOYMENTFOLDERS) { - item = item$${deploymentfolder} - itemfiles = $${item}.files - $$itemfiles = $$eval($${deploymentfolder}.source) - itempath = $${item}.path - $$itempath = $${installPrefix}/$$eval($${deploymentfolder}.target) - export($$itemfiles) - export($$itempath) - INSTALLS += $$item - } - - !isEmpty(desktopfile.path) { - export(icon.files) - export(icon.path) - export(desktopfile.files) - export(desktopfile.path) - INSTALLS += icon desktopfile - } - - isEmpty(target.path) { - target.path = $${installPrefix}/bin - export(target.path) - } - INSTALLS += target -} - -export (ICON) -export (INSTALLS) -export (DEPLOYMENT) -export (LIBS) -export (QMAKE_EXTRA_TARGETS) -} - diff --git a/projects/qt-creator/httpserver.pro b/projects/qt-creator/httpserver.pro deleted file mode 100644 index 2497baa..0000000 --- a/projects/qt-creator/httpserver.pro +++ /dev/null @@ -1,70 +0,0 @@ -TEMPLATE = app - -CONFIG += console c++11 -CONFIG -= app_bundle -CONFIG -= qt - -lessThan(QT_MAJOR_VERSION, 5) { - QMAKE_CXXFLAGS += -std=c++1y -} - -unix { - DEFINES += POSIX -} - -CONFIG(debug, debug|release):DEFINES += DEBUG - -#CONFIG(release, debug|release) -#{ -# QMAKE_CFLAGS_RELEASE -= -O -# QMAKE_CFLAGS_RELEASE -= -O1 -# QMAKE_CFLAGS_RELEASE -= -O2 -# QMAKE_CFLAGS_RELEASE *= -O3 -#} - -LIBS += -ldl -pthread - -SOURCES += \ - ../../src/ConfigParser.cpp \ - ../../src/DataVariantFormUrlencoded.cpp \ - ../../src/DataVariantMultipartFormData.cpp \ - ../../src/DataVariantTextPlain.cpp \ - ../../src/Event.cpp \ - ../../src/FileIncoming.cpp \ - ../../src/Main.cpp \ - ../../src/Module.cpp \ - ../../src/RequestParameters.cpp \ - ../../src/Server.cpp \ - ../../src/ServerApplicationsTree.cpp \ - ../../src/Socket.cpp \ - ../../src/SocketList.cpp \ - ../../src/System.cpp \ - ../../src/Utils.cpp \ - ../../src/SignalHandlers.cpp - -include(deployment.pri) -qtcAddDeployment() - -HEADERS += \ - ../../src/ConfigParser.h \ - ../../src/DataVariantAbstract.h \ - ../../src/DataVariantFormUrlencoded.h \ - ../../src/DataVariantMultipartFormData.h \ - ../../src/DataVariantTextPlain.h \ - ../../src/Event.h \ - ../../src/FileIncoming.h \ - ../../src/Main.h \ - ../../src/Module.h \ - ../../src/RawData.h \ - ../../src/RequestParameters.h \ - ../../src/Server.h \ - ../../src/ServerApplicationDefaultSettings.h \ - ../../src/ServerApplicationSettings.h \ - ../../src/ServerApplicationsTree.h \ - ../../src/ServerRequest.h \ - ../../src/ServerResponse.h \ - ../../src/Socket.h \ - ../../src/SocketList.h \ - ../../src/System.h \ - ../../src/Utils.h \ - ../../src/SignalHandlers.h diff --git a/projects/qt-creator/httpserver.pro.user b/projects/qt-creator/httpserver.pro.user deleted file mode 100644 index 285b143..0000000 --- a/projects/qt-creator/httpserver.pro.user +++ /dev/null @@ -1,271 +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 - 0 - true - 0 - 8 - true - 1 - true - 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 - - httpserver - httpserver2 - Qt4ProjectManager.Qt4RunConfiguration:/media/projects/httpserver/projects/qt-creator/httpserver.pro - --start - httpserver.pro - false - true - /media/projects/sites/servertest/httpserver/Debug - 3768 - false - true - false - false - true - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 18 - - - Version - 18 - - diff --git a/projects/qt-creator/httpserver.qbs b/projects/qt-creator/httpserver.qbs new file mode 100644 index 0000000..4fc4050 --- /dev/null +++ b/projects/qt-creator/httpserver.qbs @@ -0,0 +1,71 @@ +import qbs + +Project { + CppApplication { + name: "httpserver" + + cpp.cxxLanguageVersion: "c++14" + + 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/ConfigParser.cpp", + "../../src/ConfigParser.h", + "../../src/DataVariantAbstract.h", + "../../src/DataVariantFormUrlencoded.cpp", + "../../src/DataVariantFormUrlencoded.h", + "../../src/DataVariantMultipartFormData.cpp", + "../../src/DataVariantMultipartFormData.h", + "../../src/DataVariantTextPlain.cpp", + "../../src/DataVariantTextPlain.h", + "../../src/Event.cpp", + "../../src/Event.h", + "../../src/FileIncoming.cpp", + "../../src/FileIncoming.h", + "../../src/Main.cpp", + "../../src/Main.h", + "../../src/Module.cpp", + "../../src/Module.h", + "../../src/RawData.h", + "../../src/RequestParameters.cpp", + "../../src/RequestParameters.h", + "../../src/Server.cpp", + "../../src/Server.h", + "../../src/ServerApplicationDefaultSettings.h", + "../../src/ServerApplicationSettings.h", + "../../src/ServerApplicationsTree.cpp", + "../../src/ServerApplicationsTree.h", + "../../src/ServerRequest.h", + "../../src/ServerResponse.h", + "../../src/SignalHandlers.cpp", + "../../src/SignalHandlers.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/SocketList.cpp", + "../../src/SocketList.h", + "../../src/System.cpp", + "../../src/System.h", + "../../src/Utils.cpp", + "../../src/Utils.h", + ] + } +} diff --git a/samples/apps.conf b/samples/apps.conf index 9955438..775c087 100644 --- a/samples/apps.conf +++ b/samples/apps.conf @@ -1,8 +1,21 @@ server { listen 2280; + server_name servertest www.servertest; - server_module /media/projects/appgameserver/build/Release/libappgameserver.so; - server_module_update /media/projects/httpserverapp/httpserverapp/bin/Release/libhttpserverapp.so; + server_module /media/projects/sites/servertest/module/httpserverapp-release.so; + server_module_update /media/projects/httpserverapp/build/Release/libhttpserverapp.so; + root_dir /media/projects/sites/servertest/www/; request_max_size 10485760; + +# Comments lines +# listen 2281 tls; + +# tls_certificate /media/projects/sites/servertest/cert/cert1.pem; +# tls_certificate_key /media/projects/sites/servertest/cert/privkey1.pem; + +# tls_certificate_chain /media/projects/sites/servertest/cert/chain1.pem; +# tls_certificate_crl /media/projects/sites/servertest/cert/crl.pem; + +# tls_stapling_file /media/projects/sites/servertest/cert/ocsp.der; } diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 1af4e31..93f001c 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -29,7 +29,7 @@ namespace HttpServer std::streamsize file_size = file.tellg(); file.seekg(0, std::ifstream::beg); - const std::streamsize file_size_max = 2048 * 1024; + const std::streamsize file_size_max = 2 * 1024 * 1024; if (file_size_max < file_size) { @@ -57,17 +57,17 @@ namespace HttpServer * Config - add application */ bool ConfigParser::addApplication( - const std::unordered_map &app, + const std::unordered_multimap &app, const ServerApplicationDefaultSettings &defaults, std::vector &modules, ServerApplicationsTree &apps_tree ) { - auto it_name = app.find("server_name"); + auto const it_name = app.find("server_name"); if (app.cend() == it_name) { - std::cout << "Error: application parameter 'server_name' is not specified;" << std::endl; + std::cout << "Error: application parameter 'server_name' has not been specified;" << std::endl; return false; } @@ -95,27 +95,110 @@ namespace HttpServer names.emplace_back(std::move(name) ); } - auto it_port = app.find("listen"); + auto const range_port = app.equal_range("listen"); - if (app.cend() == it_port) + if (range_port.first == range_port.second) { std::cout << "Error: application port is not set;" << std::endl; return false; } - auto it_root_dir = app.find("root_dir"); + std::unordered_set ports; + std::unordered_set tls_ports; + + for (auto it = range_port.first; it != range_port.second; ++it) + { + const std::string &lis = it->second; + + const bool is_tls = std::string::npos != lis.find("tls"); + + const std::vector list = Utils::explode(lis, ' '); + + for (auto const &value : list) + { + const int port = std::strtol(value.c_str(), nullptr, 10); + + if (port) + { + if (is_tls) + { + tls_ports.emplace(port); + } + else + { + ports.emplace(port); + } + } + } + } + + std::string cert_file; + std::string key_file; + std::string chain_file; + std::string crl_file; + std::string stapling_file; + + if (false == tls_ports.empty() ) + { + auto const it_ca_file = app.find("tls_certificate_chain"); + + if (app.cend() != it_ca_file) + { + chain_file = it_ca_file->second; + } + + auto const it_crl_file = app.find("tls_certificate_crl"); + + if (app.cend() != it_crl_file) + { + crl_file = it_crl_file->second; + } + + auto const it_stapling_file = app.find("tls_stapling_file"); + + if (app.cend() != it_stapling_file) + { + stapling_file = it_stapling_file->second; + } + + auto const it_cert_file = app.find("tls_certificate"); + + if (app.cend() == it_cert_file) + { + std::cout << "Error: tls certificate file \"CERT\" has not been specified in configuration file;" << std::endl; + tls_ports.clear(); + } + else + { + cert_file = it_cert_file->second; + } + + auto const it_key_file = app.find("tls_certificate_key"); + + if (app.cend() == it_key_file) + { + std::cout << "Error: tls certificate key file \"KEY\" has not been specified in configuration file;" << std::endl; + tls_ports.clear(); + } + else + { + key_file = it_key_file->second; + } + } + + auto const it_root_dir = app.find("root_dir"); if (app.cend() == it_root_dir || it_root_dir->second.empty() ) { - std::cout << "Error: application parameter 'root_dir' is not specified;" << std::endl; + std::cout << "Error: application parameter 'root_dir' has not been specified;" << std::endl; return false; } - auto it_module = app.find("server_module"); + auto const it_module = app.find("server_module"); if (app.cend() == it_module) { - std::cout << "Error: application parameter 'server_module' is not specified;" << std::endl; + std::cout << "Error: application parameter 'server_module' has not been specified;" << std::endl; return false; } @@ -187,17 +270,17 @@ namespace HttpServer return false; } - auto it_temp_dir = app.find("temp_dir"); + auto const it_temp_dir = app.find("temp_dir"); - const std::string temp_dir = app.cend() != it_temp_dir ? it_temp_dir->second : defaults.temp_dir; + std::string temp_dir = app.cend() != it_temp_dir ? it_temp_dir->second : defaults.temp_dir; - auto it_request_max_size = app.find("request_max_size"); + auto const it_request_max_size = app.find("request_max_size"); const size_t request_max_size = app.cend() != it_request_max_size ? std::strtoull(it_request_max_size->second.c_str(), nullptr, 10) : defaults.request_max_size; - auto it_module_update = app.find("server_module_update"); + auto const it_module_update = app.find("server_module_update"); - const std::string module_update = app.cend() != it_module_update ? it_module_update->second : ""; + std::string module_update = app.cend() != it_module_update ? it_module_update->second : ""; // Calculate module index size_t module_index = std::numeric_limits::max(); @@ -233,30 +316,40 @@ namespace HttpServer } // Create application settings struct - ServerApplicationSettings *sets = new ServerApplicationSettings { - std::strtol(it_port->second.c_str(), nullptr, 10), - root_dir, - temp_dir, + ServerApplicationSettings *settings = new ServerApplicationSettings { + std::move(ports), + std::move(tls_ports), + + std::move(root_dir), + std::move(temp_dir), request_max_size, + module_index, it_module->second, - module_update, - app_call, - app_clear, - app_init, - app_final + std::move(module_update), + + std::move(cert_file), + std::move(key_file), + std::move(chain_file), + std::move(crl_file), + std::move(stapling_file), + + std::move(app_call), + std::move(app_clear), + std::move(app_init), + std::move(app_final) }; // Add application names in tree if (names.empty() ) { - apps_tree.addApplication(app_name, sets); + apps_tree.addApplication(app_name, settings); } else { for (size_t i = 0; i < names.size(); ++i) { - apps_tree.addApplication(names[i], sets); + apps_tree.addApplication(names[i], settings); } } @@ -359,6 +452,36 @@ namespace HttpServer return true; } + static size_t findBlockEnd(const std::string &str_buf, size_t str_pos) + { + size_t pos = str_buf.find('}', str_pos); + + while (std::string::npos != pos) + { + size_t begin_line = str_buf.rfind('\n', pos); + + if (std::string::npos == begin_line) + { + begin_line = 0; + } + + begin_line = str_buf.find_first_not_of("\r\n", begin_line); + + if ('#' == str_buf[begin_line]) + { + str_pos = str_buf.find_first_of("\r\n", pos); + } + else + { + break; + } + + pos = str_buf.find('}', str_pos); + } + + return pos; + } + /** * Config - parse */ @@ -377,7 +500,7 @@ namespace HttpServer return false; } - std::vector > applications; + std::vector > applications; const std::string whitespace(" \t\n\v\f\r"); @@ -398,22 +521,34 @@ namespace HttpServer { std::string param_name = str_buf.substr(cur_pos, delimiter - cur_pos); - cur_pos = str_buf.find_first_not_of(whitespace, delimiter + 1); - delimiter = str_buf.find_last_not_of(whitespace, end_pos); + if ('#' != param_name.front() ) + { + cur_pos = str_buf.find_first_not_of(whitespace, delimiter + 1); + delimiter = str_buf.find_last_not_of(whitespace, end_pos); - std::string param_value = str_buf.substr(cur_pos, delimiter - cur_pos); + std::string param_value = str_buf.substr(cur_pos, delimiter - cur_pos); - if ("include" == param_name) - { - this->includeConfigFile(param_value, str_buf, end_pos + 1); + if ("include" == param_name) + { + this->includeConfigFile(param_value, str_buf, end_pos + 1); + } + else + { + settings.emplace(std::move(param_name), std::move(param_value) ); + } } - else + else // if comment line { - settings.emplace(std::move(param_name), std::move(param_value) ); + end_pos = str_buf.find_first_of("\r\n", cur_pos); } } - cur_pos = end_pos + 1; + cur_pos = end_pos; + + if (std::string::npos != cur_pos) + { + ++cur_pos; + } } else if (std::string::npos != block_pos) { @@ -422,69 +557,100 @@ namespace HttpServer const std::string block_type_name = str_buf.substr(cur_pos, delimiter - cur_pos); - delimiter = str_buf.find_first_not_of(whitespace, delimiter); + if ('#' != block_type_name.front() ) + { + delimiter = str_buf.find_first_not_of(whitespace, delimiter); - cur_pos = block_pos + 1; - size_t block_end = str_buf.find('}', cur_pos); + cur_pos = block_pos + 1; + size_t block_end = findBlockEnd(str_buf, cur_pos); - if (delimiter == block_pos) - { - if ("server" == block_type_name) + if (std::string::npos == block_end) { - std::unordered_map app; + std::cout << "Error: symbol '}' after '" << block_type_name << "' has not been found;" << std::endl + << "Parsing config aborted;" << std::endl; - end_pos = str_buf.find(';', cur_pos); - - while (block_end > end_pos) + return false; + } + else if (delimiter == block_pos) + { + if ("server" == block_type_name) { - cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - delimiter = str_buf.find_first_of(whitespace, cur_pos); + std::unordered_multimap app; - if (delimiter < end_pos) - { - std::string param_name = str_buf.substr(cur_pos, delimiter - cur_pos); - - cur_pos = str_buf.find_first_not_of(whitespace, delimiter + 1); - delimiter = str_buf.find_last_not_of(whitespace, end_pos); + end_pos = str_buf.find(';', cur_pos); - std::string param_value = str_buf.substr(cur_pos, delimiter - cur_pos); + while (block_end > end_pos) + { + cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); + delimiter = str_buf.find_first_of(whitespace, cur_pos); - if ("include" == param_name) + if (delimiter < end_pos) { - cur_pos = end_pos + 1; - this->includeConfigFile(param_value, str_buf, cur_pos); - block_end = str_buf.find('}', cur_pos); + std::string param_name = str_buf.substr(cur_pos, delimiter - cur_pos); + + if ('#' != param_name.front() ) + { + cur_pos = str_buf.find_first_not_of(whitespace, delimiter + 1); + delimiter = str_buf.find_last_not_of(whitespace, end_pos); + + std::string param_value = str_buf.substr(cur_pos, delimiter - cur_pos); + + if ("include" == param_name) + { + cur_pos = end_pos + 1; + this->includeConfigFile(param_value, str_buf, cur_pos); + block_end = findBlockEnd(str_buf, cur_pos); + } + else + { + app.emplace(std::move(param_name), std::move(param_value) ); + } + } + else // if comment line + { + end_pos = str_buf.find_first_of("\r\n", cur_pos); + } } - else + + if (std::string::npos != end_pos) { - app.emplace(std::move(param_name), std::move(param_value) ); + ++end_pos; } - } - cur_pos = end_pos + 1; + cur_pos = end_pos; - end_pos = str_buf.find(';', cur_pos); - } + end_pos = str_buf.find(';', cur_pos); + } - applications.emplace_back(std::move(app) ); + applications.emplace_back(std::move(app) ); + } + else + { + std::cout << "Warning: " << block_type_name << " - unknown block type;" << std::endl; + } } else { - std::cout << "Warning: " << block_type_name << " - unknown block type;" << std::endl; + std::cout << "Warning: after " << block_type_name << " expected '{' ;" << std::endl; + } + + cur_pos = block_end; + + if (std::string::npos != cur_pos) + { + ++cur_pos; } } - else + else // if comment line { - std::cout << "Warning: after " << block_type_name << " expected '{' ;" << std::endl; + cur_pos = str_buf.find_first_of("\r\n", cur_pos); } - - cur_pos = block_end + 1; } end_pos = str_buf.find(';', cur_pos); } - auto it_mimes = settings.find("mimes"); + auto const it_mimes = settings.find("mimes"); if (settings.cend() != it_mimes) { @@ -497,11 +663,11 @@ namespace HttpServer if (false == applications.empty() ) { - auto it_default_temp_dir = settings.find("default_temp_dir"); + auto const it_default_temp_dir = settings.find("default_temp_dir"); const std::string default_temp_dir = settings.cend() != it_default_temp_dir ? it_default_temp_dir->second : System::getTempDir(); - auto it_default_request_max_size = settings.find("request_max_size"); + auto const it_default_request_max_size = settings.find("request_max_size"); const size_t default_request_max_size = settings.cend() != it_default_request_max_size ? std::strtoull(it_default_request_max_size->second.c_str(), nullptr, 10) : 0; @@ -510,7 +676,7 @@ namespace HttpServer default_request_max_size }; - for (auto &app : applications) + for (auto const &app : applications) { this->addApplication(app, defaults, modules, apps_tree); } diff --git a/src/ConfigParser.h b/src/ConfigParser.h index 45b1976..07af9c9 100644 --- a/src/ConfigParser.h +++ b/src/ConfigParser.h @@ -15,7 +15,7 @@ namespace HttpServer static bool includeConfigFile(const std::string &fileName, std::string &strBuf, const size_t offset = 0); static bool addApplication( - const std::unordered_map &app, + const std::unordered_multimap &app, const ServerApplicationDefaultSettings &defaults, std::vector &modules, ServerApplicationsTree &apps_tree diff --git a/src/DataVariantAbstract.h b/src/DataVariantAbstract.h index 88c5581..9058696 100644 --- a/src/DataVariantAbstract.h +++ b/src/DataVariantAbstract.h @@ -1,6 +1,6 @@ #pragma once -#include "Socket.h" +#include "SocketAdapter.h" #include "RequestParameters.h" namespace HttpServer @@ -30,7 +30,7 @@ namespace HttpServer */ virtual bool parse ( - const Socket &sock, + const SocketAdapter &sock, std::string &str, const size_t leftBytes, std::unordered_map &contentParams, diff --git a/src/DataVariantFormUrlencoded.cpp b/src/DataVariantFormUrlencoded.cpp index 82dd992..6dc674b 100644 --- a/src/DataVariantFormUrlencoded.cpp +++ b/src/DataVariantFormUrlencoded.cpp @@ -12,7 +12,7 @@ namespace HttpServer bool DataVariantFormUrlencoded::parse ( - const Socket &sock, + const SocketAdapter &sock, std::string &str, const size_t leftBytes, std::unordered_map &contentParams, diff --git a/src/DataVariantFormUrlencoded.h b/src/DataVariantFormUrlencoded.h index 9b9d641..0c848c1 100644 --- a/src/DataVariantFormUrlencoded.h +++ b/src/DataVariantFormUrlencoded.h @@ -12,7 +12,7 @@ namespace HttpServer public: virtual bool parse ( - const Socket &sock, + const SocketAdapter &sock, std::string & str, const size_t leftBytes, std::unordered_map &contentParams, diff --git a/src/DataVariantMultipartFormData.cpp b/src/DataVariantMultipartFormData.cpp index 3b6b20e..c79b309 100644 --- a/src/DataVariantMultipartFormData.cpp +++ b/src/DataVariantMultipartFormData.cpp @@ -13,13 +13,13 @@ namespace HttpServer bool DataVariantMultipartFormData::append ( - const Socket &sock, + const SocketAdapter &sock, const std::chrono::milliseconds &timeout, std::vector &buf, std::string &str_buf, const std::string &data_end, const size_t &leftBytes, - size_t &recv_len, + long &recv_len, size_t &recv_total_len ) { @@ -33,7 +33,7 @@ namespace HttpServer recv_len = sock.nonblock_recv(buf, timeout); // Завершаем работу, если ошибка получения данных через сокет - if (0 == recv_len || std::numeric_limits::max() == recv_len) + if (recv_len <= 0) { return false; } @@ -55,7 +55,7 @@ namespace HttpServer bool DataVariantMultipartFormData::parse ( - const Socket &sock, + const SocketAdapter &sock, std::string &str, const size_t leftBytes, std::unordered_map &contentParams, @@ -88,7 +88,7 @@ namespace HttpServer // Создание буферов std::vector buf(buf_len); - size_t recv_len; // Прочитано байт при последнем извлечении данных из сокета + long recv_len; // Прочитано байт при последнем извлечении данных из сокета size_t recv_total_len = 0; // Получено байт из сокета всего // Поиск разделителя блока данных diff --git a/src/DataVariantMultipartFormData.h b/src/DataVariantMultipartFormData.h index 28628fa..0a72b68 100644 --- a/src/DataVariantMultipartFormData.h +++ b/src/DataVariantMultipartFormData.h @@ -12,20 +12,20 @@ namespace HttpServer protected: static bool append ( - const Socket &sock, + const SocketAdapter &sock, const std::chrono::milliseconds &timeout, std::vector &buf, std::string &str_buf, const std::string &data_end, const size_t &leftBytes, - size_t &recv_len, + long &recv_len, size_t &recv_total_len ); public: virtual bool parse ( - const Socket &sock, + const SocketAdapter &sock, std::string &str, const size_t leftBytes, std::unordered_map &contentParams, diff --git a/src/DataVariantTextPlain.cpp b/src/DataVariantTextPlain.cpp index 585b377..2d5a6b1 100644 --- a/src/DataVariantTextPlain.cpp +++ b/src/DataVariantTextPlain.cpp @@ -10,7 +10,7 @@ namespace HttpServer bool DataVariantTextPlain::parse ( - const Socket &sock, + const SocketAdapter &sock, std::string &str, const size_t leftBytes, std::unordered_map &contentParams, diff --git a/src/DataVariantTextPlain.h b/src/DataVariantTextPlain.h index 28c1bcc..d3fb2ac 100644 --- a/src/DataVariantTextPlain.h +++ b/src/DataVariantTextPlain.h @@ -12,7 +12,7 @@ namespace HttpServer public: virtual bool parse ( - const Socket &sock, + const SocketAdapter &sock, std::string &str, const size_t leftBytes, std::unordered_map &contentParams, diff --git a/src/Server.cpp b/src/Server.cpp index 90ec702..62a2bfc 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -10,6 +10,8 @@ #include "ServerRequest.h" #include "ServerResponse.h" #include "ConfigParser.h" +#include "SocketAdapterDefault.h" +#include "SocketAdapterTls.h" #include #include @@ -144,7 +146,7 @@ namespace HttpServer int Server::transferFilePart ( - const Socket &clientSocket, + const SocketAdapter &clientSocket, const std::chrono::milliseconds &timeout, const std::string &fileName, const time_t fileTime, @@ -212,7 +214,7 @@ namespace HttpServer + connectionHeader + dateHeader + "\r\n"; // Отправить заголовки - if (std::numeric_limits::max() == clientSocket.nonblock_send(headers, timeout) ) + if (clientSocket.nonblock_send(headers, timeout) < 0) { file.close(); @@ -221,19 +223,19 @@ namespace HttpServer if (false == headersOnly) { + size_t position, length; + for (auto const &range : ranges) { - const size_t length = std::get<1>(range); + std::tie(position, length) = range; std::vector buf(length < 512 * 1024 ? length : 512 * 1024); - const size_t position = std::get<0>(range); - file.seekg(position, file.beg); size_t send_size_left = length; - size_t send_size; + long send_size; do { @@ -247,7 +249,7 @@ namespace HttpServer send_size_left -= send_size; } - while (false == file.eof() && false == file.fail() && std::numeric_limits::max() != send_size && send_size_left); + while (false == file.eof() && false == file.fail() && send_size > 0 && send_size_left); } } @@ -261,7 +263,7 @@ namespace HttpServer */ int Server::transferFile ( - const Socket &clientSocket, + const SocketAdapter &clientSocket, const std::string &fileName, const std::string &connectionHeader, const bool headersOnly, @@ -340,7 +342,7 @@ namespace HttpServer + connectionHeader + date_header + "\r\n"; // Отправить заголовки - if (std::numeric_limits::max() == clientSocket.nonblock_send(headers, rp.timeout) ) + if (clientSocket.nonblock_send(headers, rp.timeout) < 0) { file.close(); @@ -352,14 +354,14 @@ namespace HttpServer { std::vector buf(file_size < 512 * 1024 ? file_size : 512 * 1024); - size_t send_size; + long send_size; do { file.read(reinterpret_cast(buf.data() ), buf.size() ); send_size = clientSocket.nonblock_send(buf, file.gcount(), rp.timeout); } - while (false == file.eof() && false == file.fail() && std::numeric_limits::max() != send_size); + while (false == file.eof() && false == file.fail() && send_size > 0); } file.close(); @@ -411,7 +413,7 @@ namespace HttpServer return false; } - void Server::sendStatus(const Socket &clientSocket, const std::chrono::milliseconds &timeout, const size_t statusCode) + void Server::sendStatus(const SocketAdapter &clientSocket, const std::chrono::milliseconds &timeout, const size_t statusCode) { static const std::unordered_map statuses { {400, "Bad Request"}, @@ -434,7 +436,7 @@ namespace HttpServer /** * Метод для обработки запроса */ - int Server::threadRequestProc(Socket clientSocket) const + int Server::threadRequestProc(SocketAdapter &clientSocket, const struct sockaddr_in &clientAddr) const { struct request_parameters rp; @@ -506,30 +508,23 @@ namespace HttpServer if (false == isConnectionUpgrade(rp) ) { - // Wait for send all data to client - clientSocket.nonblock_send_sync(); - - clientSocket.shutdown(); clientSocket.close(); } return rp.app_exit_code; } - bool Server::getRequest(Socket clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp) + bool Server::getRequest(const SocketAdapter &clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp) { // Получить данные запроса от клиента - const size_t recv_size = clientSocket.nonblock_recv(buf, rp.timeout); + const long recv_size = clientSocket.nonblock_recv(buf, rp.timeout); - if (std::numeric_limits::max() == recv_size && str_buf.empty() ) + if (recv_size < 0 && str_buf.empty() ) { - #ifdef DEBUG - std::cout << "Error: " << Socket::getLastError() << std::endl; - #endif return false; } - if (recv_size) // Если данные были получены + if (recv_size > 0) // Если данные были получены { str_buf.append(buf.cbegin(), buf.cbegin() + recv_size); } @@ -654,7 +649,7 @@ namespace HttpServer return 0; } - void Server::runApplication(Socket clientSocket, const ServerApplicationSettings &appSets, struct request_parameters &rp) + void Server::runApplication(const SocketAdapter &clientSocket, const ServerApplicationSettings &appSets, struct request_parameters &rp) { Utils::raw_pair *raw_pair_params = nullptr; Utils::raw_pair *raw_pair_headers = nullptr; @@ -668,6 +663,7 @@ namespace HttpServer server_request request { clientSocket.get_handle(), + clientSocket.get_tls_session(), rp.method.c_str(), rp.uri_reference.c_str(), appSets.root_dir.c_str(), @@ -685,10 +681,9 @@ namespace HttpServer clientSocket.get_handle(), 0, nullptr }; - // Попытаться try { - // Запустить приложение + // Launch application rp.app_exit_code = appSets.application_call(&request, &response); } catch (...) @@ -714,7 +709,7 @@ namespace HttpServer Utils::destroyRawFilesInfo(raw_fileinfo_files, rp.incoming_files.size() ); } - int Server::getRequestData(Socket clientSocket, std::string &str_buf, const ServerApplicationSettings &appSets, struct request_parameters &rp) const + int Server::getRequestData(const SocketAdapter &clientSocket, std::string &str_buf, const ServerApplicationSettings &appSets, struct request_parameters &rp) const { // Определить вариант данных запроса (заодно проверить, есть ли данные) auto const it = rp.incoming_headers.find("Content-Type"); @@ -860,7 +855,7 @@ namespace HttpServer const ServerApplicationSettings *app_sets = this->apps_tree.find(host); // Если приложение найдено - if (app_sets && app_sets->port == port) + if (app_sets && (app_sets->ports.cend() != app_sets->ports.find(port) || app_sets->tls_ports.cend() != app_sets->tls_ports.find(port) ) ) { return app_sets; } @@ -869,7 +864,7 @@ namespace HttpServer return nullptr; } - void Server::xSendfile(Socket clientSocket, struct request_parameters &rp) const + void Server::xSendfile(const SocketAdapter &clientSocket, struct request_parameters &rp) const { auto const it_x_sendfile = rp.outgoing_headers.find("X-Sendfile"); @@ -939,11 +934,12 @@ namespace HttpServer * Метод для обработки запросов (запускается в отдельном потоке) * извлекает сокет клиенты из очереди и передаёт его на обслуживание */ - void Server::threadRequestCycle(std::queue &sockets, Event &eventThreadCycle) const + void Server::threadRequestCycle(std::queue > &sockets, Event &eventThreadCycle) const { while (true) { Socket clientSocket; + struct sockaddr_in addr; eventThreadCycle.wait(); @@ -956,7 +952,8 @@ namespace HttpServer if (sockets.size() ) { - clientSocket = std::move(sockets.front() ); + std::tie(clientSocket, addr) = sockets.front(); + sockets.pop(); } @@ -973,7 +970,36 @@ namespace HttpServer { ++this->threads_working_count; - this->threadRequestProc(clientSocket); + struct ::sockaddr_in p; + ::socklen_t p_len = sizeof(p); + + ::getsockname(clientSocket.get_handle(), reinterpret_cast(&p), &p_len); + + const int port = ntohs(p.sin_port); + + auto const it = this->tls_data.find(port); + + if (this->tls_data.cend() != it) // if TLS connection + { + const std::tuple &data = it->second; + + SocketAdapterTls sock( + clientSocket, + std::get(data), + std::get(data) + ); + + if (sock.handshake() ) + { + this->threadRequestProc(sock, addr); + } + } + else + { + SocketAdapterDefault sock(clientSocket); + + this->threadRequestProc(sock, addr); + } --this->threads_working_count; } @@ -983,15 +1009,17 @@ namespace HttpServer /** * Цикл управления количеством рабочих потоков */ - int Server::cycleQueue(std::queue &sockets) + int Server::cycleQueue(std::queue > &sockets) { - auto it_option = this->settings.find("threads_max_count"); + auto const it_option = this->settings.find("threads_max_count"); size_t threads_max_count = 0; if (this->settings.cend() != it_option) { - threads_max_count = std::strtoull(it_option->second.c_str(), nullptr, 10); + const std::string &option = it_option->second; + + threads_max_count = std::strtoull(option.c_str(), nullptr, 10); } if (0 == threads_max_count) @@ -1010,7 +1038,7 @@ namespace HttpServer Event eventThreadCycle(false, true); - std::function &, Event &)> serverThreadRequestCycle = std::mem_fn(&Server::threadRequestCycle); + std::function > &, Event &)> serverThreadRequestCycle = std::mem_fn(&Server::threadRequestCycle); std::vector active_threads; active_threads.reserve(threads_max_count); @@ -1329,6 +1357,8 @@ namespace HttpServer this->addDataVariant(new DataVariantMultipartFormData() ); this->addDataVariant(new DataVariantTextPlain() ); + ::gnutls_global_init(); + return true; } @@ -1367,6 +1397,17 @@ namespace HttpServer this->variants.clear(); } + if (false == this->tls_data.empty() ) + { + for (auto &pair : this->tls_data) + { + std::tuple &data = pair.second; + + ::gnutls_certificate_free_credentials(std::get<0>(data) ); + ::gnutls_priority_deinit(std::get<1>(data) ); + } + } + if (false == this->apps_tree.empty() ) { std::unordered_set applications; @@ -1407,15 +1448,129 @@ namespace HttpServer { this->settings.clear(); } + + ::gnutls_global_deinit(); } - int Server::run() + bool Server::tlsInit(const ServerApplicationSettings &app, std::tuple &data) { - if (false == init() ) + ::gnutls_certificate_credentials_t x509_cred; + + int ret = ::gnutls_certificate_allocate_credentials(&x509_cred); + + if (ret < 0) { - return 1; + std::cout << "Error: tls certificate credentials has not been allocated;" << std::endl; + + return false; + } + + if (false == app.chain_file.empty() ) + { + ret = ::gnutls_certificate_set_x509_trust_file(x509_cred, app.chain_file.c_str(), GNUTLS_X509_FMT_PEM); + + if (ret < 0) + { + std::cout << "Warning: (CA) chain file has not been accepted;" << std::endl; + } + } + + if (false == app.crl_file.empty() ) + { + ret = ::gnutls_certificate_set_x509_crl_file(x509_cred, app.crl_file.c_str(), GNUTLS_X509_FMT_PEM); + + if (ret < 0) + { + std::cout << "Warning: (CLR) clr file has not been accepted;" << std::endl; + } + } + + ret = ::gnutls_certificate_set_x509_key_file(x509_cred, app.cert_file.c_str(), app.key_file.c_str(), GNUTLS_X509_FMT_PEM); + + if (ret < 0) + { + std::cout << "Error: (CERT) tls cert file or/and (KEY) tls key file has not been accepted;" << std::endl; + + return false; + } + + if (false == app.stapling_file.empty() ) + { + ret = ::gnutls_certificate_set_ocsp_status_request_file(x509_cred, app.stapling_file.c_str(), 0); + + if (ret < 0) + { + std::cout << "Warning: (OCSP) tls stapling file has not been accepted;" << std::endl; + } + } + + ::gnutls_dh_params_t dh_params; + + ::gnutls_dh_params_init(&dh_params); + + const unsigned int bits = ::gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY); + + ::gnutls_dh_params_generate2(dh_params, bits); + + ::gnutls_certificate_set_dh_params(x509_cred, dh_params); + + ::gnutls_priority_t priority_cache; + + ret = ::gnutls_priority_init(&priority_cache, "NORMAL", nullptr); + + if (ret < 0) + { + ::gnutls_certificate_free_credentials(x509_cred); + + std::cout << "Error: failed tls priority init;" << std::endl; + + return false; + } + + data = std::tuple{x509_cred, priority_cache}; + + return true; + } + + bool Server::tryBindPort(const int port, std::unordered_set &ports) + { + // Only unique ports + if (ports.cend() != ports.find(port) ) + { + return false; } + Socket sock; + + if (false == sock.open() ) + { + std::cout << "Error: cannot open socket; errno " << Socket::getLastError() << ";" << std::endl; + return false; + } + + if (false == sock.bind(port) ) + { + std::cout << "Error: cannot bind socket " << port << "; errno " << Socket::getLastError() << ";" << std::endl; + return false; + } + + if (false == sock.listen() ) + { + std::cout << "Error: cannot listen socket " << port << "; errno " << Socket::getLastError() << ";" << std::endl; + return false; + } + + sock.nonblock(true); + + this->server_sockets.emplace_back(std::move(sock) ); + + ports.emplace(port); + + return true; + } + + void Server::initAppsPorts() + { // Applications settings list std::unordered_set applications; // Get full applications settings list @@ -1427,46 +1582,46 @@ namespace HttpServer // Open applications sockets for (auto const &app : applications) { - const int port = app->port; + const std::unordered_set &tls = app->tls_ports; - // Only unique ports - if (ports.cend() == ports.find(port) ) + if (false == tls.empty() ) { - Socket sock; + std::tuple data; - if (sock.open() ) + if (Server::tlsInit(*app, data) ) { - if (sock.bind(port) ) + for (const int port : tls) { - if (sock.listen() ) - { - sock.nonblock(true); - - this->server_sockets.emplace_back(std::move(sock) ); - - ports.emplace(port); - } - else + if (this->tryBindPort(port, ports) ) { - std::cout << "Error: cannot listen socket " << port << "; errno " << Socket::getLastError() << ";" << std::endl; + this->tls_data.emplace(port, data); } } - else - { - std::cout << "Error: cannot bind socket " << port << "; errno " << Socket::getLastError() << ";" << std::endl; - } - } - else - { - std::cout << "Error: cannot open socket; errno " << Socket::getLastError() << ";" << std::endl; } } + + const std::unordered_set &list = app->ports; + + for (const int port : list) + { + this->tryBindPort(port, ports); + } + } + } + + int Server::run() + { + if (false == this->init() ) + { + return 1; } + this->initAppsPorts(); + if (this->server_sockets.empty() ) { std::cout << "Error: do not open any socket;" << std::endl; - clear(); + this->clear(); return 2; } @@ -1486,30 +1641,38 @@ namespace HttpServer this->eventProcessQueue = new Event(); this->eventUpdateModule = new Event(false, true); - std::queue sockets; + std::queue > sockets; this->process_flag = true; - std::function &)> serverCycleQueue = std::mem_fn(&Server::cycleQueue); - - std::vector client_sockets; - + std::function > &)> serverCycleQueue = std::mem_fn(&Server::cycleQueue); std::thread threadQueue(serverCycleQueue, this, std::ref(sockets) ); + std::vector accept_sockets; + std::vector accept_sockets_address; + // Cycle receiving new connections do { - if (sockets_list.accept(client_sockets) ) + if (sockets_list.accept(accept_sockets, accept_sockets_address) ) { this->sockets_queue_mtx.lock(); - for (Socket &sock : client_sockets) + for (size_t i = 0; i < accept_sockets.size(); ++i) { + const Socket &sock = accept_sockets[i]; + if (sock.is_open() ) { sock.nonblock(true); sock.tcp_nodelay(true); - sockets.emplace(std::move(sock) ); + + sockets.emplace( + std::tuple { + sock, + accept_sockets_address[i] + } + ); } } @@ -1522,7 +1685,8 @@ namespace HttpServer this->eventNotFullQueue->reset(); } - client_sockets.clear(); + accept_sockets.clear(); + accept_sockets_address.clear(); this->eventNotFullQueue->wait(); } @@ -1535,7 +1699,7 @@ namespace HttpServer sockets_list.destroy(); - clear(); + this->clear(); std::cout << "Log: final server cycle;" << std::endl; @@ -1620,7 +1784,7 @@ namespace HttpServer std::cout << "Available arguments:" << std::endl << std::setw(4) << ' ' << "--start" << "\t\t" << "Start http server" << std::endl << std::setw(4) << ' ' << "--restart" << "\t\t" << "Restart http server" << std::endl - << std::setw(4) << ' ' << "--update_module" << "\t" << "Update applications modules" << std::endl + << std::setw(4) << ' ' << "--update-module" << "\t" << "Update applications modules" << std::endl << std::setw(4) << ' ' << "--kill" << "\t\t" << "Shutdown http server" << std::endl << std::setw(4) << ' ' << "--help" << "\t\t" << "This help" << std::endl << std::endl; diff --git a/src/Server.h b/src/Server.h index 011bf38..28ca85b 100644 --- a/src/Server.h +++ b/src/Server.h @@ -6,6 +6,7 @@ #include "ServerApplicationDefaultSettings.h" #include "Module.h" #include "Event.h" +#include "SocketAdapter.h" #include #include @@ -14,6 +15,8 @@ #include #include +#include + namespace HttpServer { class Server @@ -24,6 +27,8 @@ namespace HttpServer std::unordered_map settings; std::unordered_map mimes_types; + std::unordered_map > tls_data; + std::vector modules; ServerApplicationsTree apps_tree; @@ -48,28 +53,28 @@ namespace HttpServer static const int CONNECTION_UPGRADE = 2; protected: - int cycleQueue(std::queue &sockets); + int cycleQueue(std::queue > &sockets); - int threadRequestProc(Socket clientSocket) const; + int threadRequestProc(SocketAdapter &clientSocket, const struct sockaddr_in &clientAddr) const; - static bool getRequest(Socket clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp); + static bool getRequest(const SocketAdapter &clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp); int getRequestHeaders(std::string &str_buf, struct request_parameters &rp) const; - static void runApplication(Socket clientSocket, const ServerApplicationSettings &appSets, struct request_parameters &rp); + static void runApplication(const SocketAdapter &clientSocket, const ServerApplicationSettings &appSets, struct request_parameters &rp); - int getRequestData(Socket clientSocket, std::string &str_buf, const ServerApplicationSettings &appSets, struct request_parameters &rp) const; + int getRequestData(const SocketAdapter &clientSocket, std::string &str_buf, const ServerApplicationSettings &appSets, struct request_parameters &rp) const; const ServerApplicationSettings *getApplicationSettings(const struct request_parameters &rp) const; static void getConnectionParams(struct request_parameters &rp); - void xSendfile(Socket clientSocket, struct request_parameters &rp) const; + void xSendfile(const SocketAdapter &clientSocket, struct request_parameters &rp) const; static bool isConnectionKeepAlive(const struct request_parameters &rp); static bool isConnectionUpgrade(const struct request_parameters &rp); - void threadRequestCycle(std::queue &sockets, Event &eventThreadCycle) const; + void threadRequestCycle(std::queue > &sockets, Event &eventThreadCycle) const; std::string getMimeTypeByFileName(const std::string &fileName) const; @@ -82,7 +87,7 @@ namespace HttpServer ) const; int transferFilePart( - const Socket &clientSocket, + const SocketAdapter &clientSocket, const std::chrono::milliseconds &timeout, const std::string &fileName, const time_t fileTime, @@ -94,7 +99,7 @@ namespace HttpServer ) const; int transferFile( - const Socket &clientSocket, + const SocketAdapter &clientSocket, const std::string &fileName, const std::string &connectionHeader, const bool headersOnly, @@ -102,7 +107,12 @@ namespace HttpServer ) const; static bool parseIncomingVars(std::unordered_multimap ¶ms, const std::string &uriParams); - static void sendStatus(const Socket &clientSocket, const std::chrono::milliseconds &timeout, const size_t statusCode); + static void sendStatus(const SocketAdapter &clientSocket, const std::chrono::milliseconds &timeout, const size_t statusCode); + + static bool tlsInit(const ServerApplicationSettings &app, std::tuple &data); + + bool tryBindPort(const int port, std::unordered_set &ports); + void initAppsPorts(); bool init(); int run(); diff --git a/src/ServerApplicationSettings.h b/src/ServerApplicationSettings.h index 62b40fe..809d099 100644 --- a/src/ServerApplicationSettings.h +++ b/src/ServerApplicationSettings.h @@ -4,6 +4,7 @@ #include "ServerResponse.h" #include "RawData.h" +#include #include #include @@ -11,7 +12,9 @@ namespace HttpServer { struct ServerApplicationSettings { - long int port; + std::unordered_set ports; + std::unordered_set tls_ports; + std::string root_dir; std::string temp_dir; size_t request_max_size; @@ -20,6 +23,12 @@ namespace HttpServer std::string server_module; std::string server_module_update; + std::string cert_file; + std::string key_file; + std::string chain_file; + std::string crl_file; + std::string stapling_file; + std::function application_call; std::function application_clear; std::function application_init; diff --git a/src/ServerRequest.h b/src/ServerRequest.h index 0982cc8..dc80893 100644 --- a/src/ServerRequest.h +++ b/src/ServerRequest.h @@ -1,7 +1,7 @@ #pragma once #include "RawData.h" -#include "Socket.h" +#include "SocketAdapterTls.h" #include "FileIncoming.h" #include @@ -11,6 +11,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 +28,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 +40,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; diff --git a/src/ServerResponse.h b/src/ServerResponse.h index f59400c..7573e3a 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; }; }; diff --git a/src/SignalHandlers.cpp b/src/SignalHandlers.cpp index 0943424..819db15 100644 --- a/src/SignalHandlers.cpp +++ b/src/SignalHandlers.cpp @@ -187,6 +187,9 @@ bool bindSignalHandlers(HttpServer::Server *server) act.sa_handler = handlerSigUsr2; ::sigaction(SIGUSR2, &act, nullptr); + + ::signal(SIGPIPE, SIG_IGN); + #else #error "Undefine platform" #endif 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/SocketList.cpp b/src/SocketList.cpp index ccfdd43..4d4fe0a 100644 --- a/src/SocketList.cpp +++ b/src/SocketList.cpp @@ -218,6 +218,86 @@ namespace HttpServer return false; } + bool SocketList::accept(std::vector &sockets, std::vector &socketsAddress) const + { + if (is_created() ) + { + #ifdef WIN32 + const int count = ::WSAPoll(this->poll_events.data(), 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, 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(); + #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 SocketList::recv(std::vector &sockets, std::vector &disconnected, std::chrono::milliseconds timeout) const { if (false == is_created() ) diff --git a/src/SocketList.h b/src/SocketList.h index c318157..b61f145 100644 --- a/src/SocketList.h +++ b/src/SocketList.h @@ -29,6 +29,7 @@ namespace HttpServer bool removeSocket(const Socket &sock); bool accept(std::vector &sockets) const; + bool accept(std::vector &sockets, std::vector &socketsAddress) const; bool recv(std::vector &sockets, std::vector &errors, std::chrono::milliseconds timeout = std::chrono::milliseconds(~0) ) const; }; From 5f0fc3fb55e815fc8176620146c7e24ef7f35661 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Tue, 26 Apr 2016 21:59:03 +0300 Subject: [PATCH 23/50] Added support of HTTPS for Windows --- README.md | 39 +++++++++++++------- projects/msvs/httpserver.v12.suo | Bin 158720 -> 0 bytes projects/msvs/httpserver.vcxproj | 44 ++++++++++++++++------- projects/msvs/httpserver.vcxproj.filters | 18 ++++++++++ projects/msvs/httpserver.vcxproj.user | 10 ++++++ src/ConfigParser.cpp | 4 +-- src/Socket.cpp | 4 +-- src/Socket.h | 8 +---- src/SocketAdapterTls.cpp | 2 +- src/System.cpp | 8 +++-- src/System.h | 1 + src/Utils.cpp | 12 ++++--- 12 files changed, 104 insertions(+), 46 deletions(-) delete mode 100644 projects/msvs/httpserver.v12.suo diff --git a/README.md b/README.md index ecc999d..13f88c7 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ httpserver Http server is written on C++14 language. Dynamic libraries act as applications for the server -(* .so - linux, * .dll - windows). +(\*.so - linux, \*.dll - windows). Library connection takes place in the configuration file -[samples/apps.conf] [samples/apps.conf] +[samples/apps.conf](samples/apps.conf) by using the parameter `server_module`. Sample application code: https://github.com/awwit/httpserverapp @@ -30,26 +30,39 @@ Common: * [gnutls](https://www.gnutls.org/) -Linux: +Linux: `dl`, `pthread`, `gnutls` -* dl -* pthread +Windows: `ws2_32.lib`, `libgnutls.dll.a` Build ----- Linux: - git clone https://github.com/awwit/httpserver.git - cd httpserver - mkdir build - cd build - qbs build -f ./../projects/qt-creator/httpserver.qbs release +```sh +git clone https://github.com/awwit/httpserver.git +cd httpserver +mkdir build +cd build +qbs build -f ./../projects/qt-creator/httpserver.qbs release +``` + +Windows: + +```sh +git clone https://github.com/awwit/httpserver.git +cd httpserver +mkdir build +cd build +devenv ./../projects/msvs/httpserver.sln /build +``` Server start ------------ - ./httpserver --start +```sh +./httpserver --start +``` Configuration files must be located in the working (current) directory. @@ -57,11 +70,11 @@ Server configuration -------------------- Server (and its applications) setting is made using config-files. -Examples of settings are located in the folder [samples][samples/]. +Examples of settings are located in the folder [samples](samples/). License ======= The source codes are licensed under the [AGPL](http://www.gnu.org/licenses/agpl.html), -the full text of the license is located in the [LICENSE][LICENSE] file. +the full text of the license is located in the [LICENSE](LICENSE) file. diff --git a/projects/msvs/httpserver.v12.suo b/projects/msvs/httpserver.v12.suo deleted file mode 100644 index 4cac25849ccc06e4b6d89ec083c1763ae7cab329..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 158720 zcmeHQ37i~NnXf>&@B4-c_mz;$h6NqqU?IGt_S=7*Xu9uRn@ERs-Buxoh6;$%k=bg_xsoP zzWe*$tM9(F+t2U$?Eb&-LXT6uExmudvz@oK@%om=b8lDA|JxRL?H}*F^A7(s3}Xbw zo)~y(^J5dBzznY!{|3Aoui5Lt&wg(ORxkNuZ*QxOYaQSZ%U8U0(A{79##!GRb{PKl zbd7q$*_g4{TkM^I*%#nhv$x#x$@rJ{_O{qKKgk{cPW_j2@f7UqKc;(2aMfMjBFxXR z(3^?hTQNF(EMvXV-q_-MZ9k6owisqEv+X^$*RCzTm}LHOwl65Y#`$-_^CK~mUO(6A z=Hlmf#LvH*7f^h@9bVrbgR;$W5T5UWu^+|`7~5cMkFh((UKo30@O}KQo$&ks3_SH8 z#CHhBSSSd-uygTmf?4K20DnIUf7=%02#n*3?^ECM&O09u{VuO>{#iK%T+09IV{fkt z`9B$av|0W^1U!UuL=TAE%j^6}x#q)^fAxy`-;{s8LiyhZgYteLe(sAw`RCuLM-Il= z3WM@5I)geujYv>%ujWL4J_u{K>VY{-#c+4DE(N8$jNm z-zU7l_2>I(FT{?J7i9g(4>cGgFb>6_PjEN}*PVPpJ8(3HIX9n=EWUOEevZZ%gHel7 zhavABZ#g9dv-O>LKufYEzpIz|> z^<531WUqIj*A1VqA3wGC7oE%Y%7GR5pY)x`+kDKzyamiV71vq-?Pq$Oz|)UsZN6t( zP;ZO#%_*ht1+Ss@U+u>${#ye2H&gzu%N(_Q@LIheo4Ysah0fS?yR7Gc&!{_J{I z`7~pIEr#umUm2Hh_4HrjpB;lgN&H`G{&O)qDbobXFehkxjDq}8KQhKiI=^}SGjU~I zzNe?IQPFt;u6Q9{?e}L^f3eN(dB;~E|IE!TEhcL_o4gafme67s@XA7;@SOlLAHQ{i z00UlMkswQbvb5m0ek@)KoL0hB3{*ha)aoyxVxv)bM<4$EYU_Kidh@Me_s@C!(l0!6 z&G`@Ta!4@q!EZSmpYAWtBcB~}*YM#l&f0mzdsjc({Dp(((SMfD&Ke~C!G7Mq{%OEW zwiUcn*WFUH*Dj|W)O*8U&pPM11D-SRZoFK+#)qQc3S2RTs~g|Z={@z(nA>0d(XT%} zX87^X{_)S>@om+{4;G)OPkZfyy?#J9;}79^iA!uUSDf1a!T9SCJY$?sWai)Eo}Yw2 zNc>^SJIP2UTIjRaD6j&F+JoQPp_eEN)Dl5NoXw(J&-iY0$-sTF82Wc2Ntm0`}ud%{xyK#+mQcQh}n7}2ekcD@vId;OW9qS=ScAX z2>il4Wm5iU{YqjQyZvPylvJ1w!&S=r@IdbL^*`3lME?adZ?iD(5>S0$V?DIr&rAsh zd@%HY|1&81hxN}ita~@EopoSSH^*@T{EuOEz_bTOQu;GqytH^7;rSada|c%cLQuZf z*Z+)xO(ew+7JrPz{Pbs}rWpLI{WsPXh5q6B)l6Ig(xAhu_nnt%_>J{p^{V-;v_GcQ zn}3UYPOT^UU)G;~cpo@U&DsxHlqz)Gx2V@?f0=XV_a&u2ZQp+|>4yjNe;hSUC$^m3 z-@CY@ZJ^MyaM3{LlKCy20|R}9j{c<`{Vi=>eDl^P_bln^V)_h^6ECixFxn4|EBm~f zi&*%1K8kY{`rBG&E?U^r+Etj++SA_EQ5e;^YSqO}qnpRnk82!1vY~F=q>*Er$Br2} zsbTzEjg)-#sI9$Z*YF2xOJ7%Eu>Rj*{jZ|`SIU3x^mbYF)7K8%?Ug(4e6eNiK5J&a zz{@q6j?ZPKeCn+z40LplYU}HZrQ7I{b#>#%O{z8NHww{I3+e&A&;Zl{J>CTTeg^b# zGkz`wRQ}!uxfm!?-17!&zXtpH3$n1Er974q3;M4*`|Yi-8@}en{-1yHZ?D^EzmXah zJc;`M%F8(A`UxAhx%uf!Pwsv3hev$k^S;o9*BsLgmjC7thJJScZ!pnNY63coU%$R# z?>*;iIHdoN2d?h?>yC405ou&S7U4x^BARX*)^y@%{PT5WUBkq&Bb(~SOdMI)T-Q9Z zeo}q&$cBj%CXXH0SU*_)pFNoM)BfY&^-qQIzpwvjUfbdLFk>M8>!)t({LLMo`Se4x zn{GPi_SYAmZlgEwzkK0kZ@m8IcDFa*cIm{UuKPjn#?N2#lOJ8Z<*nO)|F-7-?$7@0 zFR$1>kJlofX8|;A{$mgv|IzcN3_Jg~ldnDVPuu)`yQ^L}%9Z_pzG(l4!}ywPycK@m z8eGK~{{QY43 zJOrZ#V+4l8?(*Kj{A4a*FrR<7eb$%1c>AYp(O$Fu^4Kw#y|(1lxw{_o=)bNzBSx0^ za@xnz!RRl${mCjDndnl^&mOy|)duLoQ>nFq%X3<1AW8Xyo z<6P)Gru_>Wwdd>Cw12nux%yo?wp=)B$%a#2wax1X20s5Vh-MJqf$tIh{f9lz-1d~0 zZ#;Z**G^5(9e?z_wr@bJk%|9i&M%D=f@A%szP;?OZ=U|ek018-TVH+g$6v7FptIZ= zrqI6LFzCq9#>eG?GcHNRG7+}_HOL6F6K4r>5M5r4ABQi2bHW--4YEeHVDKbS60^8n zh@uvNz@B#_Mx#+^VYZ9e>>8uqR)bpZa&MwH-a7^&ISn&1(qaXy7vI7T{cMm0^QnQ-eRUr!*=3&%t|d!{8&y{HzzoJvjfN_~Q{6 zN#|dT_ueUAIH>&7rf>ft;Ot*8{nt+KrU`$$?d2POaO$pyeB_od9eu@Vq?ItZ{KQ9? zB@O!zk|o_#?EmKepZNYG>4hj&hh+VawZu)e|7SXE%wl+(^hi}2K=*jfhBsR7!TtyK z<8c39QvJjIK$jQ4xDnc)9Vi9gyX`>NR~SX{jWIu{|Jl!e5JuAZP5XB)tUar4tT(gI zMCx&BCq!J;Q-c|7{kz=!l+RKR`X8)k)1Rs2`Zw4A>0xmXu-Si?s{S7^4W-sf{zhL_ z{Ldi2xv&2x@jpswflBHmmHPRjp%`0&js=9gX(nbZ8q z`MGzE`_YolPpy*N{~P1)Z8PUIpL70W@WRm;N#|!qB2E8!x$8e3-?vqY`CIYcH2wE= zcz@i3{I@Ch|HoZdn%C3vzxmzfXI(#E2O#%g+>7xEjP)4zVcd`L0LFtDpTu|w<5L(9 zV|*Ip5sc4ZJc{vIjK?rOhw(VZ=P@>5d;#MLj4xt5iSZ?jr!c;Z@fD1(VmyuUHH>F4 zzK-z?jAt>P!}w>6=P_Qu_$J1;FuslPBF1+xUc&e;#`iG3kMT0b4=`9~WVZZ=82^It zBa9zoFmwM?jDN*=4dZ7RKgak5#=l|wJH~%typHh(#xF5`h4E{Q-(dU}<3BOp#P}V? z?=jxO_%DqA#`puqA2I%f@n?*;G5!bRFBt!e@mGw$Vf-EA9~ge3U>N#_FwAw&qyBd& zFzilD89a8&=zB7NvPpc!g6!*8(m-u?qh5aP+^grTJ8nkZB}c4Y*LWYLA+p?jE%jpv z`j^dYK)9N;#p)Zo8eae1AuEsFb6ycO7$IqBrPyQvdgVN%7y|*u5Uy!CdfI zDHx4^WBgjhn3CW2Nyy$BWFhUFKx_rpR=*?Cz9mHdrn)A%tFsM}mH5^z-VDT8tY=7O zm8lnQFyTHMHeM(noLeBULmT6MXUHVRpYKPb9Y_j=UpWUz$Zb4h=C{@@c(R}QM;ztvn{1hW$CUiiL1Q-U7NZ8-3V%3hrvhr`Nx#ZLeT#+6|MT# z(*IA#pOgEaW6<>&|DgZP`A6a{{2BjF{g-KYx}x}NlIx$OKN@+)`H#b^qcM`se+u6F z;o>(XnVZA4V3hMvEM&P^XMJLsN)aTpA%&+V3y&JvM z;#;jhDyjdUfN!dn`u_)jg|hfT40_xj!nhLSDvYZ!Xs55ixEA9h81&n&$G8FGMvRYQ z+=Ov6#u|)UFmA=T4dZr&9PO;6ty(_m9Q8TBdVhK!hbqSHdZ?#m6LjAze;9@vl@&5~Ak z)phY;0==XTo1KnD>#) z=Z*7=%4cb2dKZBzW`-uXcH}vpJK#=E%}waaGLXlkKIGw z71zEXlX=Q*&qXg^PBxxkWw^6jvw>LY>A6t)|jXfi9jyN>QTJ-|X6>4s+e@j1mfiuIES}lAQ4t%zH~7x({6A zF3X@-D`+{J;Y0J>IlWF709T&03*rk}cA?!_!065!6WS?_x(vKEI~8x)d)c@LKX|OK zI`!efRNvi-D2VlsQZf>!Nuqpf^MdVCO?|^!Uj7`cvnpcqy1*UP@B7vJeTk}5gjo;8 zU2RTj8sz}VU31@@>akI{&IL_xb;g+@abZnLUZe$H25*tMG=*(Bu&vGko6t(3I0q=s zONGKNwW_;Gyko7Gw*+U*&E)%MfQrlTO)Ab)=y$=lr?bvU(A%x^UYP5#R97+>EhpD0 z@oZ(W8TDN|26wSC7RsVpU59fo>--a6q*^@_eS?g()j{oI?QRBV-Rq2AQJtVQtlbs} z&XvIFE{CIaM9^c1>IlKN0QmCA4F>UPiJk&H>z%D@8abE)e}WOZMB_Yl&)v#KIgqg@ z`#G3{T4CuU@qjN+pOsy0>ZTNS38D7j4y!yXVzTd@=b`fmO3jDg^7UHQIi5JLQ{^^E zkp_(T+(aplw$$IEUiCqkCmWC5+`6Oe=5TzsyKK7Fd1e+}$%|wWN!j%n)ns8+_Dp4x zsaFPyJ9PxJXy{pxm?T?e;|zLKr4OJ*KcQ0%qSul4pp&YRwzHCJQ#+g_Hn;*9 z-Py0G7S{L_?_Uf&?s#8l!j+V`K<8Wv-n?Qo@E~|UzQ?9=9x~@wTAtZzX1FMEcYqd; z#&WKWD+lA#M%RX~*!CXS?UBgaNlsCx@j$5GWDi`}8{s*??(*zWT5D^sZRmf22lA=& z#_expH?=z|1+&t&J%f}Ic740^Bg^w!n6rKje0lnjTEp7qmNdK!-0zOlD2I}Zpd?)6 z?^0!qs(F7b5PjR3?u)MKG{gkT!>A;-*Pqr`^c?7%y=NNr9uLJltDI3Tynf^+?mew0 ziJXPC>;s=kE_WXA#ry6_thwBTAQ~5}1>d^sbkjbcxtm(^+`r*UZ$xaSEA2yhiZAcW z-U8pV$FKJD1Y+*gSdJ)L-=B$lewScWUmf1`4wQYCNP;|l5yquXrOG^WK>3631%|b` zVNiG3;r&!4+7H$sNhR)5zTX+bsMZd@qR&4tyDStn4}_$;%bjRRodOE7^SlL_+J5}& z#c1)yVUN-1qTl}!AiKgD6*V%cxoiFL6Rc_I^!q3Dyo}@`dC|wBY?$SXF*hl=xk2ZN8*Wh?zC>ul7(eXQ|yJDWGZL_ zC{x^}|D-cM3R5JFW>q>WtXCHS|H{nqhj}d8=_8iuIHxOV*P6=0oB||y#KO`;!|0qh zcv5K2gHBkSYF*;HQA$;QWF7X$)u-G06*r%XVtA69%HZ)XJd(@U4YQn|>Z+2|2zUm9 z%EwV6kHm0iZ_TW)wlr!D+pvc2I4Z0gbTp~ZG=eU(Qqewcg~KN&Y=duZ&*Ym+3W(vR_)mi?$Z+M!qbxSjB>*o*cKy7d>i$M zsAJ}1xRc{3U3E{V);4C;Gz07IF0WuU(QE`*$IG!M)F1OP(2? zXRnHm>J*;0fXAITqHTnd0-d2!Xx;-f@&0YPTtpK8c0D*G+s@^&$byf>T9@uzz5(;P zqk1rYR`tFvBh&C-xOE!AFpf z%(EhC)+5ykfa^2&fbDT{3+7QfB;t1t@HELjNS4|cYMw66GYucEBBVBJd^Yqo?@pw2 z($zrh&bozZYs05-O?8SZs6)ai*<&bP{X@W2O?h7PY(>F%Iy6l75o4UZXpKt`pcZqx zi+V(d#aG!BHysO9c~-2<9BO=z7f(Q~COsD~o#z2*9(&G9SLTKPufuA0#%kdtewM9s zH*SaC8qC%=B(v$;heqp7w_w)zoqI{HQ97hd-KTi70Ly0X;lCSmRcDkQJPnHaXJ@Ba zquy08O1I0p@aZ>!*PUk?wrUEy*+JC|JhNjt*)9|ISA#nmxh`8{JeumelVmaDY?8JM z=1z-xR3LfY4DW%>Jp={xhRE4`A_c*{7gvFs+~q$t>R>fDnqwqI7Xn+JyM1(3E$TDt zJbW~dwmooP?u-+{5~@A9(?G*?`^V#I17-%_&XLi~m*@cAwZL7Ehvu-#-##EZ8^fJN2x~80)iF=%5RRJ-?vL+vvRUdRHa2R@4+jnUGuPm} zM+WzP(PFfL+tr-_%u_Xa$EF7}pVzLjqk9b%?RiQA&m80(+e&+PzX4izx~LI|s3qvt ztNV_dHH^;yi@PjOm}}#$-$}r=*4c`NJ>aO{awcdO>{I&{5ay#B5_ z7tBLxY5I{@hk(>O!pT#Gexm!Z%!G9y}2>2ly$kjk3GWhlz~ z);nW9*Sjafr$6%!e(tKLVJ|hlhGh5ixk4vmh1^wak|U0GOO684CsOg!VC-BP&xF~t z=$Rkd6DOVb0eW|*A4KUK^)a6Wss{M8x=TXtamPE^bt5_~_-BV7=N*UNnN^;TpDM0p z_L&|IuWSa!^>|%>Pm(NAI4e}+cXJfrS+F0g2InFS;5pCu?Zt1*4vq5jLvj1R*~8Ta zgiD}rJntNgcpGi=V&n9VnHg2ryEneuT_x7^bnIP}TIZVa@^;`icRe~b3t-nd;= zEf}*z&xJo9_}qEwQG60N1U(wjgD--D&p4BgH0vEF)zMrixu6%Lv#b}Oa$Wu4pH^IR zgGbBG6De5vQ9RY%QQvb-C019AzI zeYv!E$#W&HhgQAU8INnLZdU!Z=PP+_-TNY3{2}1Xv*JeHVos1dU0H#Z(@}z2L(rZ8 zwC*z4LbbS)Ni~N(j}_0u^EFQ|qUXk)8|1#bFx*AcK{|zPs6zAr5V_;CFosfon|W5G z@Yx>Vv-nDuEj~_?OKC<&M+Y>KxfkQJpo_cipz?IF*+RRHZvk?5eG<_)zf@<*mB5x~ z)~3E9i!l*w-kF?w0B;B9;OG}0X;(hoZkDg;wR@F%S6vI@Gr2p2TFt*>HQnW#!d`ic zCy{h%IsOh%y7SHBQ7W3<0W|LX0$8$P{)B5g% zz;Z<@9!lb!+Ih&-cS0MD#Pl`BisJh_BR2&N8WEr6w(@-k{w={-p&jq+ucZ#lz{Ocg)&1HHSB`=~Yyder6)Owo$l zg0|HsG3M#?CT+EyIRv=fc{>V&z7tjpI?}oGV*zA|JfJJN@p1Qrpb17CVKY!S^ zVsf5NaOK2~vY##ws}n%(=3f*AuYyT7w<~eD0$9s0P*e6upiF9(VP` zC>|9#=o9vYr~Uw*au?C)7>oV|v)1g}P-rE0CCFX_GI!ZS)4P}hZ1WLKwffdat>1E> z`AX)RGcFSn*6z`&Vkzyx4&y$*Z#Ss@xj);TOqdikS6j>Ir*gxi`ge6sN3HSJkkJb= zUt_ZtOaJLn40n;Gmbjo65BhYixN>)y7R9^tE_okT@@To(Pi4*_$+dv4Fh(_k&iav}61(Y7D7tpz3f$T4@_J08R`}lUONhHWiBm(i z`Z=uvs1~JaDLt$CVyRQAMyBp>#6!$+5ckiC;>TA*2ZX2c~VNLjvTujb8XD%h&JFDjPqizI^E7yeX^Tg?+0*! z@s=#f_uH=1+#k=YxE-_P5sw79UFnUbz_K=$qPDB4d_`^Nd6*uKJ=**(DCSNEwMDb# zlUtBA(LH=02QqiIHmbdpjt!r1y}~KIM0?0dz1l9B)>QFY6Og&9dIY^CwR=#!q^rU8 z?yPxq<$^wCkngD>CIeqJfYF}$YLhDA*x*FW+)cPYm6&Ll7FPnOmqI#Mv>Kcy{Iq+se2UQG{1_EBLe309}V&|_l0s|VhIvZ7}I z$&6HVwdb|M`JO%Sz1jCv*tNd8l5v>PohCA+ohxnguC#QGgY0LovF+3_d!uz!p|Si8 zbhDDJs3Pf`RGt1M8yDb*M zsxsp|fSuaxG3>^*sj7m;vIDSW?_-45!Q3rB9jIi7vvk9a1PXU~zF^*p91^VZ2|tX^ z*@nhTI<@-oK$l0>)SNZYK%cLQ5Gk7+Poq{c?Sg)(OL+nwr^PEj6|+=U zGPi9r;XSr_7lIb17drxTJ)HSmah`q9c8Dg5)fScpA8e!lv0Ox`$z|yzdI$275IC+tml# z;^71ym-@ZD90vF8{}Sl(>|+S}wD#;C^}+yjy1O_x>a&TJWFHItD9zpPcWQ0ok!eKJ zfXJOk5w(A+$}9IDlamBQi@kx>bhlF^PQz26!I9ECIn!*)(YPyw9DHYWx!Dv33qY_HBL(Alu4bfhp^ifu1LT;1BK#*WWJs;eD97`g2vm_-kKa&Lb}#)Dw!I{}=rHVCE~AZN^CR*=;%N1M_rbMZfES z=$R^~pPT|h>l)t2FLJ~)ZqCpAI)Xbu4#phoGM^)k*Gg-1yH`eQc`t^$u9j#dZO=+x z22@Wtqg^N&kC(OBSUtdKjZCDCpoWlw=>vr|b~9Pg-ErOr$F*cHQF9ARE{FuvB@+lh6^ zGp-F z-Ps6pHRW6+&w9BE}o8h!;~?0hx24eO|_SR%AJ&HA0jC6CY^o`M0wQ6!&yP` zY5od4)mbAqPl(qmx(oC|HD!WTr&Rpe+>A>O2Il_E^#*y&%$pYwJ9C$IVWYmP!Q6TH zVD-R7``cFR!6glD#@LWK4dQYaVSOIWY}va_m0poEeMCmS0qpK{Z&bGhqe~U{^W1gj zNl4o>!C&$Dm?YJzg0DGwswPj@jH^#^u1{dD`LXMmW-b+Hsq;Klo|c^3U%aNfFpoR? zZ(?Zy2G-;B$@bLWy!QJs;^|yz{Y$NPSa$0$m%C0cZMnoRv}evmB7O>V`9zsYvc)6& z58%kdnuhnD2whGC*Sf2-MKy)ZOS7*e`T0W_S>@t*3U80$d2NC3cIPV#|0+3MhPmD4 zX`-u8N?!}7oCQvCmvs~R#NVSsa9sdgdD2c%Q+f~V8OuJWw2Q7Ued+K%RLax2z*YS| zj(vA#8}R4Pk2(_|Hn$5jeJs}BsMO{Tt=~vqXvawBE5y|~%KQ0yVXkcIqBFqR;l0GW z;M=pR>gtF^M|4}_`?EjgB5sAXCKM@FHsc)d*{#m_Orr?uJKE~#zVYQ%CIc$wRXH-Q z=s?W9IA#I2yPS}wDJ4d7L5jW-(NQwjV`Ss?1p6fU-NP~BqoYc-mCodgl|BgbWS>!p zlNptX9hfFZ zW8UqZNcRHLJmS8fXRmG86yR~UvRcyx@kFhM=!*rwcdxURjmoX|>+I4YI9CE^e}+}j zI@Cq$0#(tO{`o)Q(}HitynV6sNs`sF>Gl>}3H4Q6j_VH0>drozSmZPmGsndfekfZH zVz`s7QoN$@Tns9?)9hNdnvl`ZyDj?t$~}2gttjs&$-Te|;}yUd-x*&y|CGrJFKaH4Q_Im$Bou4&0cPaDX#*ie5!)Bb5|*IA8|^hsLW~aMccIh0;We}b)rq* zwL*thcDI{oeJ1*fy=>b?odZ5$yX@v?Dpx0{*coYOWVDZfI2=VNuocbf)kAu z)>fH@FuT^s`|~hXIpZ^~k9pc25lq0yK5C0bhlgUGZ#%ovsIJyKx06bj;%^l_>rZPP z@f@zmohA)u!pwCP4{|KH-JQ1(mH%>{F8S>;V00HnYma6Mv=KY(Ti_M<<6kdE3+{tG z+P??3Z-;>F{v0_p%(GhOn;jO)=QRd#yRzYg6!niaygo;Y<1%~SD zm!Txfy(Uc^qcC3t%s0Zj&bME;8yLHN8Cl_y;eT~l5D)Ys88`Av|#r4 z4=8_?W{zD+?I&=Rk2}+LVM`J9XcW)(fLHbXf`WS%g;OpB@~3h{u05-ASHa#dp7yCf zp=jTME68)tZE0I5bpAF_y32Qkbq4Q-piYyg-=n4Thd{N#+3H78@fBOdSniHo^e|3# zD*bk?pg8appjnwY6~oku_AUr-9f$d!%zS?P6-TAC^j%?WnkX#6i-125Jsy+^^3)9& z?xZy6S%kH^meLo1>Q-m#8|J$fR6d!_;b|>VKmU)wcBM0H+SAZGfHj?tfJVqO{tZ^7 zbTn-4fmjTT@%ffC*)G!`np(`dXn?#cP`ScZ zL?4o|-VL)X&SaL-6$R0z`(wU5VjbzpVHQ)J#Yq~Uhjm<<>grn)WTL||9-X-^A?E#Pt2jbN8ARt&n3$C3MP{x>kW%jB9mocL^+ z2Suy#PNm+&rEH6wCsIJfCEYh>6fpz%+|jLcoNC@3?IEY@nZ$=E+7{q?IF)~y#EVXz zAxVN%&X!Y%uLk1vRfM=1XTtV@7u9{IEiB$C3flw zpK47;jc+mN%1nI$HR-Ioi?p3mNX4hnxq@X*?PgG$sGglJBPab~pvkrmb}Z`rV=;rA z4rK3xy#e#a?^;UZt(aG+@)-rJubFqh8*}x=N_UdEY+S-U?D~#q(VWmNn6-0AX0`2Y zT7%j0*u`DC(?ewNI-sj2{i=8-Sg})<;5=xHJnLI#mfYUSM=NkWhP&u3sMF&8xMQ)( z*=Nt`l; zX5ev`nTdJ@!F-Wjl0-Xw(<#<4?V>e4oyQEGOvH8G89bD353AkBq4m;s#4cmeOrTI~ zKOnh06(tLQF|r1f{OW){tJk;4`O+oR5C zs@VuW4QAn%&d#;>=?=D-vU(Yi~I5vw=VP%cY8IS+^e*J=SL$#o``cuk3kGK4Z5rW zr&RGA&UXKI?wDfNF?$CWAQBmcZ&W)*min>DXuNB-HwOFl_-vZL!^-x4{jH2=m_J_# zDl&5Pynn}VSBp34r}U6{|G?LQCC_Z5mQJmkSApx@b?IfHN5r~a3FQ5mYe3;%T7x$5 zWjDC4$Is2mytP=x_-+N8Cz!;lMt#M@opNqtQ4+ats24KS4(ZWc@)=-xFmqbl{h8=q zRHe7MM|UBx^~2tj_7r~uv;(ndE6*f|O=I0fAqeL%?gUT9cL!8Hvx=h3^R#ZoOx4%N zZ~9Qm`kK+kOkmE(mc`W$=t*q@RBL0orBZp0Zz@Zt4dQ>hTJ4&Cja7IYCZ7{}pX3w|!b zCtHeK2XQ5xt^~3=5ysC+>Y6vakffncs))JM>9cO(_V}`*Hq%s z;ChNic@gN`X}l=M1>?bH@P*PLg717tguDKHdsax>v{ON?>?5}@Rm{^m>^yZmaO9~~ zgRzm4*N+0z(^Vv|su~gOj*H(NCj9m_T!p*1#H^S^t*fHz13;9AUuT|qMH|I#Sn9L8 zFx=%TgA@u&iW!MN4_tZH;E1h!1SEWR0`%Iw&ZI^AAZCAx_Bw^ix*J7seh4^wik%F) zO2q6)d$IP*=j=)l3)GH_Cjcb4yGF=sasdVLIj zvZBH}5Q=YJfVO8Pt^-^{@0AQFgg50(UKg9SZMI|2uHFi-e=TqV|ckM{y|h zOg@-w8AiobcY{u6!jkLUUDCQ;5A42qCZzhlx%j>-a#;TNSPrVj$@&>kSPi zD>)Bw9jl=9!nx~|y6sjBcRA!J-_geDj!#O5^q&77$lPTxv}6VmtpJ@wR}6}qG2E~jIS7re%rk&ahrDlP+p$+=7ReW;C9#99kpRW|2*7bMUL1O2&*aErZ|F8 zmGtA7l%3&cR}?Sz1AS-ayv*5b-N} zciJjyh1Dz4H%_i*%|UC^evraSgeY}U2N5!4E4YY zWMP???KZ6Vz4-oW+Vh*Nz92r*SFu)k_E+g%oYK8Q{|TJ!vD(~b50YpHn?^VhGp#{R zQG3z09csbO*yy==HGaR5v>!9@(jBf*D_O({KWUIJf9A=!6YK7zS7eUW*4}5R- zzDOxqD)@XtUx8gK>TFAD%QG;ZPj!V!teBmqQ7$db!`kyS^OK5ql;^1>K&@8~t|m_( zG-!{4Tuf?Tijn88X9g#x@Sp|gF(Qb@dZz=2JA0}*r*!^ZsI&p--0_e`XG)yX+j5sWL3SLt+a2A) z{H&s8yH22WJs#-X)p~-mM-MJo+ZCFPcB-YqG_zMaPX@JyA_vuqU1{3Jb4^BLOo370RZ*qU;xA46{0VAHM%#XTC>}FJ(0(zSpsl_E#JHJqL{L zq-$>k5HH9av3YMjZI?!11>AWUVfkpmJ`8n-5z&KfzK^On<72><&Qs3D6Qc)DJ~ew6 zPsN(Jqmxjh1@|uCJs#M@Lax?aW1cqC4QzSF&uUerKOq`F7o5^A%40!%lu*?_LG7~y z*xW_WdR>D#2Z;?o07Q>wF8OhBQdm1hGd)V11^3(rYrv#oD@IS|sN>JB=A0*Bxa%Y{ zBO`T(YaOl0+Pw)xk7Q1T%GXZY8Z!^q;M-u@M^bTbaDSd2rNnYUogu#4bfC-fyr&6% zuMKzP#Gm(cqf?5Mm%!jI+h6)zpKndE4Svc1e3m}gBM)~C8ya85Rv|wOb5&E1Md=E; z_OYG@?mTQv@O%Q1sviT*Drb5sT!o|7S&8AUS0F57;qdrbziY@%(hrgX&V)m#Vr*_XL?3GS?wXnOp{b3i9z)(116wQ}E! zc>6#d6-S2ic+X%B+<9GL?oj=JtONDHl6MsQ5!lP2^vAhQc{duZ$q7_JpOALra~SS? zejTfcm&$H{3w=2k3-M3jyX-px;`mM@ibfy*1KOmkCbS5?xZssS(4kLrzr`#H=N2qR60c#w8ozX8E{uGiANNb&i4bEJ3lju zOuZs`vG~4(0pN6(p^oCT^_SSu3KzZ#F3dCIsP$jaN(jC`0biagAI#cD>mGu$9V_q7 zqS;p7Jo$h&b{)p7RGw6v9SQGL-VWa!?|ItveB3wND;Zni`}5>UrMG1de~>Rp**|0C zS&L)btIypE;uC%x27X+bYV}*;=T^4!RGosTcH+wXb(lZTH4Msau-d{kyb$=-IipW$ zd9`b3qP!R5{LE1Xdtnd89M5DvN1WFdj$xu%23uA~&gUWW@aZVRaXj@XPYrCIV6Eb> z>wu`5Vp$tywfA=$(B@I24Qg9Ox&H;0>aV~AGy3~NqYPv&M`mt@TI3@1gob-E--ns= z+_9pxn|Q~Xqk4gBc`QYe?6gGuZ^AE_RWK_ zfKd%E*^hYb{y4aNZYqRvew68CT75c%@cW`ziTIqft(7Vev zM{@(goP|`LF9Rxf5xCAmmFLyZ16jIGrZ`?THQID&Gv2$9|7*Rm6Xv?y8E0uK=rgI5 z6*?RmWOgbXan~H|XQOAgtJ9TE!hfPSo&qv={ZUc9saGKw*^p{SV@2FWUgdSptYY=t zv^y67r#nAXbFcF5%o9>%MeBjcoqu5R+7!rj_}-*i&L0CVcdHrYw4e?Sa+}cZWv8oY z(k>XmYN~ZY2ChfGJI~$d%i(Daz~^H39ZyG{iIGR_5L`i}wO0d+JL_Stn4E*EaMWX+ z+}ZN5t}0hKcIW#jy(DM1wfi-ZxJr8-y)`-mZEA6LBjkZ5STm9{>>I&Li!(WMTHP

xmnO*y z=u^1j`c{Uzt}Q!(&8{X}?M>pk%fYqtGl?Y1*YvBWiy`40oP(qrZQOySccJig#-h?fM9CxYPJi-lK=B>#@rF{|7K- zZ(Hl}oqfYqh@4fTrD+U>Pv!Fmy}da%wq zN|yB~RsD{Wn{X~98Y}3WqxiN2z`-2x#kgC*1e{}0>(wFqG!Z*KM#9gn$H}J?@vP2k z_Qy!PG6|y@ukl?IaOM^7aMp;|8u1SPeu;MqP6bqV%-}f`9oPl89QiDIKfwp@Iqnl7 z_;TXkw(z{|y(>=I;(>jCeCny6eB_DCn!ow=%j65UwtS8Jt@x)m@jFlE+LAE#v{8La z`^)>9JN{~L&Fa*Eg10YQCYQhk=7taR56eYz=oxnTXU(d6TgTn~AxWmihIo{>6qBo6 zF}=u2mb$Q^?EkNXA4h?XJwUHKL&jRw;VtJADGa?`QPn?F1Epu|m1kpvI~!0`&{GAh z9mDZ#)};J%tQw5ealaWQOYLgm9dEmF`AaeE{RL5p^z2%N8^VZgN;|Y=9b&fm(7p?x zlSe{#^4=94{!l=54n8jOyC|uQN7vmkL zP`~4Gl5c^sv~#0C^JT@m0m{7UBuaDET`;#Do8ln8cU$jByems=C*fPO{l-x-R(%wB zl&4(`faf~#jOPrQ*MHiO<4`%0I`DouEGK1-Mc)fnyqt0vvR@YyLvmWM1F;@!#w@^6 z=$1yTBkwRmZlqUa_u)?3C{5e@T~d@mUu{8iCHs6|->Ov?H;rx{Q_oMDpC3PZWL@3( zag%Cm8*A%pYcE+dtm(wj_;+#rgweHi4HL(XY^onKab#U{UGvELN%cH(-G9_K)=ijv z$*RtQfxbdV|I&{BQA^vF_x1NKUe$DB%h~wZ(Kb+MS-5DRbIJS`{jL^%7(Qg=k>)kZ z?P&O0qs#pByy5;kBa`6;&UY(Dqob}76;XG?iuJ%_Z^0?oP4MVje9w`;Q?)WzE&QR{kf}iJ#@KJloaIdKxvyE(+IAQYGag7GEk^j!a7%Fdq z*my^A-s#WgTL}NF_o@F)Z$!OfFPRFeWwyh zKIeC&|GW}OGyYS8+d^P77cJ~*?J7)Z?P>4oD2(b9buq4S{K$s7ag#=lZ5}&j>B=HZRzVOynNwhZ@m8IcDFa*cIm{UuKPhR<|_A*AiTjWye^ZMYM1Zy zc3Je(*ACq6l{@czv1RQ(Yi7Q{%Y7&GD5^b0y%mLlj_y%yTFpl2CTg}+48Pfbu=z5Z z{Riz$SL#1##$=cEVC+9dA*7O1*?-ZW3B{%8mE5$^E8+ZUdO_Wx)8hWy8|03*xX)8_gQ zl>a7B|9MyC|Jl+b44-@c|AK5HM}3>)sW9f;^doM^kkk^61_^`t|J>^b$mv&Jr`}vY zh_B&qj{i5u|E23Xo8y0|!%aN?XFhy${8wrIe^ZbD=nmN)`+CDdX)TqdL#5-6jma;R zIX)x;a!#gN0h=_Hb#$+Ipz8Z8@9Rm=}S-Uees7! zeB$$d(I-@Lcn6&q{e$shZOv;$Q@R@R^xLoOckuKRo_x0X)=}R&{;NDgHc}1YYl$A= z`p>&9|0T(&FtL)#zojH^sgkBj$)}Qksbdur^Qr59!D60YYfLBq{zuAFkDk&9j7n8Y2z{x?5+`PCcMRhoI~x?5`Y+U2x^dT;paS?4@=z;h&4M3eBvN*={^-+t!COFq6# z#g{8y*_*@ol#I+WUS5RfJR7M=7l`a_E1Ad$uVVIK)=%os=OSys_GNv%!skxzcx~@P zo_+kfPrq?f%XU-l;WdWWj9oS@-6d-CA=%uvNcPTS6R%L3w-TcHP^-hcGRlK8$OnA} z)4B1B<=j#dcqIG0_)meRB5JU62Nrb|nC1_BDSnA+RuhZ7JI!mA*AHd3%KMKtb^Fhj z<#%`dlTH6r!K*>9@pAMakN1v&OF1oJWs&kT^!2a7_D|{E9pS4aevb6 - + Debug @@ -32,6 +32,9 @@ + + + @@ -56,6 +59,9 @@ + + + @@ -72,7 +78,7 @@ MultiByte Application release\ - v120 + v140 true @@ -81,7 +87,7 @@ MultiByte Application release\ - v120 + v140 true @@ -90,7 +96,7 @@ MultiByte Application debug\ - v120 + v140 debug\ @@ -98,7 +104,7 @@ MultiByte Application debug\ - v120 + v140 @@ -130,15 +136,27 @@ ..\..\build\$(Platform)\$(Configuration)\ ..\..\build\$(Platform)\$(Configuration)\ + D:\usr\include;$(IncludePath) + D:\usr\lib64;$(LibraryPath) ..\..\build\$(Platform)\$(Configuration)\ ..\..\build\$(Platform)\$(Configuration)\ + D:\usr\include;$(IncludePath) + D:\usr\lib64;$(LibraryPath) + + + D:\usr\include;$(IncludePath) + D:\usr\lib;$(LibraryPath) + + + D:\usr\include;$(IncludePath) + D:\usr\lib;$(LibraryPath) %(AdditionalIncludeDirectories) - %(AdditionalOptions) + -Dssize_t=long %(AdditionalOptions) $(OutDir)asm\ false Sync @@ -154,7 +172,7 @@ true - %(AdditionalDependencies) + ws2_32.lib;libgnutls.dll.a;%(AdditionalDependencies) "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) true false @@ -177,7 +195,7 @@ %(AdditionalIncludeDirectories) - %(AdditionalOptions) + -Dssize_t=long %(AdditionalOptions) $(OutDir)asm\ false Sync @@ -193,7 +211,7 @@ true - %(AdditionalDependencies) + ws2_32.lib;libgnutls.dll.a;%(AdditionalDependencies) "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) true false @@ -216,7 +234,7 @@ %(AdditionalIncludeDirectories) - %(AdditionalOptions) + -Dssize_t=long %(AdditionalOptions) $(OutDir)asm\ false ProgramDatabase @@ -233,7 +251,7 @@ true - %(AdditionalDependencies) + ws2_32.lib;libgnutls.dll.a;%(AdditionalDependencies) "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) true true @@ -255,7 +273,6 @@ %(AdditionalIncludeDirectories) - %(AdditionalOptions) $(OutDir)asm\ false ProgramDatabase @@ -270,9 +287,10 @@ Level3 Disabled true + -Dssize_t=long %(AdditionalOptions) - %(AdditionalDependencies) + ws2_32.lib;libgnutls.dll.a;%(AdditionalDependencies) "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) true true diff --git a/projects/msvs/httpserver.vcxproj.filters b/projects/msvs/httpserver.vcxproj.filters index 322c10f..46b165a 100644 --- a/projects/msvs/httpserver.vcxproj.filters +++ b/projects/msvs/httpserver.vcxproj.filters @@ -67,6 +67,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + @@ -135,5 +144,14 @@ Header Files + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/projects/msvs/httpserver.vcxproj.user b/projects/msvs/httpserver.vcxproj.user index 89d2452..9ab31d5 100644 --- a/projects/msvs/httpserver.vcxproj.user +++ b/projects/msvs/httpserver.vcxproj.user @@ -3,4 +3,14 @@ false + + --start + D:\httpserver\debug + WindowsLocalDebugger + + + --start + D:\httpserver\debug + WindowsLocalDebugger + \ No newline at end of file diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 93f001c..2da3efb 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -283,7 +283,7 @@ namespace HttpServer std::string module_update = app.cend() != it_module_update ? it_module_update->second : ""; // Calculate module index - size_t module_index = std::numeric_limits::max(); + size_t module_index = ~0; for (size_t i = 0; i < modules.size(); ++i) { @@ -294,7 +294,7 @@ namespace HttpServer } } - if (std::numeric_limits::max() == module_index) + if (module_index == ~0) { module_index = modules.size(); modules.emplace_back(std::move(module) ); 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 fec3925c8313ea83bf7eb37500093376a0878c74 Mon Sep 17 00:00:00 2001 From: awwit Date: Tue, 31 May 2016 14:42:25 +0300 Subject: [PATCH 24/50] Added feature: loading DH params from the file --- samples/apps.conf | 2 ++ src/ConfigParser.cpp | 13 ++++++++-- src/Server.cpp | 44 +++++++++++++++++++++++++++++++-- src/ServerApplicationSettings.h | 1 + src/SignalHandlers.cpp | 24 +++++++++++++----- src/SocketAdapterTls.cpp | 4 +-- src/System.h | 3 +++ src/Utils.cpp | 2 +- 8 files changed, 80 insertions(+), 13 deletions(-) diff --git a/samples/apps.conf b/samples/apps.conf index 775c087..a88c2a2 100644 --- a/samples/apps.conf +++ b/samples/apps.conf @@ -14,8 +14,10 @@ server { # tls_certificate /media/projects/sites/servertest/cert/cert1.pem; # tls_certificate_key /media/projects/sites/servertest/cert/privkey1.pem; +# [Optional] # tls_certificate_chain /media/projects/sites/servertest/cert/chain1.pem; # tls_certificate_crl /media/projects/sites/servertest/cert/crl.pem; # tls_stapling_file /media/projects/sites/servertest/cert/ocsp.der; +# tls_dh_params_file /media/projects/sites/servertest/cert/dh.pem; } diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 2da3efb..7f65321 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -137,6 +137,7 @@ namespace HttpServer std::string chain_file; std::string crl_file; std::string stapling_file; + std::string dh_file; if (false == tls_ports.empty() ) { @@ -161,6 +162,13 @@ namespace HttpServer stapling_file = it_stapling_file->second; } + auto const it_dh_params_file = app.find("tls_dh_params_file"); + + if (app.cend() != it_dh_params_file) + { + dh_file = it_dh_params_file->second; + } + auto const it_cert_file = app.find("tls_certificate"); if (app.cend() == it_cert_file) @@ -283,7 +291,7 @@ namespace HttpServer std::string module_update = app.cend() != it_module_update ? it_module_update->second : ""; // Calculate module index - size_t module_index = ~0; + size_t module_index = std::numeric_limits::max(); for (size_t i = 0; i < modules.size(); ++i) { @@ -294,7 +302,7 @@ namespace HttpServer } } - if (module_index == ~0) + if (std::numeric_limits::max() == module_index) { module_index = modules.size(); modules.emplace_back(std::move(module) ); @@ -333,6 +341,7 @@ namespace HttpServer std::move(chain_file), std::move(crl_file), std::move(stapling_file), + std::move(dh_file), std::move(app_call), std::move(app_clear), diff --git a/src/Server.cpp b/src/Server.cpp index 62a2bfc..80095d1 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -1508,9 +1508,49 @@ namespace HttpServer ::gnutls_dh_params_init(&dh_params); - const unsigned int bits = ::gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY); + if (app.dh_file.empty() ) + { + const unsigned int bits = ::gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_HIGH); + + ret = ::gnutls_dh_params_generate2(dh_params, bits); + } + else + { + std::ifstream dh_file(app.dh_file); + + if (dh_file) + { + const size_t max_file_size = 1024 * 1024; - ::gnutls_dh_params_generate2(dh_params, bits); + std::vector buf(max_file_size); + + dh_file.read(buf.data(), buf.size() ); + + gnutls_datum_t datum { + reinterpret_cast(buf.data() ), + static_cast(dh_file.gcount() ) + }; + + ret = ::gnutls_dh_params_import_pkcs3(dh_params, &datum, GNUTLS_X509_FMT_PEM); + } + else + { + ret = -1; + + std::cout << "Error: DH params file has not been opened;" << std::endl;; + } + + dh_file.close(); + } + + if (ret < 0) + { + ::gnutls_certificate_free_credentials(x509_cred); + + std::cout << "Error: failed tls DH params get;" << std::endl; + + return false; + } ::gnutls_certificate_set_dh_params(x509_cred, dh_params); diff --git a/src/ServerApplicationSettings.h b/src/ServerApplicationSettings.h index 809d099..7d61acc 100644 --- a/src/ServerApplicationSettings.h +++ b/src/ServerApplicationSettings.h @@ -28,6 +28,7 @@ namespace HttpServer std::string chain_file; std::string crl_file; std::string stapling_file; + std::string dh_file; std::function application_call; std::function application_clear; diff --git a/src/SignalHandlers.cpp b/src/SignalHandlers.cpp index 819db15..ed7c924 100644 --- a/src/SignalHandlers.cpp +++ b/src/SignalHandlers.cpp @@ -7,13 +7,15 @@ #include static std::thread threadMessageLoop; - extern ::TCHAR myWndClassName[]; #endif #include static HttpServer::Server *globalServerPtr = nullptr; +/** + * Terminate signal + */ static void handlerSigTerm(const int sig) { if (globalServerPtr) @@ -22,6 +24,9 @@ static void handlerSigTerm(const int sig) } } +/** + * Interrupt signal + */ static void handlerSigInt(const int sig) { if (globalServerPtr) @@ -30,6 +35,9 @@ static void handlerSigInt(const int sig) } } +/** + * Signal to restart + */ static void handlerSigUsr1(const int sig) { if (globalServerPtr) @@ -39,6 +47,9 @@ static void handlerSigUsr1(const int sig) } } +/** + * Signal to update modules + */ static void handlerSigUsr2(const int sig) { if (globalServerPtr) @@ -60,6 +71,7 @@ static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const switch (message) { case SIGTERM: + case WM_CLOSE: { handlerSigTerm(message); ::PostMessage(hWnd, WM_QUIT, 0, 0); // Fuck ::PostQuitMessage(0); @@ -96,11 +108,11 @@ static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const return 0; } -static ::WPARAM mainMessageLoop(const ::HINSTANCE hInstance, HttpServer::Event *pCreatedWindow) +static ::WPARAM mainMessageLoop(const ::HINSTANCE hInstance, HttpServer::Event * const eventWindowCreation) { const ::HWND hWnd = ::CreateWindow(myWndClassName, nullptr, 0, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, nullptr, nullptr, hInstance, nullptr); - pCreatedWindow->notify(); + eventWindowCreation->notify(); // After this action, eventWindowCreation will be destroyed (in the other thread) if (0 == hWnd) { @@ -166,11 +178,11 @@ bool bindSignalHandlers(HttpServer::Server *server) return false; } - HttpServer::Event createdWindow; + HttpServer::Event eventWindowCreation; - threadMessageLoop = std::thread(mainMessageLoop, hInstance, &createdWindow); + threadMessageLoop = std::thread(mainMessageLoop, hInstance, &eventWindowCreation); - createdWindow.wait(); + eventWindowCreation.wait(); #elif POSIX 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 5824571f35dbc6af80c664fc6a2cef937abeec90 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Sat, 16 Jul 2016 20:30:56 +0300 Subject: [PATCH 25/50] The correct completion of the program's work on case of the exit from the system (for Windows) --- src/SignalHandlers.cpp | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/SignalHandlers.cpp b/src/SignalHandlers.cpp index ed7c924..4286810 100644 --- a/src/SignalHandlers.cpp +++ b/src/SignalHandlers.cpp @@ -6,7 +6,8 @@ #include #include - static std::thread threadMessageLoop; + static DWORD gMainThreadId; + static std::thread gThreadMessageLoop; #endif #include @@ -71,7 +72,6 @@ static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const switch (message) { case SIGTERM: - case WM_CLOSE: { handlerSigTerm(message); ::PostMessage(hWnd, WM_QUIT, 0, 0); // Fuck ::PostQuitMessage(0); @@ -99,6 +99,21 @@ static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const break; } + // Cases WM_QUERYENDSESSION and WM_ENDSESSION run before shutting down the system (or ending user session) + case WM_QUERYENDSESSION: + { + handlerSigTerm(message); + break; + } + + case WM_ENDSESSION: + { + ::HANDLE hThread = ::OpenThread(SYNCHRONIZE, false, gMainThreadId); + ::WaitForSingleObject(hThread, INFINITE); + ::CloseHandle(hThread); + break; + } + default: { return ::DefWindowProc(hWnd, message, wParam, lParam); @@ -136,9 +151,18 @@ static ::BOOL consoleSignalHandler(const ::DWORD ctrlType) switch (ctrlType) { case CTRL_CLOSE_EVENT: + // Cases CTRL_LOGOFF_EVENT and CTRL_SHUTDOWN_EVENT don't happen because... it's Windows %) + // @see my function WndProc -> cases WM_QUERYENDSESSION and WM_ENDSESSION. Only they happen in this program, because the library user32.dll is connected. + // @prooflink: https://msdn.microsoft.com/library/windows/desktop/ms686016(v=vs.85).aspx + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + { handlerSigTerm(ctrlType); - std::this_thread::sleep_for(std::chrono::seconds(60) ); + ::HANDLE hThread = ::OpenThread(SYNCHRONIZE, false, gMainThreadId); + ::WaitForSingleObject(hThread, INFINITE); + ::CloseHandle(hThread); return true; + } case CTRL_C_EVENT: handlerSigInt(ctrlType); @@ -180,7 +204,8 @@ bool bindSignalHandlers(HttpServer::Server *server) HttpServer::Event eventWindowCreation; - threadMessageLoop = std::thread(mainMessageLoop, hInstance, &eventWindowCreation); + gMainThreadId = ::GetCurrentThreadId(); + gThreadMessageLoop = std::thread(mainMessageLoop, hInstance, &eventWindowCreation); eventWindowCreation.wait(); @@ -213,6 +238,6 @@ void stopSignalHandlers() { #ifdef WIN32 System::sendSignal(::GetCurrentProcessId(), SIGINT); - threadMessageLoop.join(); + gThreadMessageLoop.join(); #endif } \ No newline at end of file From 5016ee4b50a7205175995e23a943bf5ee930840a Mon Sep 17 00:00:00 2001 From: awwit Date: Fri, 22 Jul 2016 20:19:58 +0300 Subject: [PATCH 26/50] Command line parameters '--config-path=' and '--server-name=' were added --- README.md | 6 +- projects/qt-creator/httpserver.qbs | 9 +- src/Event.cpp | 1 + src/GlobalMutex.cpp | 175 +++++++++++++++++ src/GlobalMutex.h | 45 +++++ src/Main.cpp | 6 +- src/Module.cpp | 20 +- src/Module.h | 23 +-- src/Server.cpp | 299 ++++++++++++++++++++++------- src/Server.h | 35 +--- src/ServerStructuresArguments.h | 13 ++ src/SharedMemory.cpp | 240 +++++++++++++++++++++++ src/SharedMemory.h | 42 ++++ src/SignalHandlers.cpp | 8 +- src/Socket.cpp | 26 +++ src/Socket.h | 31 +-- src/SocketList.cpp | 6 + src/SocketList.h | 5 + src/System.cpp | 73 +++++++ src/System.h | 37 +--- 20 files changed, 921 insertions(+), 179 deletions(-) create mode 100644 src/GlobalMutex.cpp create mode 100644 src/GlobalMutex.h create mode 100644 src/ServerStructuresArguments.h create mode 100644 src/SharedMemory.cpp create mode 100644 src/SharedMemory.h diff --git a/README.md b/README.md index 13f88c7..0e1b53b 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Common: * [gnutls](https://www.gnutls.org/) -Linux: `dl`, `pthread`, `gnutls` +Linux: `dl`, `pthread`, `rt`, `gnutls` Windows: `ws2_32.lib`, `libgnutls.dll.a` @@ -65,6 +65,10 @@ Server start ``` Configuration files must be located in the working (current) directory. +Or input a parameter `--config-path=` to set the directory with configuration files. + +Use the parameter `--server-name=` to define the name of web-server's instance. +Instances can be used to run web-servers with different settings. Server configuration -------------------- diff --git a/projects/qt-creator/httpserver.qbs b/projects/qt-creator/httpserver.qbs index 4fc4050..67eab75 100644 --- a/projects/qt-creator/httpserver.qbs +++ b/projects/qt-creator/httpserver.qbs @@ -13,12 +13,12 @@ Project { Properties { condition: qbs.targetOS.contains("linux") cpp.defines: outer.concat(["POSIX"]) - cpp.dynamicLibraries: outer.concat(["dl", "pthread"]) + cpp.dynamicLibraries: outer.concat(["dl", "pthread", "rt"]) } Properties { condition: qbs.targetOS.contains("windows") - cpp.defines: outer.concat(["WIN32"]) + cpp.defines: outer.concat(["WIN32", "NOMINMAX"]) } files: [ @@ -35,6 +35,8 @@ Project { "../../src/Event.h", "../../src/FileIncoming.cpp", "../../src/FileIncoming.h", + "../../src/GlobalMutex.cpp", + "../../src/GlobalMutex.h", "../../src/Main.cpp", "../../src/Main.h", "../../src/Module.cpp", @@ -50,6 +52,9 @@ Project { "../../src/ServerApplicationsTree.h", "../../src/ServerRequest.h", "../../src/ServerResponse.h", + "../../src/ServerStructuresArguments.h", + "../../src/SharedMemory.cpp", + "../../src/SharedMemory.h", "../../src/SignalHandlers.cpp", "../../src/SignalHandlers.h", "../../src/Socket.cpp", diff --git a/src/Event.cpp b/src/Event.cpp index d4b3258..c7a9d42 100644 --- a/src/Event.cpp +++ b/src/Event.cpp @@ -1,3 +1,4 @@ + #include "Event.h" namespace HttpServer diff --git a/src/GlobalMutex.cpp b/src/GlobalMutex.cpp new file mode 100644 index 0000000..9fa7ca5 --- /dev/null +++ b/src/GlobalMutex.cpp @@ -0,0 +1,175 @@ + +#include "GlobalMutex.h" + +#ifdef WIN32 + #include +#elif POSIX + #include +#endif + +namespace HttpServer +{ + GlobalMutex::GlobalMutex() : mtx_desc(nullptr) + { + + } + + GlobalMutex::~GlobalMutex() + { + this->close(); + } + + bool GlobalMutex::create(const std::string &mutexName) + { + this->close(); + + #ifdef WIN32 + this->mtx_desc = ::CreateMutex(nullptr, false, mutexName.c_str() ); + + if (nullptr == this->mtx_desc) + { + return false; + } + #elif POSIX + ::sem_t *sem = ::sem_open(mutexName.c_str(), O_CREAT, 0666, 1); + + if (SEM_FAILED == sem) + { + return false; + } + + this->mtx_desc = sem; + #else + #error "Undefine platform" + #endif + + this->mtx_name = mutexName; + + return true; + } + + bool GlobalMutex::destory(const std::string &mutexName) + { + #ifdef WIN32 + return true; + #elif POSIX + return 0 == ::sem_unlink(mutexName.c_str() ); + #else + #error "Undefine platform" + #endif + } + + bool GlobalMutex::destory() + { + #ifdef WIN32 + const bool ret = ::CloseHandle(this->mtx_desc); + + this->close(); + + return ret; + #elif POSIX + const int ret = ::sem_unlink(this->mtx_name.c_str() ); + + this->close(); + + return 0 == ret; + #else + #error "Undefine platform" + #endif + } + + bool GlobalMutex::open(const std::string &mutexName) + { + this->close(); + + #ifdef WIN32 + this->mtx_desc = ::OpenMutex(SYNCHRONIZE, false, mutexName.c_str() ); + + if (nullptr == this->mtx_desc) + { + return false; + } + #elif POSIX + ::sem_t *sem = ::sem_open(mutexName.c_str(), 0); + + if (SEM_FAILED == sem) + { + return false; + } + + this->mtx_desc = sem; + #else + #error "Undefine platform" + #endif + + this->mtx_name = mutexName; + + return true; + } + + bool GlobalMutex::close() + { + if (this->mtx_desc) + { + #ifdef WIN32 + ::CloseHandle(this->mtx_desc); + this->mtx_desc = nullptr; + #elif POSIX + ::sem_close(this->mtx_desc); + this->mtx_desc = nullptr; + #else + #error "Undefine platform" + #endif + + this->mtx_name.clear(); + + return true; + } + + return false; + } + + bool GlobalMutex::is_open() const + { + #ifdef WIN32 + return nullptr != this->mtx_desc; + #elif POSIX + return nullptr != this->mtx_desc; + #else + #error "Undefine platform" + #endif + } + + bool GlobalMutex::lock() const + { + #ifdef WIN32 + return WAIT_OBJECT_0 == ::WaitForSingleObject(this->mtx_desc, INFINITE); + #elif POSIX + return 0 == ::sem_wait(this->mtx_desc); + #else + #error "Undefine platform" + #endif + } + + bool GlobalMutex::try_lock() const + { + #ifdef WIN32 + return WAIT_OBJECT_0 == ::WaitForSingleObject(this->mtx_desc, 0); + #elif POSIX + return 0 == ::sem_trywait(this->mtx_desc); + #else + #error "Undefine platform" + #endif + } + + bool GlobalMutex::unlock() const + { + #ifdef WIN32 + return ::ReleaseMutex(this->mtx_desc); + #elif POSIX + return 0 == ::sem_post(this->mtx_desc); + #else + #error "Undefine platform" + #endif + } +}; \ No newline at end of file diff --git a/src/GlobalMutex.h b/src/GlobalMutex.h new file mode 100644 index 0000000..42cee55 --- /dev/null +++ b/src/GlobalMutex.h @@ -0,0 +1,45 @@ +#pragma once + +#ifdef WIN32 + #include + #include +#elif POSIX + #include +#endif + +#include + +namespace HttpServer +{ + class GlobalMutex + { + private: + #ifdef WIN32 + ::HANDLE mtx_desc; + #elif POSIX + ::sem_t *mtx_desc; + #else + #error "Undefine platform" + #endif + + std::string mtx_name; + + public: + GlobalMutex(); + ~GlobalMutex(); + + bool create(const std::string &mutexName); + bool destory(); + + static bool destory(const std::string &mutexName); + + bool open(const std::string &mutexName); + bool close(); + + bool is_open() const; + + bool lock() const; + bool try_lock() const; + bool unlock() const; + }; +}; \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp index a788f4e..c7739e1 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -34,16 +34,16 @@ int main(const int argc, const char *argv[]) } else { - std::cout << "Unknown command, see --help" << std::endl; + std::cout << "Unknown parameter, see --help" << std::endl; } } else if (1 == argc) { - std::cout << "Try: " << argv[0] << " --help" << std::endl; + std::cout << "Try to run with the parameter --help" << std::endl; } else { - std::cout << "Arguments failure, see --help command" << std::endl; + std::cout << "The number of arguments cannot be equal to zero. Enter the parameter --help" << std::endl; } return exitcode; diff --git a/src/Module.cpp b/src/Module.cpp index 43e9c9e..4ade418 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -2,10 +2,13 @@ #include "Module.h" #ifdef WIN32 + #include + #ifdef UNICODE #include #endif #elif POSIX + #include #include #endif @@ -31,6 +34,11 @@ namespace HttpServer obj.lib_handle = nullptr; } + bool Module::is_open() const + { + return nullptr != this->lib_handle; + } + bool Module::open(const std::string &libPath) { if (is_open() ) @@ -68,7 +76,7 @@ namespace HttpServer #else const std::string &lib_path = libPath; #endif - + lib_handle = ::LoadLibraryEx(lib_path.c_str(), 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); if (cookie) @@ -156,6 +164,16 @@ namespace HttpServer return false; } + bool Module::operator ==(const Module &obj) const + { + return this->lib_handle == obj.lib_handle; + } + + bool Module::operator !=(const Module &obj) const + { + return this->lib_handle != obj.lib_handle; + } + Module &Module::operator =(const Module &obj) { if (*this != obj) diff --git a/src/Module.h b/src/Module.h index 295e6ac..a1dc301 100644 --- a/src/Module.h +++ b/src/Module.h @@ -1,11 +1,8 @@ #pragma once #ifdef WIN32 - #include -#elif POSIX - #include -#else - #error "Undefine platform" + #include + #include #endif #include @@ -31,10 +28,7 @@ namespace HttpServer ~Module() = default; - inline bool is_open() const - { - return nullptr != lib_handle; - } + bool is_open() const; bool open(const std::string &libPath); void close(); @@ -42,15 +36,8 @@ namespace HttpServer bool find(const std::string &symbolName, void *(**addr)(void *) ) const; bool find(const char *symbolName, void *(**addr)(void *) ) const; - inline bool operator ==(const Module &obj) const - { - return lib_handle == obj.lib_handle; - } - - inline bool operator !=(const Module &obj) const - { - return lib_handle != obj.lib_handle; - } + bool operator ==(const Module &obj) const; + bool operator !=(const Module &obj) const; Module &operator =(const Module &obj); Module &operator =(Module &&obj); diff --git a/src/Server.cpp b/src/Server.cpp index 80095d1..130b01c 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -12,7 +12,10 @@ #include "ConfigParser.h" #include "SocketAdapterDefault.h" #include "SocketAdapterTls.h" +#include "GlobalMutex.h" +#include "SharedMemory.h" +#include #include #include #include @@ -1131,9 +1134,9 @@ namespace HttpServer app->application_final(); } } - catch (...) + catch (std::exception &exc) { - std::cout << "Warning: error when finalizing application '" << app->server_module << "';" << std::endl; + std::cout << "Warning: the error of the application's finalize '" << app->server_module << "':" << exc.what() << std::endl; } app->application_call = std::function(); @@ -1154,7 +1157,7 @@ namespace HttpServer if ( ! src) { - std::cout << "Error: file '" << app->server_module_update << "' cannot be open;" << std::endl; + std::cout << "Error: the file '" << app->server_module_update << "' cannot be open;" << std::endl; return false; } @@ -1162,7 +1165,7 @@ namespace HttpServer if ( ! dst) { - std::cout << "Error: file '" << module_name << "' cannot be open;" << std::endl; + std::cout << "Error: the file '" << module_name << "' cannot be open;" << std::endl; return false; } @@ -1196,7 +1199,7 @@ namespace HttpServer if ( ! src) { - std::cout << "Error: file '" << app->server_module_update << "' cannot be open;" << std::endl; + std::cout << "Error: the file '" << app->server_module_update << "' cannot be open;" << std::endl; return false; } @@ -1204,7 +1207,7 @@ namespace HttpServer if ( ! dst) { - std::cout << "Error: file '" << module_name << "' cannot be open;" << std::endl; + std::cout << "Error: the file '" << module_name << "' cannot be open;" << std::endl; return false; } @@ -1219,13 +1222,13 @@ namespace HttpServer if (0 != remove(module_name.c_str() ) ) { - std::cout << "Error: file '" << module_name << "' cannot be removed;" << std::endl; + std::cout << "Error: the file '" << module_name << "' could not be removed;" << std::endl; return false; } if (0 != rename(module_name_temp.c_str(), module_name.c_str() ) ) { - std::cout << "Error: file '" << module_name_temp << "' cannot be renamed;" << std::endl; + std::cout << "Error: the file '" << module_name_temp << "' could not be renamed;" << std::endl; return false; } #else @@ -1234,7 +1237,7 @@ namespace HttpServer if (false == module.is_open() ) { - std::cout << "Error: application module '" << module_name << "' cannot be open;" << std::endl; + std::cout << "Error: application's module '" << module_name << "' cloud not be opened;" << std::endl; return false; } @@ -1242,7 +1245,7 @@ namespace HttpServer if (false == module.find("application_call", &addr) ) { - std::cout << "Error: function 'application_call' not found in module '" << module_name << "';" << std::endl; + std::cout << "Error: the function 'application_call' was not found in the module '" << module_name << "';" << std::endl; return false; } @@ -1250,13 +1253,13 @@ namespace HttpServer if ( ! app_call) { - std::cout << "Error: invalid function 'application_call' in module '" << module_name << "';" << std::endl; + std::cout << "Error: invalid function 'application_call' is in the module '" << module_name << "';" << std::endl; return false; } if (false == module.find("application_clear", &addr) ) { - std::cout << "Error: function 'application_clear' not found in module '" << module_name << "';" << std::endl; + std::cout << "Error: the function 'application_clear' was not found in the module '" << module_name << "';" << std::endl; return false; } @@ -1290,9 +1293,9 @@ namespace HttpServer app->application_init(); } } - catch (...) + catch (std::exception &exc) { - std::cout << "Warning: error when initializing application '" << module_name << "';" << std::endl; + std::cout << "Warning: the error of the application's initializing '" << module_name << "':" << exc.what() << std::endl; } } @@ -1341,7 +1344,7 @@ namespace HttpServer } } - std::cout << "Notice: applications modules have been updated;" << std::endl; + std::cout << "Notice: applications' modules have been updated;" << std::endl; this->process_flag = true; this->eventUpdateModule->reset(); @@ -1422,9 +1425,9 @@ namespace HttpServer app->application_final(); } } - catch (...) + catch (std::exception &exc) { - std::cout << "Warning: error when finalizing application '" << app->server_module << "';" << std::endl; + std::cout << "Warning: the error of the application's finalize '" << app->server_module << "':" << exc.what() << std::endl; } delete app; @@ -1460,7 +1463,7 @@ namespace HttpServer if (ret < 0) { - std::cout << "Error: tls certificate credentials has not been allocated;" << std::endl; + std::cout << "Error [tls]: certificate credentials has not been allocated;" << std::endl; return false; } @@ -1471,7 +1474,7 @@ namespace HttpServer if (ret < 0) { - std::cout << "Warning: (CA) chain file has not been accepted;" << std::endl; + std::cout << "Warning [tls]: (CA) chain file has not been accepted;" << std::endl; } } @@ -1481,7 +1484,7 @@ namespace HttpServer if (ret < 0) { - std::cout << "Warning: (CLR) clr file has not been accepted;" << std::endl; + std::cout << "Warning [tls]: (CLR) clr file has not been accepted;" << std::endl; } } @@ -1489,7 +1492,7 @@ namespace HttpServer if (ret < 0) { - std::cout << "Error: (CERT) tls cert file or/and (KEY) tls key file has not been accepted;" << std::endl; + std::cout << "Error [tls]: (CERT) cert file or/and (KEY) key file has not been accepted;" << std::endl; return false; } @@ -1500,7 +1503,7 @@ namespace HttpServer if (ret < 0) { - std::cout << "Warning: (OCSP) tls stapling file has not been accepted;" << std::endl; + std::cout << "Warning [tls]: (OCSP) stapling file has not been accepted;" << std::endl; } } @@ -1537,7 +1540,7 @@ namespace HttpServer { ret = -1; - std::cout << "Error: DH params file has not been opened;" << std::endl;; + std::cout << "Error [tls]: DH params file has not been opened;" << std::endl;; } dh_file.close(); @@ -1547,7 +1550,7 @@ namespace HttpServer { ::gnutls_certificate_free_credentials(x509_cred); - std::cout << "Error: failed tls DH params get;" << std::endl; + std::cout << "Error [tls]: DH params were not loaded;" << std::endl; return false; } @@ -1562,7 +1565,7 @@ namespace HttpServer { ::gnutls_certificate_free_credentials(x509_cred); - std::cout << "Error: failed tls priority init;" << std::endl; + std::cout << "Error [tls]: priority cache cannot be init;" << std::endl; return false; } @@ -1584,19 +1587,19 @@ namespace HttpServer if (false == sock.open() ) { - std::cout << "Error: cannot open socket; errno " << Socket::getLastError() << ";" << std::endl; + std::cout << "Error: the socket cannot be open; errno " << Socket::getLastError() << ";" << std::endl; return false; } if (false == sock.bind(port) ) { - std::cout << "Error: cannot bind socket " << port << "; errno " << Socket::getLastError() << ";" << std::endl; + std::cout << "Error: the socket " << port << " cannot be bind; errno " << Socket::getLastError() << ";" << std::endl; return false; } if (false == sock.listen() ) { - std::cout << "Error: cannot listen socket " << port << "; errno " << Socket::getLastError() << ";" << std::endl; + std::cout << "Error: the socket " << port << " cannot be listen; errno " << Socket::getLastError() << ";" << std::endl; return false; } @@ -1653,16 +1656,16 @@ namespace HttpServer { if (false == this->init() ) { - return 1; + return 0x10; } this->initAppsPorts(); if (this->server_sockets.empty() ) { - std::cout << "Error: do not open any socket;" << std::endl; + std::cout << "Error: any socket was not open;" << std::endl; this->clear(); - return 2; + return 0x20; } SocketList sockets_list; @@ -1674,7 +1677,7 @@ namespace HttpServer sockets_list.addSocket(sock); } - std::cout << "Log: start server cycle;" << std::endl << std::endl; + std::cout << "Log: launch server's cycle;" << std::endl << std::endl; const size_t queue_max_length = 1024; this->eventNotFullQueue = new Event(true, true); @@ -1691,7 +1694,7 @@ namespace HttpServer std::vector accept_sockets; std::vector accept_sockets_address; - // Cycle receiving new connections + // Cycle for receiving new connections do { if (sockets_list.accept(accept_sockets, accept_sockets_address) ) @@ -1741,7 +1744,7 @@ namespace HttpServer this->clear(); - std::cout << "Log: final server cycle;" << std::endl; + std::cout << "Log: complete server's cycle;" << std::endl; return EXIT_SUCCESS; } @@ -1758,25 +1761,161 @@ namespace HttpServer this->setProcessQueue(); } + void Server::unsetProcess() + { + this->process_flag = false; + } + + void Server::setRestart() + { + this->restart_flag = true; + } + + void Server::setUpdateModule() + { + if (this->eventUpdateModule) + { + this->eventUpdateModule->notify(); + } + } + + void Server::setProcessQueue() + { + if (this->eventProcessQueue) + { + this->eventProcessQueue->notify(); + } + } + + bool Server::get_start_args(const int argc, const char *argv[], struct server_start_args *st) + { + for (int i = 1; i < argc; ++i) + { + if (0 == ::strcmp(argv[i], "--start") ) + { + + } + else if (0 == ::strcmp(argv[i], "--force") ) + { + st->force = true; + } + else if (argv[i] == ::strstr(argv[i], "--config-path=") ) + { + st->config_path = std::string(argv[i] + sizeof("--config-path=") - 1); + } + else if (argv[i] == ::strstr(argv[i], "--server-name=") ) + { + st->server_name = std::string(argv[i] + sizeof("--server-name=") - 1); + } + else + { + std::cout << "The argument '" << argv[i] << "' can't be applied with --start;" << std::endl; + + return false; + } + } + + if (st->server_name.empty() ) + { + st->server_name = argv[0]; + } + + System::filterSharedMemoryName(st->server_name); + + return true; + } + int Server::command_start(const int argc, const char *argv[]) { - const std::string pid_file_name = "httpserver.pid"; + struct server_start_args st = {}; - // TODO: - // Проверить, существует ли файл и открыт ли он уже на запись - значит сервер уже запущен - нужно завершить текущий (this) процесс + if (false == Server::get_start_args(argc, argv, &st) ) + { + return 0x1; + } - // Создать файл для хранения идентификатора процесса - std::ofstream file(pid_file_name, std::ofstream::trunc); + if (false == st.config_path.empty() ) + { + if (false == System::changeCurrentDirectory(st.config_path) ) + { + std::cout << "Configuration path '" << st.config_path << "' has not been found;" << std::endl; - // Если создать не удалось - if (false == file.good() || false == file.is_open() ) + return 0x2; + } + } + + if (st.force) { - file.close(); - return 7; + SharedMemory::destroy(st.server_name); + GlobalMutex::destory(st.server_name); + } + + GlobalMutex glob_mtx; + SharedMemory glob_mem; + + bool is_exists = false; + + if (glob_mtx.open(st.server_name) ) + { + glob_mtx.lock(); + + if (glob_mem.open(st.server_name) ) + { + System::native_processid_type pid = 0; + + if (glob_mem.read(&pid, sizeof(pid) ) ) + { + is_exists = System::isProcessExists(pid); + } + } + + glob_mtx.unlock(); + } + + if (is_exists) + { + std::cout << "The server instance with the name '" << st.server_name << "' is already running;" << std::endl; + + return 0x3; } - // Записать идентификатор текущего процесса в файл - file << std::to_string(System::getProcessId() ) << std::flush; + if (false == glob_mtx.open(st.server_name) ) + { + if (false == glob_mtx.create(st.server_name) ) + { + std::cout << "The global mutex could not been created;" << std::endl; + + return 0x4; + } + } + + glob_mtx.lock(); + + if (false == glob_mem.open(st.server_name) ) + { + if (false == glob_mem.create(st.server_name, sizeof(System::native_processid_type) ) ) + { + glob_mtx.unlock(); + + std::cout << "The shared memory could not been allocated;" << std::endl; + + return 0x5; + } + } + + System::native_processid_type pid = System::getProcessId(); + + if (false == glob_mem.write(&pid, sizeof(pid) ) ) + { + glob_mem.destroy(); + glob_mtx.unlock(); + + std::cout << "Writing data to the shared memory has failed;" << std::endl; + + return 0x6; + } + + glob_mtx.unlock(); int code = EXIT_FAILURE; @@ -1789,51 +1928,79 @@ namespace HttpServer } while (this->process_flag || this->restart_flag); - file.close(); - - remove(pid_file_name.c_str() ); + glob_mem.destroy(); + glob_mtx.destory(); return code; } - System::native_processid_type Server::getPidFromFile() const + System::native_processid_type Server::getServerProcessId(const std::string &serverName) { System::native_processid_type pid = 0; - std::ifstream file("httpserver.pid"); + GlobalMutex glob_mtx; - if (file.good() && file.is_open() ) + if (glob_mtx.open(serverName) ) { - char str_pid[32] = {0}; + SharedMemory glob_mem; - file.get(str_pid, sizeof(str_pid) ); + glob_mtx.lock(); - if (file.gcount() ) + if (glob_mem.open(serverName) ) { - pid = std::strtoull(str_pid, nullptr, 10); + glob_mem.read(&pid, sizeof(pid) ); } - } - file.close(); + glob_mtx.unlock(); + } return pid; } int Server::command_help(const int argc, const char *argv[]) const { - std::cout << "Available arguments:" << std::endl - << std::setw(4) << ' ' << "--start" << "\t\t" << "Start http server" << std::endl - << std::setw(4) << ' ' << "--restart" << "\t\t" << "Restart http server" << std::endl - << std::setw(4) << ' ' << "--update-module" << "\t" << "Update applications modules" << std::endl - << std::setw(4) << ' ' << "--kill" << "\t\t" << "Shutdown http server" << std::endl - << std::setw(4) << ' ' << "--help" << "\t\t" << "This help" << std::endl << std::endl; + std::cout << std::left << "Available arguments:" << std::endl + << std::setw(4) << ' ' << std::setw(26) << "--start" << "Start the http server" << std::endl + << std::setw(8) << ' ' << std::setw(22) << "[options]" << std::endl + << std::setw(8) << ' ' << std::setw(22) << "--force" << "Forcibly start the http server (ignore the existing instance)" << std::endl + << std::setw(8) << ' ' << std::setw(22) << "--config-path=" << "The path to the directory with configuration files" << std::endl + << std::endl + << std::setw(4) << ' ' << std::setw(26) << "--restart" << "Restart the http server" << std::endl + << std::setw(4) << ' ' << std::setw(26) << "--update-module" << "Update the applications modules" << std::endl + << std::setw(4) << ' ' << std::setw(26) << "--kill" << "Shutdown the http server" << std::endl + << std::setw(4) << ' ' << std::setw(26) << "--help" << "This help" << std::endl + << std::endl<< "Optional arguments:" << std::endl + << std::setw(4) << ' ' << std::setw(26) << "--server-name=" << "The name of the server instance" << std::endl; return EXIT_SUCCESS; } + static std::string get_server_name(const int argc, const char *argv[]) + { + std::string server_name; + + for (int i = 1; i < argc; ++i) + { + if (argv[i] == ::strstr(argv[i], "--server-name=") ) + { + server_name = std::string(argv[i] + sizeof("--server-name=") - 1); + break; + } + } + + if (server_name.empty() ) + { + server_name = argv[0]; + } + + System::filterSharedMemoryName(server_name); + + return server_name; + } + int Server::command_restart(const int argc, const char *argv[]) const { - const System::native_processid_type pid = getPidFromFile(); + const System::native_processid_type pid = Server::getServerProcessId(get_server_name(argc, argv) ); if (1 < pid && System::sendSignal(pid, SIGUSR1) ) { @@ -1845,7 +2012,7 @@ namespace HttpServer int Server::command_terminate(const int argc, const char *argv[]) const { - const System::native_processid_type pid = getPidFromFile(); + const System::native_processid_type pid = Server::getServerProcessId(get_server_name(argc, argv) ); if (1 < pid && System::sendSignal(pid, SIGTERM) ) { @@ -1857,7 +2024,7 @@ namespace HttpServer int Server::command_update_module(const int argc, const char *argv[]) const { - const System::native_processid_type pid = getPidFromFile(); + const System::native_processid_type pid = Server::getServerProcessId(get_server_name(argc, argv) ); if (1 < pid && System::sendSignal(pid, SIGUSR2) ) { diff --git a/src/Server.h b/src/Server.h index 28ca85b..54f1d2d 100644 --- a/src/Server.h +++ b/src/Server.h @@ -7,6 +7,7 @@ #include "Module.h" #include "Event.h" #include "SocketAdapter.h" +#include "ServerStructuresArguments.h" #include #include @@ -118,7 +119,7 @@ namespace HttpServer int run(); void clear(); - System::native_processid_type getPidFromFile() const; + static System::native_processid_type getServerProcessId(const std::string &serverName); void updateModules(); bool updateModule(Module &module, std::unordered_set &applications, const size_t moduleIndex); @@ -126,37 +127,17 @@ namespace HttpServer private: void addDataVariant(DataVariantAbstract *dataVariant); + static bool get_start_args(const int argc, const char *argv[], struct server_start_args *st); + public: Server(); ~Server() = default; void stopProcess(); - - inline void unsetProcess() - { - this->process_flag = false; - } - - inline void setRestart() - { - this->restart_flag = true; - } - - inline void setUpdateModule() - { - if (this->eventUpdateModule) - { - this->eventUpdateModule->notify(); - } - } - - inline void setProcessQueue() - { - if (this->eventProcessQueue) - { - this->eventProcessQueue->notify(); - } - } + void unsetProcess(); + void setRestart(); + void setUpdateModule(); + void setProcessQueue(); int command_help(const int argc, const char *argv[]) const; int command_start(const int argc, const char *argv[]); diff --git a/src/ServerStructuresArguments.h b/src/ServerStructuresArguments.h new file mode 100644 index 0000000..6877ab0 --- /dev/null +++ b/src/ServerStructuresArguments.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace HttpServer +{ + struct server_start_args + { + std::string server_name; + std::string config_path; + bool force; + }; +}; \ No newline at end of file diff --git a/src/SharedMemory.cpp b/src/SharedMemory.cpp new file mode 100644 index 0000000..6d41827 --- /dev/null +++ b/src/SharedMemory.cpp @@ -0,0 +1,240 @@ + +#include "SharedMemory.h" + +#ifdef WIN32 + #include +#elif POSIX + #include + #include + #include +#endif + +#include + +namespace HttpServer +{ + SharedMemory::SharedMemory() + { + #ifdef WIN32 + this->shm_desc = nullptr; + #elif POSIX + this->shm_desc = -1; + #else + #error "Undefine platform" + #endif + } + + SharedMemory::~SharedMemory() + { + this->close(); + } + + bool SharedMemory::create(const std::string &memName, const size_t memSize) + { + this->close(); + + #ifdef WIN32 + + this->shm_desc = ::CreateFileMapping( + INVALID_HANDLE_VALUE, + nullptr, + PAGE_READWRITE, + 0, + memSize, + memName.c_str() + ); + + if (nullptr == this->shm_desc) + { + return false; + } + + #elif POSIX + + this->shm_desc = ::shm_open(memName.c_str(), O_CREAT | O_RDWR, 0666); + + if (-1 == this->shm_desc) + { + return false; + } + + if (-1 == ::ftruncate64(this->shm_desc, memSize) ) + { + this->destroy(memName); + + return false; + } + + #else + #error "Undefine platform" + #endif + + this->shm_name = memName; + + return true; + } + + bool SharedMemory::open(const std::string &memName) + { + this->close(); + + #ifdef WIN32 + + this->shm_desc = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, false, memName.c_str() ); + + if (nullptr == this->shm_desc) + { + return false; + } + + #elif POSIX + + this->shm_desc = ::shm_open(memName.c_str(), O_RDWR, 0666); + + if (-1 == this->shm_desc) + { + return false; + } + + #else + #error "Undefine platform" + #endif + + this->shm_name = memName; + + return true; + } + + bool SharedMemory::is_open() const + { + #ifdef WIN32 + return nullptr != this->shm_desc; + #elif POSIX + return -1 != this->shm_desc; + #else + #error "Undefine platform" + #endif + } + + bool SharedMemory::write(const void *src, const size_t size, const size_t offset) const + { + #ifdef WIN32 + + void * const addr = ::MapViewOfFile(this->shm_desc, FILE_MAP_WRITE, 0, offset, size); + + if (nullptr == addr) + { + return false; + } + + ::CopyMemory(addr, src, size); + + ::UnmapViewOfFile(addr); + + #elif POSIX + + void * const addr = ::mmap(0, size, PROT_WRITE, MAP_SHARED, this->shm_desc, offset); + + if (reinterpret_cast(-1) == addr) + { + return false; + } + + ::memcpy(addr, src, size); + + ::munmap(addr, size); + + #else + #error "Undefine platform" + #endif + + return true; + } + + bool SharedMemory::read(void *dest, const size_t size, const size_t offset) const + { + #ifdef WIN32 + + void * const addr = ::MapViewOfFile(this->shm_desc, FILE_MAP_READ, 0, offset, size); + + if (nullptr == addr) + { + return false; + } + + ::CopyMemory(dest, addr, size); + + ::UnmapViewOfFile(addr); + + #elif POSIX + + void * const addr = ::mmap(0, size, PROT_READ, MAP_SHARED, this->shm_desc, offset); + + if (reinterpret_cast(-1) == addr) + { + return false; + } + + ::memcpy(dest, addr, size); + + ::munmap(addr, size); + + #else + #error "Undefine platform" + #endif + + return true; + } + + bool SharedMemory::close() + { + if (this->is_open() ) + { + #ifdef WIN32 + ::CloseHandle(this->shm_desc); + this->shm_desc = nullptr; + #elif POSIX + ::close(this->shm_desc); + this->shm_desc = ~0; + #else + #error "Undefine platform" + #endif + + this->shm_name.clear(); + + return true; + } + + return false; + } + + bool SharedMemory::destroy() + { + #ifdef WIN32 + bool ret = ::CloseHandle(this->shm_desc); + + this->close(); + + return ret; + #elif POSIX + const int ret = ::shm_unlink(this->shm_name.c_str() ); + + this->close(); + + return 0 == ret; + #else + #error "Undefine platform" + #endif + } + + bool SharedMemory::destroy(const std::string &memName) + { + #ifdef WIN32 + return ::CloseHandle(this->shm_desc); + #elif POSIX + return 0 == ::shm_unlink(memName.c_str() ); + #else + #error "Undefine platform" + #endif + } +}; \ No newline at end of file diff --git a/src/SharedMemory.h b/src/SharedMemory.h new file mode 100644 index 0000000..8ea5b24 --- /dev/null +++ b/src/SharedMemory.h @@ -0,0 +1,42 @@ +#pragma once + +#ifdef WIN32 + #include + #include +#endif + +#include + +namespace HttpServer +{ + class SharedMemory + { + private: + #ifdef WIN32 + ::HANDLE shm_desc; + #elif POSIX + int shm_desc; + #else + #error "Undefine platform" + #endif + + std::string shm_name; + + public: + SharedMemory(); + ~SharedMemory(); + + bool create(const std::string &memName, const size_t memSize); + bool open(const std::string &memName); + + bool is_open() const; + + bool write(const void *data, const size_t size, const size_t offset = 0) const; + bool read(void *dest, const size_t size, const size_t offset = 0) const; + + bool close(); + bool destroy(); + + static bool destroy(const std::string &memName); + }; +}; \ No newline at end of file diff --git a/src/SignalHandlers.cpp b/src/SignalHandlers.cpp index 4286810..cdc4bd4 100644 --- a/src/SignalHandlers.cpp +++ b/src/SignalHandlers.cpp @@ -17,7 +17,7 @@ static HttpServer::Server *globalServerPtr = nullptr; /** * Terminate signal */ -static void handlerSigTerm(const int sig) +static void handlerSigTerm(const int) { if (globalServerPtr) { @@ -28,7 +28,7 @@ static void handlerSigTerm(const int sig) /** * Interrupt signal */ -static void handlerSigInt(const int sig) +static void handlerSigInt(const int) { if (globalServerPtr) { @@ -39,7 +39,7 @@ static void handlerSigInt(const int sig) /** * Signal to restart */ -static void handlerSigUsr1(const int sig) +static void handlerSigUsr1(const int) { if (globalServerPtr) { @@ -51,7 +51,7 @@ static void handlerSigUsr1(const int sig) /** * Signal to update modules */ -static void handlerSigUsr2(const int sig) +static void handlerSigUsr2(const int) { if (globalServerPtr) { diff --git a/src/Socket.cpp b/src/Socket.cpp index ead8bb4..2a1cd09 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -1,6 +1,16 @@ #include "Socket.h" +#ifdef POSIX + #include + #include + #include + #include + #include + #include + #include +#endif + namespace HttpServer { bool Socket::Startup() @@ -90,6 +100,22 @@ namespace HttpServer return false; } + bool Socket::is_open() const + { + #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 + { + return this->socket_handle; + } + bool Socket::bind(const int port) const { const ::sockaddr_in sock_addr = { diff --git a/src/Socket.h b/src/Socket.h index fb7eecc..738abc8 100644 --- a/src/Socket.h +++ b/src/Socket.h @@ -1,21 +1,7 @@ #pragma once -#ifdef POSIX - #include - #include - #include - #include - #include - #include - #include - #include -#endif - #include "System.h" -#include -#include - #include #include #include @@ -43,16 +29,8 @@ namespace HttpServer 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 is_open() const; + System::native_socket_type get_handle() const; bool bind(const int port) const; bool listen() const; @@ -78,11 +56,6 @@ namespace HttpServer 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; diff --git a/src/SocketList.cpp b/src/SocketList.cpp index 4d4fe0a..bbd82f4 100644 --- a/src/SocketList.cpp +++ b/src/SocketList.cpp @@ -1,6 +1,12 @@  #include "SocketList.h" +#ifdef POSIX + #include + #include + #include +#endif + namespace HttpServer { SocketList::SocketList() diff --git a/src/SocketList.h b/src/SocketList.h index b61f145..06c8d56 100644 --- a/src/SocketList.h +++ b/src/SocketList.h @@ -2,6 +2,11 @@ #include "Socket.h" +#ifdef POSIX + #include + #include +#endif + namespace HttpServer { class SocketList diff --git a/src/System.cpp b/src/System.cpp index 636f4cd..ea2180f 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -10,6 +10,11 @@ #ifdef UNICODE #include #endif +#elif POSIX + #include + #include + #include + #include #endif namespace System @@ -47,6 +52,41 @@ namespace System } #endif + native_processid_type getProcessId() + { + #ifdef WIN32 + return ::GetCurrentProcessId(); + #elif POSIX + return ::getpid(); + #else + #error "Undefine platform" + #endif + } + + bool changeCurrentDirectory(const std::string &dir) + { + #ifdef WIN32 + return ::SetCurrentDirectory(dir.c_str() ); + #elif POSIX + return 0 == ::chdir(dir.c_str() ); + #else + #error "Undefine platform" + #endif + } + + bool isProcessExists(const native_processid_type pid) + { + #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) { #ifdef WIN32 @@ -67,6 +107,17 @@ namespace System #endif } + 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 + } + std::string getTempDir() { #ifdef WIN32 @@ -207,4 +258,26 @@ namespace System #error "Undefine platform" #endif } + + void filterSharedMemoryName(std::string &memName) + { + #ifdef WIN32 + + #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 + } }; \ No newline at end of file diff --git a/src/System.h b/src/System.h index 87d0fac..6d5e109 100644 --- a/src/System.h +++ b/src/System.h @@ -2,9 +2,6 @@ #ifdef WIN32 #include - #include - #undef min - #undef max ::TCHAR myWndClassName[]; @@ -26,15 +23,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 +50,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 - } + native_processid_type getProcessId(); + + bool changeCurrentDirectory(const std::string &dir); + + bool isProcessExists(const native_processid_type pid); 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 - } + bool isDoneThread(const std::thread::native_handle_type handle); std::string getTempDir(); bool isFileExists(const std::string &fileName); bool getFileSizeAndTimeGmt(const std::string &filePath, size_t *fileSize, time_t *fileTime); + + void filterSharedMemoryName(std::string &memName); }; \ No newline at end of file From 2ce931519b740c12e192a23209f02f48901b560d Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Sat, 23 Jul 2016 01:01:25 +0300 Subject: [PATCH 27/50] Command line parameters '--config-path=' and '--server-name=' were added (for Windows) --- projects/msvs/httpserver.vcxproj | 14 +++-- projects/msvs/httpserver.vcxproj.filters | 15 ++++++ projects/msvs/httpserver.vcxproj.user | 8 +++ src/GlobalMutex.cpp | 57 +++++++++++++++++--- src/Module.cpp | 2 +- src/SharedMemory.cpp | 66 ++++++++++++++++++++---- src/Socket.cpp | 16 +++--- src/SocketAdapterTls.cpp | 2 +- src/SocketList.cpp | 6 +-- src/System.cpp | 47 +++++++++++++++-- 10 files changed, 193 insertions(+), 40 deletions(-) diff --git a/projects/msvs/httpserver.vcxproj b/projects/msvs/httpserver.vcxproj index 402b215..4808b5f 100644 --- a/projects/msvs/httpserver.vcxproj +++ b/projects/msvs/httpserver.vcxproj @@ -25,11 +25,13 @@ + + @@ -47,6 +49,7 @@ + @@ -57,6 +60,8 @@ + + @@ -70,6 +75,7 @@ {A7023B84-DA18-3E3E-A9AE-B87F45CAC37F} httpserver Qt4VSv1.0 + 8.1 @@ -162,7 +168,7 @@ Sync $(OutDir)obj\ MaxSpeed - _CONSOLE;WIN32;NDEBUG;%(PreprocessorDefinitions) + _CONSOLE;WIN32;NDEBUG;NOMINMAX;%(PreprocessorDefinitions) false ..\..\build\ MultiThreadedDLL @@ -201,7 +207,7 @@ Sync $(OutDir)obj\ MaxSpeed - _CONSOLE;WIN32;NDEBUG;%(PreprocessorDefinitions) + _CONSOLE;WIN32;NDEBUG;NOMINMAX;%(PreprocessorDefinitions) false ..\..\build\ MultiThreadedDLL @@ -240,7 +246,7 @@ ProgramDatabase Sync $(OutDir)obj\ - _CONSOLE;WIN32;DEBUG;%(PreprocessorDefinitions) + _CONSOLE;WIN32;DEBUG;NOMINMAX;%(PreprocessorDefinitions) false ..\..\build\ MultiThreadedDebugDLL @@ -278,7 +284,7 @@ ProgramDatabase Sync $(OutDir)obj\ - _CONSOLE;WIN32;DEBUG;%(PreprocessorDefinitions) + _CONSOLE;WIN32;DEBUG;NOMINMAX;%(PreprocessorDefinitions) false ..\..\build\ MultiThreadedDebugDLL diff --git a/projects/msvs/httpserver.vcxproj.filters b/projects/msvs/httpserver.vcxproj.filters index 46b165a..e539bf5 100644 --- a/projects/msvs/httpserver.vcxproj.filters +++ b/projects/msvs/httpserver.vcxproj.filters @@ -76,6 +76,12 @@ Source Files + + Source Files + + + Source Files + @@ -153,5 +159,14 @@ Header Files + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/projects/msvs/httpserver.vcxproj.user b/projects/msvs/httpserver.vcxproj.user index 9ab31d5..70e72e1 100644 --- a/projects/msvs/httpserver.vcxproj.user +++ b/projects/msvs/httpserver.vcxproj.user @@ -13,4 +13,12 @@ D:\httpserver\debug WindowsLocalDebugger + + --start + WindowsLocalDebugger + + + --start + WindowsLocalDebugger + \ No newline at end of file diff --git a/src/GlobalMutex.cpp b/src/GlobalMutex.cpp index 9fa7ca5..68a0c3a 100644 --- a/src/GlobalMutex.cpp +++ b/src/GlobalMutex.cpp @@ -3,6 +3,10 @@ #ifdef WIN32 #include + + #ifdef UNICODE + #include + #endif #elif POSIX #include #endif @@ -24,7 +28,17 @@ namespace HttpServer this->close(); #ifdef WIN32 - this->mtx_desc = ::CreateMutex(nullptr, false, mutexName.c_str() ); + + this->mtx_name = "mtx-" + mutexName; + + #ifdef UNICODE + std::wstring_convert > converter; + const std::wstring mutex_name = converter.from_bytes(this->mtx_name); + #else + const std::string &mutex_name = this->mtx_name; + #endif + + this->mtx_desc = ::CreateMutex(nullptr, false, mutex_name.c_str() ); if (nullptr == this->mtx_desc) { @@ -39,19 +53,29 @@ namespace HttpServer } this->mtx_desc = sem; + this->mtx_name = mutexName; #else #error "Undefine platform" #endif - this->mtx_name = mutexName; - return true; } bool GlobalMutex::destory(const std::string &mutexName) { #ifdef WIN32 - return true; + const std::string mtx_name = "mtx-" + mutexName; + + #ifdef UNICODE + std::wstring_convert > converter; + const std::wstring mutex_name = converter.from_bytes(mtx_name); + #else + const std::string &mutex_name = mtx_name; + #endif + + ::HANDLE hMutex = ::OpenMutex(DELETE, true, mutex_name.c_str() ); + + return 0 != ::CloseHandle(hMutex); #elif POSIX return 0 == ::sem_unlink(mutexName.c_str() ); #else @@ -62,7 +86,16 @@ namespace HttpServer bool GlobalMutex::destory() { #ifdef WIN32 - const bool ret = ::CloseHandle(this->mtx_desc); + #ifdef UNICODE + std::wstring_convert > converter; + const std::wstring mutex_name = converter.from_bytes(this->mtx_name); + #else + const std::string &mutex_name = this->mtx_name; + #endif + + ::HANDLE hMutex = ::OpenMutex(DELETE, true, mutex_name.c_str() ); + + const bool ret = (0 != ::CloseHandle(hMutex) ); this->close(); @@ -83,7 +116,17 @@ namespace HttpServer this->close(); #ifdef WIN32 - this->mtx_desc = ::OpenMutex(SYNCHRONIZE, false, mutexName.c_str() ); + + this->mtx_name = "mtx-" + mutexName; + + #ifdef UNICODE + std::wstring_convert > converter; + const std::wstring mutex_name = converter.from_bytes(this->mtx_name); + #else + const std::string &mutex_name = this->mtx_name; + #endif + + this->mtx_desc = ::OpenMutex(SYNCHRONIZE, false, mutex_name.c_str() ); if (nullptr == this->mtx_desc) { @@ -165,7 +208,7 @@ namespace HttpServer bool GlobalMutex::unlock() const { #ifdef WIN32 - return ::ReleaseMutex(this->mtx_desc); + return 0 != ::ReleaseMutex(this->mtx_desc); #elif POSIX return 0 == ::sem_post(this->mtx_desc); #else diff --git a/src/Module.cpp b/src/Module.cpp index 4ade418..50aa0b5 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -71,7 +71,7 @@ namespace HttpServer } #ifdef UNICODE - std::wstring_convert> converter; + std::wstring_convert > converter; const std::wstring lib_path = converter.from_bytes(libPath); #else const std::string &lib_path = libPath; diff --git a/src/SharedMemory.cpp b/src/SharedMemory.cpp index 6d41827..878d3d4 100644 --- a/src/SharedMemory.cpp +++ b/src/SharedMemory.cpp @@ -3,6 +3,10 @@ #ifdef WIN32 #include + + #ifdef UNICODE + #include + #endif #elif POSIX #include #include @@ -35,13 +39,22 @@ namespace HttpServer #ifdef WIN32 + this->shm_name = "shm-" + memName; + + #ifdef UNICODE + std::wstring_convert > converter; + const std::wstring memory_name = converter.from_bytes(this->shm_name); + #else + const std::string &memory_name = this->shm_name; + #endif + this->shm_desc = ::CreateFileMapping( INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, - memSize, - memName.c_str() + static_cast<::DWORD>(memSize), + memory_name.c_str() ); if (nullptr == this->shm_desc) @@ -65,12 +78,12 @@ namespace HttpServer return false; } + this->shm_name = memName; + #else #error "Undefine platform" #endif - this->shm_name = memName; - return true; } @@ -80,13 +93,24 @@ namespace HttpServer #ifdef WIN32 - this->shm_desc = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, false, memName.c_str() ); + this->shm_name = "shm-" + memName; + + #ifdef UNICODE + std::wstring_convert > converter; + const std::wstring memory_name = converter.from_bytes(this->shm_name); + #else + const std::string &memory_name = this->shm_name; + #endif + + this->shm_desc = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, false, memory_name.c_str() ); if (nullptr == this->shm_desc) { return false; } + this->shm_name = memName; + #elif POSIX this->shm_desc = ::shm_open(memName.c_str(), O_RDWR, 0666); @@ -96,12 +120,12 @@ namespace HttpServer return false; } + this->shm_name = memName; + #else #error "Undefine platform" #endif - this->shm_name = memName; - return true; } @@ -120,7 +144,7 @@ namespace HttpServer { #ifdef WIN32 - void * const addr = ::MapViewOfFile(this->shm_desc, FILE_MAP_WRITE, 0, offset, size); + void * const addr = ::MapViewOfFile(this->shm_desc, FILE_MAP_WRITE, 0, static_cast<::DWORD>(offset), size); if (nullptr == addr) { @@ -155,7 +179,7 @@ namespace HttpServer { #ifdef WIN32 - void * const addr = ::MapViewOfFile(this->shm_desc, FILE_MAP_READ, 0, offset, size); + void * const addr = ::MapViewOfFile(this->shm_desc, FILE_MAP_READ, 0, static_cast<::DWORD>(offset), size); if (nullptr == addr) { @@ -211,7 +235,16 @@ namespace HttpServer bool SharedMemory::destroy() { #ifdef WIN32 - bool ret = ::CloseHandle(this->shm_desc); + #ifdef UNICODE + std::wstring_convert > converter; + const std::wstring memory_name = converter.from_bytes(this->shm_name); + #else + const std::string &memory_name = this->shm_name; + #endif + + ::HANDLE hMemory = ::OpenFileMapping(DELETE, false, memory_name.c_str() ); + + const bool ret = (0 != ::CloseHandle(hMemory) ); this->close(); @@ -230,7 +263,18 @@ namespace HttpServer bool SharedMemory::destroy(const std::string &memName) { #ifdef WIN32 - return ::CloseHandle(this->shm_desc); + const std::string shm_name = "shm-" + memName; + + #ifdef UNICODE + std::wstring_convert > converter; + const std::wstring memory_name = converter.from_bytes(shm_name); + #else + const std::string &memory_name = shm_name; + #endif + + ::HANDLE hMemory = ::OpenFileMapping(DELETE, false, memory_name.c_str() ); + + return 0 != ::CloseHandle(hMemory); #elif POSIX return 0 == ::shm_unlink(memName.c_str() ); #else diff --git a/src/Socket.cpp b/src/Socket.cpp index 2a1cd09..158e2d0 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -186,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) ); } @@ -265,7 +265,7 @@ namespace HttpServer long Socket::recv(std::vector &buf) const { #ifdef WIN32 - return ::recv(this->socket_handle, buf.data(), buf.size(), 0); + return ::recv(this->socket_handle, buf.data(), static_cast(buf.size() ), 0); #elif POSIX return ::recv(this->socket_handle, buf.data(), buf.size(), 0); #else @@ -283,9 +283,9 @@ 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) { - recv_len = ::recv(this->socket_handle, buf.data(), buf.size(), 0); + recv_len = ::recv(this->socket_handle, buf.data(), static_cast(buf.size() ), 0); } #elif POSIX struct ::pollfd event = { @@ -320,7 +320,7 @@ namespace HttpServer total += send_size; } - return total; + return static_cast(total); } long Socket::send(const std::string &buf) const @@ -346,9 +346,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) { @@ -392,7 +392,7 @@ 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 diff --git a/src/SocketAdapterTls.cpp b/src/SocketAdapterTls.cpp index b26903d..2860db7 100644 --- a/src/SocketAdapterTls.cpp +++ b/src/SocketAdapterTls.cpp @@ -72,7 +72,7 @@ namespace HttpServer total += send_size; } - return total; + return static_cast(total); } System::native_socket_type SocketAdapterTls::get_handle() const diff --git a/src/SocketList.cpp b/src/SocketList.cpp index bbd82f4..e016ed8 100644 --- a/src/SocketList.cpp +++ b/src/SocketList.cpp @@ -157,7 +157,7 @@ namespace HttpServer if (is_created() ) { #ifdef WIN32 - const int count = ::WSAPoll(this->poll_events.data(), 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) { @@ -229,7 +229,7 @@ namespace HttpServer if (is_created() ) { #ifdef WIN32 - const int count = ::WSAPoll(this->poll_events.data(), 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) { @@ -312,7 +312,7 @@ namespace HttpServer } #ifdef WIN32 - const int count = ::WSAPoll(this->poll_events.data(), this->poll_events.size(), 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) { diff --git a/src/System.cpp b/src/System.cpp index ea2180f..c903837 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -38,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) ) { @@ -66,7 +66,13 @@ namespace System bool changeCurrentDirectory(const std::string &dir) { #ifdef WIN32 - return ::SetCurrentDirectory(dir.c_str() ); + #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 @@ -121,12 +127,12 @@ namespace System 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); @@ -262,7 +268,38 @@ namespace System 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() ) { From f5d621210aaf61b75a6b75d9c4f7cdab6408ea86 Mon Sep 17 00:00:00 2001 From: awwit Date: Thu, 18 Aug 2016 19:28:36 +0300 Subject: [PATCH 28/50] Improvements in the code class Event --- src/Event.cpp | 73 +++++++++++++++++++++++++++++++------------------- src/Server.cpp | 26 +++++++++--------- 2 files changed, 59 insertions(+), 40 deletions(-) diff --git a/src/Event.cpp b/src/Event.cpp index c7a9d42..77eeb40 100644 --- a/src/Event.cpp +++ b/src/Event.cpp @@ -10,73 +10,92 @@ namespace HttpServer void Event::wait() { - std::unique_lock lck(mtx); - - while (false == signaled) + if (false == this->signaled.load() ) { - cv.wait(lck); + std::unique_lock lck(this->mtx); + + do + { + this->cv.wait(lck); + } + while (false == this->signaled.load() ); } - if (false == manually) + if (false == this->manually) { - signaled = false; + this->signaled.store(false); } } bool Event::wait_for(const std::chrono::milliseconds &ms) { - std::unique_lock lck(mtx); + bool is_timeout = false; - auto const status = cv.wait_for(lck, ms); + 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 == manually) + if (false == this->manually) { - signaled = false; + this->signaled.store(false); } - return std::cv_status::timeout == status; + return is_timeout; } bool Event::wait_until(const std::chrono::high_resolution_clock::time_point &tp) { - std::unique_lock lck(mtx); + bool is_timeout = false; + + if (false == this->signaled.load() ) + { + std::unique_lock lck(this->mtx); - auto const status = cv.wait_until(lck, tp); + do + { + if (std::cv_status::timeout == this->cv.wait_until(lck, tp) ) + { + is_timeout = true; + break; + } + } + while (false == this->signaled.load() ); + } - if (false == manually) + if (false == this->manually) { - signaled = false; + this->signaled.store(false); } - return std::cv_status::timeout == status; + return is_timeout; } void Event::notify() { - signaled = true; - cv.notify_all(); + this->signaled.store(true); + this->cv.notify_all(); } void Event::notify(const size_t threadsCount) { - if (threadsCount) - { - signaled = true; + this->signaled.store(true); - for (size_t i = 0; i < threadsCount; ++i) - { - cv.notify_one(); - } + for (size_t i = 0; i < threadsCount; ++i) + { + this->cv.notify_one(); } } void Event::reset() { - signaled = false; + this->signaled.store(false); } bool Event::notifed() const { - return signaled; + return this->signaled.load(); } }; \ No newline at end of file diff --git a/src/Server.cpp b/src/Server.cpp index 130b01c..6c53dea 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -941,7 +941,7 @@ namespace HttpServer { while (true) { - Socket clientSocket; + Socket sock; struct sockaddr_in addr; eventThreadCycle.wait(); @@ -955,7 +955,7 @@ namespace HttpServer if (sockets.size() ) { - std::tie(clientSocket, addr) = sockets.front(); + std::tie(sock, addr) = sockets.front(); sockets.pop(); } @@ -969,16 +969,16 @@ namespace HttpServer this->sockets_queue_mtx.unlock(); - if (clientSocket.is_open() ) + if (sock.is_open() ) { ++this->threads_working_count; - struct ::sockaddr_in p; - ::socklen_t p_len = sizeof(p); + struct ::sockaddr_in sock_addr; + ::socklen_t sock_addr_len = sizeof(sock_addr); - ::getsockname(clientSocket.get_handle(), reinterpret_cast(&p), &p_len); + ::getsockname(sock.get_handle(), reinterpret_cast(&sock_addr), &sock_addr_len); - const int port = ntohs(p.sin_port); + const int port = ntohs(sock_addr.sin_port); auto const it = this->tls_data.find(port); @@ -986,22 +986,22 @@ namespace HttpServer { const std::tuple &data = it->second; - SocketAdapterTls sock( - clientSocket, + SocketAdapterTls socket_adapter( + sock, std::get(data), std::get(data) ); - if (sock.handshake() ) + if (socket_adapter.handshake() ) { - this->threadRequestProc(sock, addr); + this->threadRequestProc(socket_adapter, addr); } } else { - SocketAdapterDefault sock(clientSocket); + SocketAdapterDefault socket_adapter(sock); - this->threadRequestProc(sock, addr); + this->threadRequestProc(socket_adapter, addr); } --this->threads_working_count; From 0e20e1b78dc4387181ddfc32ba9f805051336179 Mon Sep 17 00:00:00 2001 From: awwit Date: Thu, 30 Mar 2017 22:28:45 +0300 Subject: [PATCH 29/50] Refactor code, categorize source code files. Add HTTP/2 protocol support --- README.md | 24 +- projects/qt-creator/httpserver.qbs | 158 +- src/DataVariantAbstract.h | 40 - src/DataVariantFormUrlencoded.cpp | 62 - src/DataVariantFormUrlencoded.h | 22 - src/DataVariantMultipartFormData.cpp | 426 -- src/DataVariantMultipartFormData.h | 35 - src/DataVariantTextPlain.cpp | 60 - src/DataVariantTextPlain.h | 22 - src/FileIncoming.cpp | 36 - src/FileIncoming.h | 41 - src/Main.cpp | 4 +- src/RawData.h | 20 - src/RequestParameters.cpp | 21 - src/RequestParameters.h | 31 - src/Server.cpp | 2036 ------ src/Server.h | 148 - src/ServerApplicationDefaultSettings.h | 12 - src/ServerRequest.h | 53 - src/ServerResponse.h | 23 - src/SignalHandlers.cpp | 36 +- src/SignalHandlers.h | 6 +- src/Socket.h | 76 - 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/Utils.cpp | 459 -- src/Utils.h | 74 - src/server/Request.cpp | 20 + src/server/Request.h | 44 + src/server/Server.cpp | 1109 +++ src/server/Server.h | 62 + src/{ => server}/ServerApplicationSettings.h | 11 +- src/{ => server}/ServerApplicationsTree.cpp | 47 +- src/{ => server}/ServerApplicationsTree.h | 10 +- src/server/ServerControls.cpp | 75 + src/server/ServerControls.h | 37 + src/server/ServerSettings.cpp | 61 + src/server/ServerSettings.h | 25 + src/{ => server}/ServerStructuresArguments.h | 2 +- src/server/SocketsQueue.h | 20 + src/{ => server/config}/ConfigParser.cpp | 46 +- src/{ => server/config}/ConfigParser.h | 24 +- src/server/data-variant/Abstract.cpp | 20 + src/server/data-variant/Abstract.h | 40 + src/server/data-variant/FormUrlencoded.cpp | 63 + src/server/data-variant/FormUrlencoded.h | 15 + src/server/data-variant/MultipartFormData.cpp | 411 ++ src/server/data-variant/MultipartFormData.h | 19 + src/server/data-variant/TextPlain.cpp | 61 + src/server/data-variant/TextPlain.h | 15 + src/server/protocol/ServerHttp1.cpp | 563 ++ src/server/protocol/ServerHttp1.h | 29 + src/server/protocol/ServerHttp2.cpp | 728 ++ src/server/protocol/ServerHttp2.h | 21 + src/server/protocol/ServerHttp2Protocol.cpp | 178 + src/server/protocol/ServerHttp2Protocol.h | 25 + src/server/protocol/ServerHttp2Stream.cpp | 110 + src/server/protocol/ServerHttp2Stream.h | 16 + src/server/protocol/ServerProtocol.cpp | 166 + src/server/protocol/ServerProtocol.h | 39 + src/server/protocol/ServerWebSocket.cpp | 47 + src/server/protocol/ServerWebSocket.h | 22 + src/server/protocol/extensions/Sendfile.cpp | 375 + src/server/protocol/extensions/Sendfile.h | 41 + 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/{SocketList.cpp => socket/List.cpp} | 59 +- src/{SocketList.h => socket/List.h} | 24 +- src/{ => socket}/Socket.cpp | 114 +- src/socket/Socket.h | 79 + src/system/Cache.h | 24 + src/{ => system}/GlobalMutex.cpp | 18 +- src/{ => system}/GlobalMutex.h | 18 +- src/{ => system}/Module.cpp | 26 +- src/{ => system}/Module.h | 28 +- src/{ => system}/SharedMemory.cpp | 16 +- src/{ => system}/SharedMemory.h | 16 +- src/{ => system}/System.cpp | 10 +- src/{ => system}/System.h | 12 +- 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 | 15 +- src/{ => utils}/Event.h | 16 +- src/utils/Utils.cpp | 841 +++ src/utils/Utils.h | 137 + 101 files changed, 12901 insertions(+), 4319 deletions(-) delete mode 100644 src/DataVariantAbstract.h delete mode 100644 src/DataVariantFormUrlencoded.cpp delete mode 100644 src/DataVariantFormUrlencoded.h delete mode 100644 src/DataVariantMultipartFormData.cpp delete mode 100644 src/DataVariantMultipartFormData.h delete mode 100644 src/DataVariantTextPlain.cpp delete mode 100644 src/DataVariantTextPlain.h delete mode 100644 src/FileIncoming.cpp delete mode 100644 src/FileIncoming.h delete mode 100644 src/RawData.h delete mode 100644 src/RequestParameters.cpp delete mode 100644 src/RequestParameters.h delete mode 100644 src/Server.cpp delete mode 100644 src/Server.h delete mode 100644 src/ServerApplicationDefaultSettings.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/Utils.cpp delete mode 100644 src/Utils.h create mode 100644 src/server/Request.cpp create mode 100644 src/server/Request.h create mode 100644 src/server/Server.cpp create mode 100644 src/server/Server.h rename src/{ => server}/ServerApplicationSettings.h (73%) rename src/{ => server}/ServerApplicationsTree.cpp (75%) rename src/{ => server}/ServerApplicationsTree.h (84%) create mode 100644 src/server/ServerControls.cpp create mode 100644 src/server/ServerControls.h create mode 100644 src/server/ServerSettings.cpp create mode 100644 src/server/ServerSettings.h rename src/{ => server}/ServerStructuresArguments.h (98%) create mode 100644 src/server/SocketsQueue.h rename src/{ => server/config}/ConfigParser.cpp (90%) rename src/{ => server/config}/ConfigParser.h (56%) create mode 100644 src/server/data-variant/Abstract.cpp create mode 100644 src/server/data-variant/Abstract.h create mode 100644 src/server/data-variant/FormUrlencoded.cpp create mode 100644 src/server/data-variant/FormUrlencoded.h create mode 100644 src/server/data-variant/MultipartFormData.cpp create mode 100644 src/server/data-variant/MultipartFormData.h create mode 100644 src/server/data-variant/TextPlain.cpp create mode 100644 src/server/data-variant/TextPlain.h create mode 100644 src/server/protocol/ServerHttp1.cpp create mode 100644 src/server/protocol/ServerHttp1.h create mode 100644 src/server/protocol/ServerHttp2.cpp create mode 100644 src/server/protocol/ServerHttp2.h create mode 100644 src/server/protocol/ServerHttp2Protocol.cpp create mode 100644 src/server/protocol/ServerHttp2Protocol.h create mode 100644 src/server/protocol/ServerHttp2Stream.cpp create mode 100644 src/server/protocol/ServerHttp2Stream.h create mode 100644 src/server/protocol/ServerProtocol.cpp create mode 100644 src/server/protocol/ServerProtocol.h create mode 100644 src/server/protocol/ServerWebSocket.cpp create mode 100644 src/server/protocol/ServerWebSocket.h create mode 100644 src/server/protocol/extensions/Sendfile.cpp create mode 100644 src/server/protocol/extensions/Sendfile.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 rename src/{SocketList.cpp => socket/List.cpp} (83%) rename src/{SocketList.h => socket/List.h} (60%) rename src/{ => socket}/Socket.cpp (73%) create mode 100644 src/socket/Socket.h create mode 100644 src/system/Cache.h rename src/{ => system}/GlobalMutex.cpp (92%) rename src/{ => system}/GlobalMutex.h (67%) rename src/{ => system}/Module.cpp (84%) rename src/{ => system}/Module.h (51%) rename src/{ => system}/SharedMemory.cpp (95%) rename src/{ => system}/SharedMemory.h (76%) rename src/{ => system}/System.cpp (97%) rename src/{ => system}/System.h (88%) 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 rename src/{ => utils}/Event.cpp (83%) rename src/{ => utils}/Event.h (59%) create mode 100644 src/utils/Utils.cpp create mode 100644 src/utils/Utils.h diff --git a/README.md b/README.md index 0e1b53b..75bcf02 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -httpserver -========== +# httpserver Http server is written on C++14 language. @@ -11,20 +10,19 @@ by using the parameter `server_module`. Sample application code: https://github.com/awwit/httpserverapp -Features --------- +## Features This http server support: * HTTP v1.1 * HTTPS (TLS) +* HTTP v2 (*need optimize cleanup of streams*) * Keep-Alive * WebSocket -* Get-Parted requests * X-Sendfile (header) +* Get-Parted requests -Dependencies ------------- +## Dependencies Common: @@ -34,8 +32,7 @@ Linux: `dl`, `pthread`, `rt`, `gnutls` Windows: `ws2_32.lib`, `libgnutls.dll.a` -Build ------ +## Build Linux: @@ -57,8 +54,7 @@ cd build devenv ./../projects/msvs/httpserver.sln /build ``` -Server start ------------- +## Server start ```sh ./httpserver --start @@ -70,14 +66,12 @@ Or input a parameter `--config-path=` to set the directory with configurat Use the parameter `--server-name=` to define the name of web-server's instance. Instances can be used to run web-servers with different settings. -Server configuration --------------------- +## Server configuration Server (and its applications) setting is made using config-files. Examples of settings are located in the folder [samples](samples/). -License -======= +# License The source codes are licensed under the [AGPL](http://www.gnu.org/licenses/agpl.html), diff --git a/projects/qt-creator/httpserver.qbs b/projects/qt-creator/httpserver.qbs index 67eab75..464d956 100644 --- a/projects/qt-creator/httpserver.qbs +++ b/projects/qt-creator/httpserver.qbs @@ -1,76 +1,100 @@ import qbs Project { - CppApplication { - name: "httpserver" + CppApplication { + name: "httpserver" - cpp.cxxLanguageVersion: "c++14" + cpp.cxxLanguageVersion: "c++14" - cpp.defines: qbs.buildVariant == "debug" ? base : base.concat(["DEBUG"]) + cpp.defines: qbs.buildVariant == "debug" ? ["DEBUG"] : original - 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", "rt"]) - } + Properties { + condition: qbs.targetOS.contains("linux") + cpp.platformDefines: outer.concat(["POSIX"]) + cpp.dynamicLibraries: outer.concat(["dl", "pthread", "rt"]) + } + Properties { + condition: qbs.targetOS.contains("windows") + cpp.platformDefines: outer.concat(["WIN32", "NOMINMAX"]) + } - Properties { - condition: qbs.targetOS.contains("windows") - cpp.defines: outer.concat(["WIN32", "NOMINMAX"]) - } - - files: [ - "../../src/ConfigParser.cpp", - "../../src/ConfigParser.h", - "../../src/DataVariantAbstract.h", - "../../src/DataVariantFormUrlencoded.cpp", - "../../src/DataVariantFormUrlencoded.h", - "../../src/DataVariantMultipartFormData.cpp", - "../../src/DataVariantMultipartFormData.h", - "../../src/DataVariantTextPlain.cpp", - "../../src/DataVariantTextPlain.h", - "../../src/Event.cpp", - "../../src/Event.h", - "../../src/FileIncoming.cpp", - "../../src/FileIncoming.h", - "../../src/GlobalMutex.cpp", - "../../src/GlobalMutex.h", - "../../src/Main.cpp", - "../../src/Main.h", - "../../src/Module.cpp", - "../../src/Module.h", - "../../src/RawData.h", - "../../src/RequestParameters.cpp", - "../../src/RequestParameters.h", - "../../src/Server.cpp", - "../../src/Server.h", - "../../src/ServerApplicationDefaultSettings.h", - "../../src/ServerApplicationSettings.h", - "../../src/ServerApplicationsTree.cpp", - "../../src/ServerApplicationsTree.h", - "../../src/ServerRequest.h", - "../../src/ServerResponse.h", - "../../src/ServerStructuresArguments.h", - "../../src/SharedMemory.cpp", - "../../src/SharedMemory.h", - "../../src/SignalHandlers.cpp", - "../../src/SignalHandlers.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/SocketList.cpp", - "../../src/SocketList.h", - "../../src/System.cpp", - "../../src/System.h", - "../../src/Utils.cpp", - "../../src/Utils.h", - ] - } + files: [ + "../../src/transfer/AppRequest.h", + "../../src/transfer/AppResponse.h", + "../../src/server/ServerControls.cpp", + "../../src/server/ServerControls.h", + "../../src/server/ServerSettings.cpp", + "../../src/server/ServerSettings.h", + "../../src/server/SocketsQueue.h", + "../../src/server/config/ConfigParser.cpp", + "../../src/server/config/ConfigParser.h", + "../../src/server/data-variant/Abstract.cpp", + "../../src/server/data-variant/Abstract.h", + "../../src/server/data-variant/FormUrlencoded.cpp", + "../../src/server/data-variant/FormUrlencoded.h", + "../../src/server/data-variant/MultipartFormData.cpp", + "../../src/server/data-variant/MultipartFormData.h", + "../../src/server/data-variant/TextPlain.cpp", + "../../src/server/data-variant/TextPlain.h", + "../../src/server/protocol/ServerHttp2Protocol.cpp", + "../../src/server/protocol/ServerHttp2Protocol.h", + "../../src/server/protocol/ServerHttp2Stream.cpp", + "../../src/server/protocol/ServerHttp2Stream.h", + "../../src/server/protocol/ServerWebSocket.cpp", + "../../src/server/protocol/ServerWebSocket.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/socket/List.cpp", + "../../src/socket/List.h", + "../../src/system/Cache.h", + "../../src/utils/Event.cpp", + "../../src/utils/Event.h", + "../../src/transfer/FileIncoming.cpp", + "../../src/transfer/FileIncoming.h", + "../../src/system/GlobalMutex.cpp", + "../../src/system/GlobalMutex.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/system/Module.cpp", + "../../src/system/Module.h", + "../../src/transfer/ProtocolVariant.h", + "../../src/server/Request.cpp", + "../../src/server/Request.h", + "../../src/server/Server.cpp", + "../../src/server/Server.h", + "../../src/server/ServerApplicationSettings.h", + "../../src/server/ServerApplicationsTree.cpp", + "../../src/server/ServerApplicationsTree.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/extensions/Sendfile.cpp", + "../../src/server/protocol/extensions/Sendfile.h", + "../../src/server/ServerStructuresArguments.h", + "../../src/system/SharedMemory.cpp", + "../../src/system/SharedMemory.h", + "../../src/SignalHandlers.cpp", + "../../src/SignalHandlers.h", + "../../src/socket/Socket.cpp", + "../../src/socket/Socket.h", + "../../src/system/System.cpp", + "../../src/system/System.h", + "../../src/utils/Utils.cpp", + "../../src/utils/Utils.h", + ] + } } diff --git a/src/DataVariantAbstract.h b/src/DataVariantAbstract.h deleted file mode 100644 index 9058696..0000000 --- a/src/DataVariantAbstract.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "SocketAdapter.h" -#include "RequestParameters.h" - -namespace HttpServer -{ - class DataVariantAbstract - { - protected: - std::string data_variant_name; - - public: - inline std::string getName() const { return data_variant_name; } - - public: - /** - * virtual destructor - */ - virtual ~DataVariantAbstract() = default; - - /** - * @param const Socket &sock - сокет, откуда можно достать остальные данные - * @param std::string &str - первая часть полученных данных - * @param const size_t leftBytes - сколько осталось данных (в байтах) получить из сокета - * @param const std::unordered_map &contentParams - дополнительные параметры, описывающие формат данных - * @param request_data &rp - данные текущего запроса (заголовки, параметры, коллекции для хранения данных) - * - * @return bool - (true|false) - удачно ли были разобраны данные - */ - virtual bool parse - ( - const SocketAdapter &sock, - std::string &str, - const size_t leftBytes, - std::unordered_map &contentParams, - struct request_parameters &rp - ) = 0; - }; -}; \ No newline at end of file diff --git a/src/DataVariantFormUrlencoded.cpp b/src/DataVariantFormUrlencoded.cpp deleted file mode 100644 index 6dc674b..0000000 --- a/src/DataVariantFormUrlencoded.cpp +++ /dev/null @@ -1,62 +0,0 @@ - -#include "DataVariantFormUrlencoded.h" - -#include "Utils.h" - -namespace HttpServer -{ - DataVariantFormUrlencoded::DataVariantFormUrlencoded() - { - data_variant_name = "application/x-www-form-urlencoded"; - } - - bool DataVariantFormUrlencoded::parse - ( - const SocketAdapter &sock, - std::string &str, - const size_t leftBytes, - std::unordered_map &contentParams, - struct request_parameters &rp - ) - { - if (str.empty() ) - { - return true; - } - - for (size_t var_pos = 0, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) - { - // Поиск следующего параметра - var_end = str.find('&', var_pos); - - // Поиск значения параметра - size_t delimiter = str.find('=', var_pos); - - if (delimiter >= var_end) - { - // Получить имя параметра - std::string var_name = Utils::urlDecode(str.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos) ); - - // Сохранить параметр с пустым значением - rp.incoming_data.emplace(std::move(var_name), ""); - } - else - { - // Получить имя параметра - std::string var_name = Utils::urlDecode(str.substr(var_pos, delimiter - var_pos) ); - - ++delimiter; - - // Получить значение параметра - std::string var_value = Utils::urlDecode(str.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos) ); - - // Сохранить параметр и значение - rp.incoming_data.emplace(std::move(var_name), std::move(var_value) ); - } - } - - str.clear(); - - return true; - } -}; \ No newline at end of file diff --git a/src/DataVariantFormUrlencoded.h b/src/DataVariantFormUrlencoded.h deleted file mode 100644 index 0c848c1..0000000 --- a/src/DataVariantFormUrlencoded.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "DataVariantAbstract.h" - -namespace HttpServer -{ - class DataVariantFormUrlencoded: public DataVariantAbstract - { - public: - DataVariantFormUrlencoded(); - - public: - virtual bool parse - ( - const SocketAdapter &sock, - std::string & str, - const size_t leftBytes, - std::unordered_map &contentParams, - struct request_parameters &rp - ) override; - }; -}; \ No newline at end of file diff --git a/src/DataVariantMultipartFormData.cpp b/src/DataVariantMultipartFormData.cpp deleted file mode 100644 index c79b309..0000000 --- a/src/DataVariantMultipartFormData.cpp +++ /dev/null @@ -1,426 +0,0 @@ - -#include "Utils.h" -#include "DataVariantMultipartFormData.h" - -#include - -namespace HttpServer -{ - DataVariantMultipartFormData::DataVariantMultipartFormData() - { - data_variant_name = "multipart/form-data"; - } - - bool DataVariantMultipartFormData::append - ( - const SocketAdapter &sock, - const std::chrono::milliseconds &timeout, - std::vector &buf, - std::string &str_buf, - const std::string &data_end, - const size_t &leftBytes, - long &recv_len, - size_t &recv_total_len - ) - { - // Завершаем работу, если уже получено байт сколько нужно - if (recv_total_len >= leftBytes) - { - return false; - } - - // Получаем данные из сокета - recv_len = sock.nonblock_recv(buf, timeout); - - // Завершаем работу, если ошибка получения данных через сокет - if (recv_len <= 0) - { - return false; - } - - // Обновляем общее количество полученных данных - recv_total_len += recv_len; - - // Добавляем полученные данные к рабочему буферу - str_buf.append(buf.cbegin(), buf.cbegin() + recv_len); - - // Завершаем работу, если в буфере меньше чем окончание блока данных - if (str_buf.length() <= data_end.length() ) - { - return false; - } - - return true; - } - - bool DataVariantMultipartFormData::parse - ( - const SocketAdapter &sock, - std::string &str, - const size_t leftBytes, - std::unordered_map &contentParams, - struct request_parameters &rp - ) - { - // Проверить есть ли в параметрах разделитель блоков данных - auto const it = contentParams.find("boundary"); - - if (contentParams.cend() == it) - { - return false; - } - - // Определить признак начала блока данных - std::string block_delimiter("--" + it->second); - // Определить признак окончания всех данных - std::string data_end("--" + it->second + "--\r\n"); - - if (0 == str.find(data_end) ) - { - return true; - } - - data_end = "\r\n" + data_end; - - // Установить размер буфера данных - const size_t buf_len = (leftBytes >= 512 * 1024) ? 512 * 1024 : leftBytes; - - // Создание буферов - std::vector buf(buf_len); - - long recv_len; // Прочитано байт при последнем извлечении данных из сокета - size_t recv_total_len = 0; // Получено байт из сокета всего - - // Поиск разделителя блока данных - // str_cur — текущая позиция в буфере - size_t str_cur = str.find(block_delimiter); - - if (std::string::npos == str_cur) - { - // Получить следующий кусок данных - if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, recv_total_len) ) - { - return false; - } - - // Поиск разделителя блока данных - str_cur = str.find(block_delimiter); - - if (std::string::npos == str_cur) - { - return false; - } - } - - str_cur += block_delimiter.length() + 2; - - block_delimiter = "\r\n" + block_delimiter; - - // Если найден конец данных - bool is_find_data_end = false; - - do - { - // Правильно ли был передан блок данных - bool is_block_valid = true; - - // Поиск конца заголовков блока данных - size_t headers_end = str.find("\r\n\r\n", str_cur); - - // Если конец не был найден, то - if (std::string::npos == headers_end) - { - // Получить следующий кусок данных - if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, recv_total_len) ) - { - return false; - } - - // Провести повторный поиск - headers_end = str.find("\r\n\r\n", str_cur); - - // Если снова не найдено, то данные некорректны - if (std::string::npos == headers_end) - { - is_block_valid = false; - } - } - - if (is_block_valid) - { - // Разобрать заголовки блока данных - std::unordered_map headers; - - for (size_t line_end = str.find("\r\n", str_cur); str_cur < headers_end; line_end = str.find("\r\n", str_cur) ) - { - size_t delimiter = str.find(':', str_cur); - - if (std::string::npos == delimiter || delimiter > line_end) - { - std::string header_name = str.substr(str_cur, line_end - str_cur); - Utils::trim(header_name); - headers.emplace(std::move(header_name), ""); - } - else - { - std::string header_name = str.substr(str_cur, delimiter - str_cur); - Utils::trim(header_name); - - ++delimiter; - - std::string header_value = str.substr(delimiter, line_end - delimiter); - Utils::trim(header_value); - - headers.emplace(std::move(header_name), std::move(header_value) ); - } - - // Перейти к следующему заголовку - str_cur = line_end + 2; - } - - // Перейти к данным - str_cur += 2; - - // Определить источник блока данных - auto it = headers.find("Content-Disposition"); - - // Если заголовок определён - if (headers.cend() != it) - { - // Разобрать значение заголовка данных на параметры - std::unordered_map header_params; - - const std::string &header_value = it->second; - - size_t delimiter = header_value.find(';'); - - std::string content_disposition(header_value.substr(0, delimiter) ); - Utils::trim(content_disposition); - - // Проверить соответствие указанного формата - if ("form-data" == content_disposition && std::string::npos != delimiter) - { - // Получить параметры блока данных - for (size_t str_param_cur = delimiter + 1, str_param_end; std::string::npos != str_param_cur; str_param_cur = str_param_end) - { - str_param_end = header_value.find(';', str_param_cur); - delimiter = header_value.find('=', str_param_cur); - - if (std::string::npos == delimiter || delimiter > str_param_end) - { - std::string param_name = (std::string::npos == str_param_end) ? header_value.substr(str_param_cur) : header_value.substr(str_param_cur, str_param_end - str_param_cur); - Utils::trim(param_name); - header_params.emplace(std::move(param_name), ""); - } - else - { - std::string param_name = header_value.substr(str_param_cur, delimiter - str_param_cur); - Utils::trim(param_name); - - ++delimiter; - - delimiter = header_value.find('"', delimiter); - - if (std::string::npos == delimiter) - { - str_param_end = header_value.find(';', str_param_cur); - - std::string param_value = (std::string::npos == str_param_end) ? header_value.substr(delimiter) : header_value.substr(delimiter, str_param_end - delimiter); - Utils::trim(param_value); - - header_params.emplace(std::move(param_name), std::move(param_value) ); - } - else - { - ++delimiter; - - str_param_cur = header_value.find('"', delimiter); - str_param_end = header_value.find(';', str_param_cur); - - std::string param_value = (std::string::npos == str_param_cur) ? header_value.substr(delimiter) : header_value.substr(delimiter, str_param_cur - delimiter); - - header_params.emplace(std::move(param_name), std::move(param_value) ); - } - } - - if (std::string::npos != str_param_end) - { - ++str_param_end; - } - } - - // Поиск имени блока данных - auto const it_name = header_params.find("name"); - - if (header_params.cend() != it_name) - { - // Если данные пришли из файла - auto const it_filename = header_params.find("filename"); - - if (header_params.cend() != it_filename) - { - // Найти тип файла - auto const it_filetype = headers.find("Content-Type"); - - if (headers.cend() != it_filetype) - { - // Сгенерировать уникальное имя - std::string tmp_name = System::getTempDir() + Utils::getUniqueName(); - - // Создать файл - std::ofstream file(tmp_name, std::ofstream::trunc | std::ofstream::binary); - - // Если файл был создан и готов для работы - if (file.is_open() ) - { - // Смещение данных в буфере в начало - // str.assign(str.cbegin() + str_cur, str.cend() ); - str.erase(str.begin(), str.begin() + str_cur); - - // Поиск конца блока данных - size_t delimiter = str.find(block_delimiter); - - // Пока конец блока данных не найден - while (std::string::npos == delimiter) - { - // Добавить данные к значению - file.write(str.data(), str.length() - data_end.length() ); - - // str.assign(str.cend() - data_end.length(), str.cend() ); - str.erase(str.begin(), str.end() - data_end.length() ); - - // Получить следующий кусок данных - if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, recv_total_len) ) - { - return false; - } - - // Поиск конца блока данных - delimiter = str.find(block_delimiter); - } - - // Добавить последнюю часть данных к значению - file.write(str.data(), delimiter); - - // Добавить данные в список - rp.incoming_files.emplace(it_name->second, FileIncoming(std::move(tmp_name), it_filetype->second, file.tellp() ) ); - - file.close(); - - // Если найден конец данных - if (str.find(data_end, delimiter) == delimiter) - { - is_find_data_end = true; - } - - str_cur = delimiter + block_delimiter.length() + 2; - } - else // Файл не смог быть открыт/создан - { - is_block_valid = false; - } - } - else // Тип файла не определён - { - is_block_valid = false; - } - } - else // Если данные пришли из формы - { - std::string value; - - // Смещение данных в буфере в начало - // str.assign(str.cbegin() + str_cur, str.cend() ); - str.erase(str.begin(), str.begin() + str_cur); - - // Поиск конца блока данных - size_t delimiter = str.find(block_delimiter); - - // Пока конец блока данных не найден - while (std::string::npos == delimiter) - { - // Добавить данные к значению - value.append(str.cbegin(), str.cend() - data_end.length() ); - - // str.assign(str.cend() - data_end.length(), str.cend() ); - str.erase(str.begin(), str.end() - data_end.length() ); - - // Получить следующий кусок данных - if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, recv_total_len) ) - { - return false; - } - - // Поиск конца блока данных - delimiter = str.find(block_delimiter); - } - - // Добавить последнюю часть данных к значению - value.append(str.cbegin(), str.cbegin() + delimiter); - - // Добавить данные в список - rp.incoming_data.emplace(it_name->second, std::move(value) ); - - // Если найден конец данных - if (str.find(data_end, delimiter) == delimiter) - { - is_find_data_end = true; - } - - str_cur = delimiter + block_delimiter.length() + 2; - } - } - else // Имя блока данных не определено - { - is_block_valid = false; - } - } - else // Формат не соответствует - { - is_block_valid = false; - } - } - else // Если источник не определён - { - is_block_valid = false; - } - } - - // Если данные некорректны - if (false == is_block_valid) - { - // то блок данных пропускаем (ищем следующий блок) - str_cur = str.find(block_delimiter, str_cur); - - while (std::string::npos == str_cur) - { - // str.assign(str.cend() - data_end.length(), str.cend() ); - str.erase(str.begin(), str.end() - data_end.length() ); - - // Получить следующий кусок данных - if (false == append(sock, rp.timeout, buf, str, data_end, leftBytes, recv_len, recv_total_len) ) - { - return false; - } - - str_cur = str.find(block_delimiter); - } - - // Если найден конец данных - if (str.find(data_end, str_cur) == str_cur) - { - is_find_data_end = true; - } - - str_cur += block_delimiter.length() + 2; - } - - str.erase(str.begin(), str.begin() + str_cur); - - str_cur = 0; - } - while (false == is_find_data_end); - - return true; - } -}; \ No newline at end of file diff --git a/src/DataVariantMultipartFormData.h b/src/DataVariantMultipartFormData.h deleted file mode 100644 index 0a72b68..0000000 --- a/src/DataVariantMultipartFormData.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "DataVariantAbstract.h" - -namespace HttpServer -{ - class DataVariantMultipartFormData: public DataVariantAbstract - { - public: - DataVariantMultipartFormData(); - - protected: - static bool append - ( - const SocketAdapter &sock, - const std::chrono::milliseconds &timeout, - std::vector &buf, - std::string &str_buf, - const std::string &data_end, - const size_t &leftBytes, - long &recv_len, - size_t &recv_total_len - ); - - public: - virtual bool parse - ( - const SocketAdapter &sock, - std::string &str, - const size_t leftBytes, - std::unordered_map &contentParams, - struct request_parameters &rp - ) override; - }; -}; \ No newline at end of file diff --git a/src/DataVariantTextPlain.cpp b/src/DataVariantTextPlain.cpp deleted file mode 100644 index 2d5a6b1..0000000 --- a/src/DataVariantTextPlain.cpp +++ /dev/null @@ -1,60 +0,0 @@ - -#include "DataVariantTextPlain.h" - -namespace HttpServer -{ - DataVariantTextPlain::DataVariantTextPlain() - { - data_variant_name = "text/plain"; - } - - bool DataVariantTextPlain::parse - ( - const SocketAdapter &sock, - std::string &str, - const size_t leftBytes, - std::unordered_map &contentParams, - struct request_parameters &rp - ) - { - if (str.empty() ) - { - return true; - } - - for (size_t var_pos = 0, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) - { - // Поиск следующего параметра - var_end = str.find('&', var_pos); - - // Поиск значения параметра - size_t delimiter = str.find('=', var_pos); - - if (delimiter >= var_end) - { - // Получить имя параметра - std::string var_name = str.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos); - - // Сохранить параметр с пустым значением - rp.incoming_data.emplace(std::move(var_name), ""); - } - else - { - // Получить имя параметра - std::string var_name = str.substr(var_pos, delimiter - var_pos); - - ++delimiter; - - // Получить значение параметра - std::string var_value = str.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos); - - // Сохранить параметр и значение - rp.incoming_data.emplace(std::move(var_name), std::move(var_value) ); - } - } - - str.clear(); - - return true; - } -}; \ No newline at end of file diff --git a/src/DataVariantTextPlain.h b/src/DataVariantTextPlain.h deleted file mode 100644 index d3fb2ac..0000000 --- a/src/DataVariantTextPlain.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "DataVariantAbstract.h" - -namespace HttpServer -{ - class DataVariantTextPlain: public DataVariantAbstract - { - public: - DataVariantTextPlain(); - - public: - virtual bool parse - ( - const SocketAdapter &sock, - std::string &str, - const size_t leftBytes, - std::unordered_map &contentParams, - struct request_parameters &rp - ) override; - }; -}; \ No newline at end of file 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/Main.cpp b/src/Main.cpp index c7739e1..d3d341d 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,6 +1,6 @@ #include "Main.h" -#include "Server.h" +#include "server/Server.h" #include "SignalHandlers.h" #include @@ -47,4 +47,4 @@ int main(const int argc, const char *argv[]) } return exitcode; -} \ No newline at end of file +} 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/RequestParameters.cpp b/src/RequestParameters.cpp deleted file mode 100644 index d3e1c39..0000000 --- a/src/RequestParameters.cpp +++ /dev/null @@ -1,21 +0,0 @@ - -#include "RequestParameters.h" - -namespace HttpServer -{ - void request_parameters::clear() - { - incoming_headers.clear(); - incoming_params.clear(); - incoming_data.clear(); - incoming_files.clear(); - - outgoing_headers.clear(); - - method.clear(); - version.clear(); - uri_reference.clear(); - - timeout = std::chrono::milliseconds::zero(); - } -}; \ No newline at end of file diff --git a/src/RequestParameters.h b/src/RequestParameters.h deleted file mode 100644 index 0d3e209..0000000 --- a/src/RequestParameters.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "FileIncoming.h" - -#include -#include - -namespace HttpServer -{ - struct request_parameters - { - std::unordered_map incoming_headers; - std::unordered_multimap incoming_params; - std::unordered_multimap incoming_data; - std::unordered_multimap incoming_files; - - std::unordered_map outgoing_headers; - - std::string method; - std::string version; - std::string uri_reference; - - std::chrono::milliseconds timeout; - - size_t keep_alive_count; - int connection_params; - int app_exit_code; - - void clear(); - }; -}; \ No newline at end of file diff --git a/src/Server.cpp b/src/Server.cpp deleted file mode 100644 index 6c53dea..0000000 --- a/src/Server.cpp +++ /dev/null @@ -1,2036 +0,0 @@ - -#include "Server.h" -#include "Utils.h" -#include "System.h" - -#include "DataVariantFormUrlencoded.h" -#include "DataVariantMultipartFormData.h" -#include "DataVariantTextPlain.h" -#include "FileIncoming.h" -#include "ServerRequest.h" -#include "ServerResponse.h" -#include "ConfigParser.h" -#include "SocketAdapterDefault.h" -#include "SocketAdapterTls.h" -#include "GlobalMutex.h" -#include "SharedMemory.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace HttpServer -{ - std::string Server::getMimeTypeByFileName(const std::string &fileName) const - { - const size_t ext_pos = fileName.rfind('.'); - std::string file_ext = std::string::npos != ext_pos ? fileName.substr(ext_pos + 1) : ""; - - const std::locale loc; - Utils::toLower(file_ext, loc); - - auto const it_mime = this->mimes_types.find(file_ext); - - return this->mimes_types.cend() != it_mime ? it_mime->second : "application/octet-stream"; - } - - std::vector > Server::getRanges( - const std::string &rangeHeader, - const size_t posSymEqual, - const size_t fileSize, - std::string &resultRangeHeader, - size_t &contentLength - ) const - { - std::vector > ranges; - - contentLength = 0; - - size_t delimiter = posSymEqual; // rangeHeader.find('='); - - const std::string range_unit_name(rangeHeader.cbegin(), rangeHeader.cbegin() + delimiter); - - static const std::unordered_map ranges_units { - {"bytes", 1} - }; - - auto const it_unit = ranges_units.find(range_unit_name); - - if (ranges_units.cend() == it_unit) - { - return ranges; - } - - const size_t range_unit = it_unit->second; - - for (size_t str_pos; std::string::npos != delimiter; ) - { - str_pos = delimiter + 1; - - delimiter = rangeHeader.find(',', str_pos); - - const size_t range_pos = rangeHeader.find('-', str_pos); - - if (range_pos < delimiter) - { - const std::string range_begin_str(rangeHeader.cbegin() + str_pos, rangeHeader.cbegin() + range_pos); - const std::string range_end_str(rangeHeader.cbegin() + range_pos + 1, std::string::npos == delimiter ? rangeHeader.cend() : rangeHeader.cbegin() + delimiter); - - if (false == range_begin_str.empty() ) - { - const size_t range_begin = std::strtoull(range_begin_str.c_str(), nullptr, 10) * range_unit; - - if (range_begin < fileSize) - { - if (false == range_end_str.empty() ) - { - size_t range_end = std::strtoull(range_end_str.c_str(), nullptr, 10) * range_unit; - - if (range_end >= range_begin) - { - if (range_end > fileSize) - { - range_end = fileSize; - } - - const size_t length = range_end - range_begin + 1; - - contentLength += length; - - resultRangeHeader += std::to_string(range_begin) + '-' + std::to_string(range_end) + ','; - - ranges.emplace_back(std::tuple {range_begin, length}); - } - } - else // if range_end_str empty - { - const size_t length = fileSize - range_begin; - - contentLength += length; - - resultRangeHeader += std::to_string(range_begin) + '-' + std::to_string(fileSize - 1) + ','; - - ranges.emplace_back(std::tuple {range_begin, length}); - } - } - } - else if (false == range_end_str.empty() ) // if range_begin_str empty - { - size_t range_end = std::strtoull(range_end_str.c_str(), nullptr, 10) * range_unit; - - const size_t length = range_end < fileSize ? fileSize - range_end : fileSize; - - const size_t range_begin = fileSize - length; - - range_end = fileSize - range_begin - 1; - - contentLength += length; - - resultRangeHeader += std::to_string(range_begin) + '-' + std::to_string(range_end) + ','; - - ranges.emplace_back(std::tuple {range_begin, length}); - } - } - } - - if (false == ranges.empty() ) - { - resultRangeHeader.back() = '/'; - - resultRangeHeader = "bytes " + resultRangeHeader + std::to_string(fileSize); - } - - return ranges; - } - - int Server::transferFilePart - ( - const SocketAdapter &clientSocket, - const std::chrono::milliseconds &timeout, - const std::string &fileName, - const time_t fileTime, - const size_t fileSize, - const std::string &rangeHeader, - const std::string &connectionHeader, - const std::string &dateHeader, - const bool headersOnly - ) const - { - const size_t pos_sym_equal = rangeHeader.find('='); - - if (std::string::npos == pos_sym_equal) - { - // HTTP 400 - std::string headers("HTTP/1.1 400 Bad Request\r\n"); - headers += connectionHeader + dateHeader + "\r\n"; - - clientSocket.nonblock_send(headers, timeout); - - return 0; - } - - std::string content_range_header; - - size_t content_length; - - const std::vector > ranges = this->getRanges(rangeHeader, pos_sym_equal, fileSize, content_range_header, content_length); - - if (0 == content_length) - { - // HTTP 416 - std::string headers("HTTP/1.1 416 Requested Range Not Satisfiable\r\n"); - headers += connectionHeader + dateHeader + "\r\n"; - - clientSocket.nonblock_send(headers, timeout); - - return 0; - } - - // Ranges transfer - std::ifstream file(fileName, std::ifstream::binary); - - if ( ! file) - { - file.close(); - - // HTTP 500 - std::string headers("HTTP/1.1 500 Internal Server Error\r\n"); - headers += connectionHeader + dateHeader + "\r\n"; - - clientSocket.nonblock_send(headers, timeout); - - return 0; - } - - const std::string file_mime_type = this->getMimeTypeByFileName(fileName); - - std::string headers("HTTP/1.1 206 Partial Content\r\n"); - headers += "Content-Type: " + file_mime_type + "\r\n" - + "Content-Length: " + std::to_string(content_length) + "\r\n" - + "Accept-Ranges: bytes\r\n" - + "Content-Range: " + content_range_header + "\r\n" - + "Last-Modified: " + Utils::getDatetimeAsString(fileTime, true) + "\r\n" - + connectionHeader + dateHeader + "\r\n"; - - // Отправить заголовки - if (clientSocket.nonblock_send(headers, timeout) < 0) - { - file.close(); - - return 0; - } - - if (false == headersOnly) - { - size_t position, length; - - for (auto const &range : ranges) - { - std::tie(position, length) = range; - - std::vector buf(length < 512 * 1024 ? length : 512 * 1024); - - file.seekg(position, file.beg); - - size_t send_size_left = length; - - long send_size; - - do - { - if (send_size_left < 512 * 1024) - { - buf.resize(send_size_left); - } - - file.read(buf.data(), buf.size() ); - send_size = clientSocket.nonblock_send(buf, file.gcount(), timeout); - - send_size_left -= send_size; - } - while (false == file.eof() && false == file.fail() && send_size > 0 && send_size_left); - } - } - - file.close(); - - return 1; - } - - /** - * Передача файла (или его части) - */ - int Server::transferFile - ( - const SocketAdapter &clientSocket, - const std::string &fileName, - const std::string &connectionHeader, - const bool headersOnly, - struct request_parameters &rp - ) const - { - // Get current time in GMT - const std::string date_header = "Date: " + Utils::getDatetimeAsString() + "\r\n"; - - time_t file_time; - size_t file_size; - - // Получить размер файла и дату последнего изменения - if (false == System::getFileSizeAndTimeGmt(fileName, &file_size, &file_time) ) - { - // HTTP 404 - std::string headers("HTTP/1.1 404 Not Found\r\n"); - headers += connectionHeader + date_header + "\r\n"; - - clientSocket.nonblock_send(headers, rp.timeout); - - return 0; - } - - // Check for If-Modified header - auto const it_modified = rp.incoming_headers.find("If-Modified-Since"); - - // Если найден заголовок проверки изменения файла (проверить, изменялся ли файл) - if (rp.incoming_headers.cend() != it_modified) - { - const time_t time_in_request = Utils::stringTimeToTimestamp(it_modified->second); - - if (file_time == time_in_request) - { - // HTTP 304 - std::string headers("HTTP/1.1 304 Not Modified\r\n"); - headers += connectionHeader + date_header + "\r\n"; - - clientSocket.nonblock_send(headers, rp.timeout); - - return 0; - } - } - - auto const it_range = rp.incoming_headers.find("Range"); - - // Range transfer - if (rp.incoming_headers.cend() != it_range) - { - return this->transferFilePart(clientSocket, rp.timeout, fileName, file_time, file_size, it_range->second, connectionHeader, date_header, headersOnly); - } - - // File transfer - std::ifstream file(fileName, std::ifstream::binary); - - if ( ! file) - { - file.close(); - - // HTTP 500 - std::string headers("HTTP/1.1 500 Internal Server Error\r\n"); - headers += connectionHeader + date_header + "\r\n"; - - clientSocket.nonblock_send(headers, rp.timeout); - - return 0; - } - - const std::string file_mime_type = this->getMimeTypeByFileName(fileName); - - std::string headers("HTTP/1.1 200 OK\r\n"); - headers += "Content-Type: " + file_mime_type + "\r\n" - + "Content-Length: " + std::to_string(file_size) + "\r\n" - + "Accept-Ranges: bytes\r\n" - + "Last-Modified: " + Utils::getDatetimeAsString(file_time, true) + "\r\n" - + connectionHeader + date_header + "\r\n"; - - // Отправить заголовки - if (clientSocket.nonblock_send(headers, rp.timeout) < 0) - { - file.close(); - - return 0; - } - - // Отправить файл - if (false == headersOnly && file_size) - { - std::vector buf(file_size < 512 * 1024 ? file_size : 512 * 1024); - - long send_size; - - do - { - file.read(reinterpret_cast(buf.data() ), buf.size() ); - send_size = clientSocket.nonblock_send(buf, file.gcount(), rp.timeout); - } - while (false == file.eof() && false == file.fail() && send_size > 0); - } - - file.close(); - - return 1; - } - - /** - * Парсинг переданных параметров (URI) - */ - bool Server::parseIncomingVars(std::unordered_multimap ¶ms, const std::string &uriParams) - { - if (uriParams.length() ) - { - for (size_t var_pos = 0, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) - { - // Поиск следующего параметра - var_end = uriParams.find('&', var_pos); - - // Поиск значения параметра - size_t delimiter = uriParams.find('=', var_pos); - - if (delimiter >= var_end) - { - // Получить имя параметра - std::string var_name = Utils::urlDecode(uriParams.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos) ); - - // Сохранить параметр с пустым значением - params.emplace(std::move(var_name), ""); - } - else - { - // Получить имя параметра - std::string var_name = Utils::urlDecode(uriParams.substr(var_pos, delimiter - var_pos) ); - - ++delimiter; - - // Получить значение параметра - std::string var_value = Utils::urlDecode(uriParams.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos) ); - - // Сохранить параметр и значение - params.emplace(std::move(var_name), std::move(var_value) ); - } - } - - return true; - } - - return false; - } - - void Server::sendStatus(const SocketAdapter &clientSocket, const std::chrono::milliseconds &timeout, const size_t statusCode) - { - static const std::unordered_map statuses { - {400, "Bad Request"}, - {404, "Not Found"}, - {413, "Request Entity Too Large"} - }; - - auto const it = statuses.find(statusCode); - - if (statuses.cend() != it) - { - const std::string &status = it->second; - - std::string headers("HTTP/1.1 " + std::to_string(statusCode) + ' ' + status + "\r\n\r\n"); - - clientSocket.nonblock_send(headers, timeout); - } - } - - /** - * Метод для обработки запроса - */ - int Server::threadRequestProc(SocketAdapter &clientSocket, const struct sockaddr_in &clientAddr) const - { - struct request_parameters rp; - - rp.keep_alive_count = 100; - - const size_t buf_len = 4096; - std::vector buf(buf_len); - - std::string str_buf; - - do - { - rp.app_exit_code = EXIT_FAILURE; - - // Подготовить параметры для получения данных - rp.timeout = std::chrono::milliseconds(5000); - - if (false == getRequest(clientSocket, buf, str_buf, rp) ) - { - break; - } - - if (int error_code = getRequestHeaders(str_buf, rp) ) - { - this->sendStatus(clientSocket, rp.timeout, error_code); - - break; - } - - const ServerApplicationSettings *app_sets = getApplicationSettings(rp); - - // Если приложение не найдено - if (nullptr == app_sets) - { - // HTTP 404 Not Found - this->sendStatus(clientSocket, rp.timeout, 404); - - break; - } - - if (int error_code = getRequestData(clientSocket, str_buf, *app_sets, rp) ) - { - this->sendStatus(clientSocket, rp.timeout, error_code); - - break; - } - - runApplication(clientSocket, *app_sets, rp); - - for (auto const &it : rp.incoming_files) - { - remove(it.second.getName().c_str() ); - } - - if (EXIT_SUCCESS == rp.app_exit_code) - { - this->getConnectionParams(rp); - - this->xSendfile(clientSocket, rp); - } - else - { - rp.connection_params = CONNECTION_CLOSED; - } - - rp.clear(); - } - while (isConnectionKeepAlive(rp) ); - - if (false == isConnectionUpgrade(rp) ) - { - clientSocket.close(); - } - - return rp.app_exit_code; - } - - bool Server::getRequest(const SocketAdapter &clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp) - { - // Получить данные запроса от клиента - const long recv_size = clientSocket.nonblock_recv(buf, rp.timeout); - - if (recv_size < 0 && str_buf.empty() ) - { - return false; - } - - if (recv_size > 0) // Если данные были получены - { - str_buf.append(buf.cbegin(), buf.cbegin() + recv_size); - } - - return true; - } - - int Server::getRequestHeaders(std::string &str_buf, struct request_parameters &rp) const - { - // Если запрос пустой - if (str_buf.empty() ) - { - // HTTP 400 Bad Request - return 400; - } - - // Поиск конца заголовков (пустая строка) - size_t headers_end = str_buf.find("\r\n\r\n"); - - // Если найден конец заголовков - if (std::string::npos == headers_end) - { - // HTTP 400 Bad Request - return 400; - } - - headers_end += 2; - - size_t str_cur = 0; - // Поиск конца первого заголовка - size_t str_end = str_buf.find("\r\n"); - - // Если не найден конец заголовка - if (std::string::npos == str_end) - { - // HTTP 400 Bad Request - return 400; - } - - // Установка конца строки (для поиска) - str_buf[str_end] = '\0'; - - // Разделить метод запроса и параметры запроса - size_t delimiter = str_buf.find(' ', str_cur); - - // Получить метод запроса (GET, POST, PUT, DELETE, ...) - rp.method = str_buf.substr(str_cur, delimiter - str_cur); - // Сохранить метод и параметры запроса - rp.incoming_headers[rp.method] = str_buf.substr(delimiter + 1, str_end - delimiter - 1); - - delimiter += 1; - // Найти окончание URI - size_t uri_end = str_buf.find(' ', delimiter); - - // Если окончание не найдено - if (std::string::npos == uri_end) - { - uri_end = str_end; - // то версия протокола HTTP - 0.9 - rp.version = "0.9"; - } - else // Если окончание найдено - { - str_buf[uri_end] = '\0'; - const size_t ver_beg = uri_end + 6; // Пропустить "HTTP/" - - if (ver_beg < str_end) - { - // Получить версию протокола HTTP - rp.version = str_buf.substr(ver_beg, str_end - ver_beg); - } - } - - // Поиск именованных параметров запросов (переменных ?) - const size_t params_pos = str_buf.find('?', delimiter); - - // Сохранить полную ссылку URI (без параметров) - rp.uri_reference = (std::string::npos == params_pos) ? str_buf.substr(delimiter) : str_buf.substr(delimiter, params_pos - delimiter); - - if (std::string::npos != params_pos) - { - // Извлекаем параметры запроса из URI - if (false == parseIncomingVars(rp.incoming_params, str_buf.substr(params_pos + 1, uri_end) ) ) - { - // HTTP 400 Bad Request - return 400; - } - } - - // Переход к обработке следующего заголовка - str_cur = str_end + 2; - // Поиск конца заголовка - str_end = str_buf.find("\r\n", str_cur); - // Установка конца заголовка - str_buf[str_end] = '\0'; - - // Цикл извлечения заголовков запроса - for (; str_cur != headers_end; str_end = str_buf.find("\r\n", str_cur), str_buf[str_end] = '\0') - { - // Поиск разделителя названия заголовка и его значения - delimiter = str_buf.find(':', str_cur); - - // Если разделитель найден в текущей строке - if (delimiter < str_end) - { - std::string header_name = str_buf.substr(str_cur, delimiter - str_cur); - std::string header_value = str_buf.substr(delimiter + 1, str_end - delimiter - 1); - - // Удалить лишние пробелы в начале и в конце строки - Utils::trim(header_value); - - // Сохранить заголовок и его значение - rp.incoming_headers.emplace(std::move(header_name), std::move(header_value) ); - } - - // Перейти к следующей строке - str_cur = str_end + 2; - } - - str_buf.erase(str_buf.begin(), str_buf.begin() + headers_end + 2); - - return 0; - } - - void Server::runApplication(const SocketAdapter &clientSocket, const ServerApplicationSettings &appSets, struct request_parameters &rp) - { - Utils::raw_pair *raw_pair_params = nullptr; - Utils::raw_pair *raw_pair_headers = nullptr; - Utils::raw_pair *raw_pair_data = nullptr; - Utils::raw_fileinfo *raw_fileinfo_files = nullptr; - - Utils::stlToRawPairs(&raw_pair_params, rp.incoming_params); - Utils::stlToRawPairs(&raw_pair_headers, rp.incoming_headers); - Utils::stlToRawPairs(&raw_pair_data, rp.incoming_data); - Utils::filesIncomingToRawFilesInfo(&raw_fileinfo_files, rp.incoming_files); - - server_request request { - clientSocket.get_handle(), - clientSocket.get_tls_session(), - rp.method.c_str(), - rp.uri_reference.c_str(), - appSets.root_dir.c_str(), - rp.incoming_params.size(), - raw_pair_params, - rp.incoming_headers.size(), - raw_pair_headers, - rp.incoming_data.size(), - raw_pair_data, - rp.incoming_files.size(), - raw_fileinfo_files - }; - - server_response response { - clientSocket.get_handle(), 0, nullptr - }; - - try - { - // Launch application - rp.app_exit_code = appSets.application_call(&request, &response); - } - catch (...) - { - rp.app_exit_code = EXIT_FAILURE; - } - - if (EXIT_SUCCESS == rp.app_exit_code) - { - Utils::rawPairsToStl(rp.outgoing_headers, response.headers, response.headers_count); - } - - // Очистить заголовки сформированные приложением - try - { - appSets.application_clear(response.headers, response.headers_count); - } - catch (...) {} - - Utils::destroyRawPairs(raw_pair_params, rp.incoming_params.size() ); - Utils::destroyRawPairs(raw_pair_headers, rp.incoming_headers.size() ); - Utils::destroyRawPairs(raw_pair_data, rp.incoming_data.size() ); - Utils::destroyRawFilesInfo(raw_fileinfo_files, rp.incoming_files.size() ); - } - - int Server::getRequestData(const SocketAdapter &clientSocket, std::string &str_buf, const ServerApplicationSettings &appSets, struct request_parameters &rp) const - { - // Определить вариант данных запроса (заодно проверить, есть ли данные) - auto const it = rp.incoming_headers.find("Content-Type"); - - if (rp.incoming_headers.cend() == it) - { - return 0; - } - - // Параметры - std::unordered_map content_params; - - // Получить значение заголовка - const std::string &header_value = it->second; - - // Определить, содержит ли тип данных запроса дополнительные параметры - size_t delimiter = header_value.find(';'); - - std::string data_variant_name; // Название варианта данных запроса - - // Если есть дополнительные параметры - извлекаем их - if (std::string::npos != delimiter) - { - data_variant_name = header_value.substr(0, delimiter); - Utils::trim(data_variant_name); - - for (size_t str_param_cur = delimiter + 1, str_param_end = 0; std::string::npos != str_param_end; str_param_cur = str_param_end + 1) - { - str_param_end = header_value.find(';', str_param_cur); - delimiter = header_value.find('=', str_param_cur); - - if (delimiter >= str_param_end) - { - std::string param_name = header_value.substr(str_param_cur, std::string::npos != str_param_end ? str_param_end - str_param_cur : std::string::npos); - Utils::trim(param_name); - content_params.emplace(std::move(param_name), ""); - } - else - { - std::string param_name = header_value.substr(str_param_cur, delimiter - str_param_cur); - Utils::trim(param_name); - - ++delimiter; - - std::string param_value = header_value.substr(delimiter, std::string::npos != str_param_end ? str_param_end - delimiter : std::string::npos); - Utils::trim(param_value); - - content_params.emplace(std::move(param_name), std::move(param_value) ); - } - } - } - else - { - data_variant_name = header_value; - } - - // Поиск варианта данных по имени типа - auto variant = this->variants.find(data_variant_name); - - // Если сервер не поддерживает формат полученных данных - if (this->variants.cend() == variant) - { - // HTTP 400 Bad Request - return 400; - } - - DataVariantAbstract *data_variant = variant->second; - - // Получить длину запроса в байтах - size_t data_length = 0; - - auto const it_len = rp.incoming_headers.find("Content-Length"); - - if (rp.incoming_headers.cend() != it_len) - { - data_length = std::strtoull(it_len->second.c_str(), nullptr, 10); - } - - // Если размер запроса превышает лимит (если лимит был установлен) - if (data_length > appSets.request_max_size && 0 != appSets.request_max_size) - { - // HTTP 413 Request Entity Too Large - return 413; - } - - // Сколько осталось получить данных - size_t left_bytes = 0; - - std::string data_buf; - - if (data_length >= str_buf.length() ) - { - left_bytes = data_length - str_buf.length(); - - data_buf.swap(str_buf); - } - else - { - data_buf.assign(str_buf.cbegin(), str_buf.cbegin() + data_length); - str_buf.erase(str_buf.begin(), str_buf.begin() + data_length); - } - - // Разобрать данные на составляющие - if (false == data_variant->parse(clientSocket, data_buf, left_bytes, content_params, rp) ) - { - for (auto const &it : rp.incoming_files) - { - remove(it.second.getName().c_str() ); - } - - // HTTP 400 Bad Request - return 400; - } - - if (false == data_buf.empty() ) - { - str_buf.swap(data_buf); - } - - return 0; - } - - const ServerApplicationSettings *Server::getApplicationSettings(const struct request_parameters &rp) const - { - // Получить доменное имя (или адрес) назначения запроса - auto const it_host = rp.incoming_headers.find("Host"); - - // Если имя задано - продолжить обработку запроса - if (rp.incoming_headers.cend() != it_host) - { - const std::string &host_header = it_host->second; - - // Поиск разделителя, за которым помещается номер порта, если указан - const size_t delimiter = host_header.find(':'); - - // Получить имя (или адрес) - const std::string host = host_header.substr(0, delimiter); - - // Получить номер порта - const int port = (std::string::npos != delimiter) ? std::strtol(host_header.substr(delimiter + 1).c_str(), nullptr, 10) : 80; - - // Поиск настроек приложения по имени - const ServerApplicationSettings *app_sets = this->apps_tree.find(host); - - // Если приложение найдено - if (app_sets && (app_sets->ports.cend() != app_sets->ports.find(port) || app_sets->tls_ports.cend() != app_sets->tls_ports.find(port) ) ) - { - return app_sets; - } - } - - return nullptr; - } - - void Server::xSendfile(const SocketAdapter &clientSocket, struct request_parameters &rp) const - { - auto const it_x_sendfile = rp.outgoing_headers.find("X-Sendfile"); - - if (rp.outgoing_headers.cend() != it_x_sendfile) - { - const std::string connection_header = isConnectionKeepAlive(rp) ? "Connection: Keep-Alive\r\nKeep-Alive: timeout=5; max=" + std::to_string(rp.keep_alive_count) + "\r\n" : "Connection: Close\r\n"; - - const bool headers_only = ("head" == rp.method); - - this->transferFile(clientSocket, it_x_sendfile->second, connection_header, headers_only, rp); - } - } - - void Server::getConnectionParams(struct request_parameters &rp) - { - rp.connection_params = CONNECTION_CLOSED; - - auto const it_in_connection = rp.incoming_headers.find("Connection"); - auto const it_out_connection = rp.outgoing_headers.find("Connection"); - - if (rp.incoming_headers.cend() != it_in_connection && rp.outgoing_headers.cend() != it_out_connection) - { - const std::locale loc; - - std::string connection_in = it_in_connection->second; - Utils::toLower(connection_in, loc); - - std::string connection_out = it_out_connection->second; - Utils::toLower(connection_out, loc); - - auto const incoming_params = Utils::explode(connection_in, ','); - - auto const it = std::find(incoming_params.cbegin(), incoming_params.cend(), connection_out); - - if (incoming_params.cend() != it) - { - const std::string &inc = *it; - - if ("keep-alive" == inc) - { - --rp.keep_alive_count; - - if (0 < rp.keep_alive_count) - { - rp.connection_params |= CONNECTION_KEEP_ALIVE; - } - } - else if ("upgrade" == inc) - { - rp.connection_params |= CONNECTION_UPGRADE; - } - } - } - } - - bool Server::isConnectionKeepAlive(const struct request_parameters &rp) - { - return (rp.connection_params & CONNECTION_KEEP_ALIVE) == CONNECTION_KEEP_ALIVE; - } - - bool Server::isConnectionUpgrade(const struct request_parameters &rp) - { - return (rp.connection_params & CONNECTION_UPGRADE) == CONNECTION_UPGRADE; - } - - /** - * Метод для обработки запросов (запускается в отдельном потоке) - * извлекает сокет клиенты из очереди и передаёт его на обслуживание - */ - void Server::threadRequestCycle(std::queue > &sockets, Event &eventThreadCycle) const - { - while (true) - { - Socket sock; - struct sockaddr_in addr; - - eventThreadCycle.wait(); - - if (false == this->process_flag) - { - break; - } - - this->sockets_queue_mtx.lock(); - - if (sockets.size() ) - { - std::tie(sock, addr) = sockets.front(); - - sockets.pop(); - } - - if (sockets.empty() ) - { - eventThreadCycle.reset(); - - this->eventNotFullQueue->notify(); - } - - this->sockets_queue_mtx.unlock(); - - if (sock.is_open() ) - { - ++this->threads_working_count; - - struct ::sockaddr_in sock_addr; - ::socklen_t sock_addr_len = sizeof(sock_addr); - - ::getsockname(sock.get_handle(), reinterpret_cast(&sock_addr), &sock_addr_len); - - const int port = ntohs(sock_addr.sin_port); - - auto const it = this->tls_data.find(port); - - if (this->tls_data.cend() != it) // if TLS connection - { - const std::tuple &data = it->second; - - SocketAdapterTls socket_adapter( - sock, - std::get(data), - std::get(data) - ); - - if (socket_adapter.handshake() ) - { - this->threadRequestProc(socket_adapter, addr); - } - } - else - { - SocketAdapterDefault socket_adapter(sock); - - this->threadRequestProc(socket_adapter, addr); - } - - --this->threads_working_count; - } - } - } - - /** - * Цикл управления количеством рабочих потоков - */ - int Server::cycleQueue(std::queue > &sockets) - { - auto const it_option = this->settings.find("threads_max_count"); - - size_t threads_max_count = 0; - - if (this->settings.cend() != it_option) - { - const std::string &option = it_option->second; - - threads_max_count = std::strtoull(option.c_str(), nullptr, 10); - } - - if (0 == threads_max_count) - { - threads_max_count = std::thread::hardware_concurrency(); - - if (0 == threads_max_count) - { - threads_max_count = 1; - } - - threads_max_count *= 2; - } - - this->threads_working_count = 0; - - Event eventThreadCycle(false, true); - - std::function > &, Event &)> serverThreadRequestCycle = std::mem_fn(&Server::threadRequestCycle); - - std::vector active_threads; - active_threads.reserve(threads_max_count); - - // For update applications modules - do - { - if (this->eventUpdateModule->notifed() ) - { - updateModules(); - } - - // Cycle creation threads applications requests - do - { - while (this->threads_working_count == active_threads.size() && active_threads.size() < threads_max_count && sockets.empty() == false) - { - active_threads.emplace_back(serverThreadRequestCycle, this, std::ref(sockets), std::ref(eventThreadCycle) ); - } - - size_t notify_count = active_threads.size() - this->threads_working_count; - - if (notify_count > sockets.size() ) - { - notify_count = sockets.size(); - } - - eventThreadCycle.notify(notify_count); - - this->eventProcessQueue->wait(); - } - while (this->process_flag); - - // Data clear - - eventThreadCycle.notify(); - - if (false == active_threads.empty() ) - { - // Join threads (wait completion) - for (auto &th : active_threads) - { - th.join(); - } - - active_threads.clear(); - } - - this->eventNotFullQueue->notify(); - } - while (this->eventUpdateModule->notifed() ); - - if (false == this->server_sockets.empty() ) - { - for (Socket &s : this->server_sockets) - { - s.close(); - } - - this->server_sockets.clear(); - } - - return 0; - } - - Server::Server(): eventNotFullQueue(nullptr), eventProcessQueue(nullptr), eventUpdateModule(nullptr) - { - - } - - void Server::addDataVariant(DataVariantAbstract *dataVariant) - { - this->variants.emplace(dataVariant->getName(), dataVariant); - } - - bool Server::updateModule(Module &module, std::unordered_set &applications, const size_t moduleIndex) - { - std::unordered_set same; - - for (auto &app : applications) - { - if (app->module_index == moduleIndex) - { - same.emplace(app); - - try - { - if (app->application_final) - { - app->application_final(); - } - } - catch (std::exception &exc) - { - std::cout << "Warning: the error of the application's finalize '" << app->server_module << "':" << exc.what() << std::endl; - } - - app->application_call = std::function(); - app->application_clear = std::function(); - app->application_init = std::function(); - app->application_final = std::function(); - } - } - - module.close(); - - auto const app = *(same.cbegin() ); - - const std::string &module_name = app->server_module; - - #ifdef WIN32 - std::ifstream src(app->server_module_update, std::ifstream::binary); - - if ( ! src) - { - std::cout << "Error: the file '" << app->server_module_update << "' cannot be open;" << std::endl; - return false; - } - - std::ofstream dst(module_name, std::ofstream::binary | std::ofstream::trunc); - - if ( ! dst) - { - std::cout << "Error: the file '" << module_name << "' cannot be open;" << std::endl; - return false; - } - - // Copy (rewrite) file - dst << src.rdbuf(); - - src.close(); - dst.close(); - - // Open updated module - module.open(module_name); - - #elif POSIX - // HACK: for posix system — load new version shared library - - const size_t dir_pos = module_name.rfind('/'); - const size_t ext_pos = module_name.rfind('.'); - - std::string module_name_temp; - - if (std::string::npos != ext_pos && (std::string::npos == dir_pos || dir_pos < ext_pos) ) - { - module_name_temp = module_name.substr(0, ext_pos) + '-' + Utils::getUniqueName() + module_name.substr(ext_pos); - } - else - { - module_name_temp = module_name + '-' + Utils::getUniqueName(); - } - - std::ifstream src(app->server_module_update, std::ifstream::binary); - - if ( ! src) - { - std::cout << "Error: the file '" << app->server_module_update << "' cannot be open;" << std::endl; - return false; - } - - std::ofstream dst(module_name_temp, std::ofstream::binary | std::ofstream::trunc); - - if ( ! dst) - { - std::cout << "Error: the file '" << module_name << "' cannot be open;" << std::endl; - return false; - } - - // Copy (rewrite) file - dst << src.rdbuf(); - - src.close(); - dst.close(); - - // Open updated module - module.open(module_name_temp); - - if (0 != remove(module_name.c_str() ) ) - { - std::cout << "Error: the file '" << module_name << "' could not be removed;" << std::endl; - return false; - } - - if (0 != rename(module_name_temp.c_str(), module_name.c_str() ) ) - { - std::cout << "Error: the file '" << module_name_temp << "' could not be renamed;" << std::endl; - return false; - } - #else - #error "Undefine platform" - #endif - - if (false == module.is_open() ) - { - std::cout << "Error: application's module '" << module_name << "' cloud not be opened;" << std::endl; - return false; - } - - void *(*addr)(void *) = nullptr; - - if (false == module.find("application_call", &addr) ) - { - std::cout << "Error: the function 'application_call' was not found in the module '" << module_name << "';" << std::endl; - return false; - } - - std::function app_call = reinterpret_cast(addr); - - if ( ! app_call) - { - std::cout << "Error: invalid function 'application_call' is in the module '" << module_name << "';" << std::endl; - return false; - } - - if (false == module.find("application_clear", &addr) ) - { - std::cout << "Error: the function 'application_clear' was not found in the module '" << module_name << "';" << std::endl; - return false; - } - - std::function app_clear = reinterpret_cast(addr); - - std::function app_init = std::function(); - - if (module.find("application_init", &addr) ) - { - app_init = reinterpret_cast(addr); - } - - std::function app_final = std::function(); - - if (module.find("application_final", &addr) ) - { - app_final = reinterpret_cast(addr); - } - - for (auto &app : same) - { - app->application_call = app_call; - app->application_clear = app_clear; - app->application_init = app_init; - app->application_final = app_final; - - try - { - if (app->application_init) - { - app->application_init(); - } - } - catch (std::exception &exc) - { - std::cout << "Warning: the error of the application's initializing '" << module_name << "':" << exc.what() << std::endl; - } - } - - return true; - } - - void Server::updateModules() - { - // Applications settings list - std::unordered_set applications; - // Get full applications settings list - this->apps_tree.collectApplicationSettings(applications); - - std::unordered_set updated; - - for (auto const &app : applications) - { - const size_t module_index = app->module_index; - - // If module is not updated (not checked) - if (updated.cend() == updated.find(module_index) ) - { - if (false == app->server_module_update.empty() && app->server_module_update != app->server_module) - { - size_t module_size_new = 0; - time_t module_time_new = 0; - - if (System::getFileSizeAndTimeGmt(app->server_module_update, &module_size_new, &module_time_new) ) - { - size_t module_size_cur = 0; - time_t module_time_cur = 0; - - Module &module = this->modules[module_index]; - - if (System::getFileSizeAndTimeGmt(app->server_module, &module_size_cur, &module_time_cur) ) - { - if (module_size_cur != module_size_new || module_time_cur < module_time_new) - { - this->updateModule(module, applications, module_index); - } - } - } - } - - updated.emplace(module_index); - } - } - - std::cout << "Notice: applications' modules have been updated;" << std::endl; - - this->process_flag = true; - this->eventUpdateModule->reset(); - } - - bool Server::init() - { - ConfigParser conf_parser; - - if (Socket::Startup() && conf_parser.loadConfig("main.conf", this->settings, this->mimes_types, this->modules, this->apps_tree) ) - { - this->addDataVariant(new DataVariantFormUrlencoded() ); - this->addDataVariant(new DataVariantMultipartFormData() ); - this->addDataVariant(new DataVariantTextPlain() ); - - ::gnutls_global_init(); - - return true; - } - - return false; - } - - void Server::clear() - { - Socket::Cleanup(); - - if (this->eventNotFullQueue) - { - delete this->eventNotFullQueue; - this->eventNotFullQueue = nullptr; - } - - if (this->eventProcessQueue) - { - delete this->eventProcessQueue; - this->eventProcessQueue = nullptr; - } - - if (this->eventUpdateModule) - { - delete this->eventUpdateModule; - this->eventUpdateModule = nullptr; - } - - if (false == this->variants.empty() ) - { - for (auto &variant : this->variants) - { - delete variant.second; - } - - this->variants.clear(); - } - - if (false == this->tls_data.empty() ) - { - for (auto &pair : this->tls_data) - { - std::tuple &data = pair.second; - - ::gnutls_certificate_free_credentials(std::get<0>(data) ); - ::gnutls_priority_deinit(std::get<1>(data) ); - } - } - - if (false == this->apps_tree.empty() ) - { - std::unordered_set applications; - this->apps_tree.collectApplicationSettings(applications); - - for (auto &app : applications) - { - try - { - if (app->application_final) - { - app->application_final(); - } - } - catch (std::exception &exc) - { - std::cout << "Warning: the error of the application's finalize '" << app->server_module << "':" << exc.what() << std::endl; - } - - delete app; - } - - applications.clear(); - this->apps_tree.clear(); - } - - if (false == this->modules.empty() ) - { - for (auto &module : this->modules) - { - module.close(); - } - - this->modules.empty(); - } - - if (false == this->settings.empty() ) - { - this->settings.clear(); - } - - ::gnutls_global_deinit(); - } - - bool Server::tlsInit(const ServerApplicationSettings &app, std::tuple &data) - { - ::gnutls_certificate_credentials_t x509_cred; - - int ret = ::gnutls_certificate_allocate_credentials(&x509_cred); - - if (ret < 0) - { - std::cout << "Error [tls]: certificate credentials has not been allocated;" << std::endl; - - return false; - } - - if (false == app.chain_file.empty() ) - { - ret = ::gnutls_certificate_set_x509_trust_file(x509_cred, app.chain_file.c_str(), GNUTLS_X509_FMT_PEM); - - if (ret < 0) - { - std::cout << "Warning [tls]: (CA) chain file has not been accepted;" << std::endl; - } - } - - if (false == app.crl_file.empty() ) - { - ret = ::gnutls_certificate_set_x509_crl_file(x509_cred, app.crl_file.c_str(), GNUTLS_X509_FMT_PEM); - - if (ret < 0) - { - std::cout << "Warning [tls]: (CLR) clr file has not been accepted;" << std::endl; - } - } - - ret = ::gnutls_certificate_set_x509_key_file(x509_cred, app.cert_file.c_str(), app.key_file.c_str(), GNUTLS_X509_FMT_PEM); - - if (ret < 0) - { - std::cout << "Error [tls]: (CERT) cert file or/and (KEY) key file has not been accepted;" << std::endl; - - return false; - } - - if (false == app.stapling_file.empty() ) - { - ret = ::gnutls_certificate_set_ocsp_status_request_file(x509_cred, app.stapling_file.c_str(), 0); - - if (ret < 0) - { - std::cout << "Warning [tls]: (OCSP) stapling file has not been accepted;" << std::endl; - } - } - - ::gnutls_dh_params_t dh_params; - - ::gnutls_dh_params_init(&dh_params); - - if (app.dh_file.empty() ) - { - const unsigned int bits = ::gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_HIGH); - - ret = ::gnutls_dh_params_generate2(dh_params, bits); - } - else - { - std::ifstream dh_file(app.dh_file); - - if (dh_file) - { - const size_t max_file_size = 1024 * 1024; - - std::vector buf(max_file_size); - - dh_file.read(buf.data(), buf.size() ); - - gnutls_datum_t datum { - reinterpret_cast(buf.data() ), - static_cast(dh_file.gcount() ) - }; - - ret = ::gnutls_dh_params_import_pkcs3(dh_params, &datum, GNUTLS_X509_FMT_PEM); - } - else - { - ret = -1; - - std::cout << "Error [tls]: DH params file has not been opened;" << std::endl;; - } - - dh_file.close(); - } - - if (ret < 0) - { - ::gnutls_certificate_free_credentials(x509_cred); - - std::cout << "Error [tls]: DH params were not loaded;" << std::endl; - - return false; - } - - ::gnutls_certificate_set_dh_params(x509_cred, dh_params); - - ::gnutls_priority_t priority_cache; - - ret = ::gnutls_priority_init(&priority_cache, "NORMAL", nullptr); - - if (ret < 0) - { - ::gnutls_certificate_free_credentials(x509_cred); - - std::cout << "Error [tls]: priority cache cannot be init;" << std::endl; - - return false; - } - - data = std::tuple{x509_cred, priority_cache}; - - return true; - } - - bool Server::tryBindPort(const int port, std::unordered_set &ports) - { - // Only unique ports - if (ports.cend() != ports.find(port) ) - { - return false; - } - - Socket sock; - - if (false == sock.open() ) - { - std::cout << "Error: the socket cannot be open; errno " << Socket::getLastError() << ";" << std::endl; - return false; - } - - if (false == sock.bind(port) ) - { - std::cout << "Error: the socket " << port << " cannot be bind; errno " << Socket::getLastError() << ";" << std::endl; - return false; - } - - if (false == sock.listen() ) - { - std::cout << "Error: the socket " << port << " cannot be listen; errno " << Socket::getLastError() << ";" << std::endl; - return false; - } - - sock.nonblock(true); - - this->server_sockets.emplace_back(std::move(sock) ); - - ports.emplace(port); - - return true; - } - - void Server::initAppsPorts() - { - // Applications settings list - std::unordered_set applications; - // Get full applications settings list - this->apps_tree.collectApplicationSettings(applications); - - // Bind ports set - std::unordered_set ports; - - // Open applications sockets - for (auto const &app : applications) - { - const std::unordered_set &tls = app->tls_ports; - - if (false == tls.empty() ) - { - std::tuple data; - - if (Server::tlsInit(*app, data) ) - { - for (const int port : tls) - { - if (this->tryBindPort(port, ports) ) - { - this->tls_data.emplace(port, data); - } - } - } - } - - const std::unordered_set &list = app->ports; - - for (const int port : list) - { - this->tryBindPort(port, ports); - } - } - } - - int Server::run() - { - if (false == this->init() ) - { - return 0x10; - } - - this->initAppsPorts(); - - if (this->server_sockets.empty() ) - { - std::cout << "Error: any socket was not open;" << std::endl; - this->clear(); - return 0x20; - } - - SocketList sockets_list; - - sockets_list.create(this->server_sockets.size() ); - - for (auto const &sock : this->server_sockets) - { - sockets_list.addSocket(sock); - } - - std::cout << "Log: launch server's cycle;" << std::endl << std::endl; - - const size_t queue_max_length = 1024; - this->eventNotFullQueue = new Event(true, true); - this->eventProcessQueue = new Event(); - this->eventUpdateModule = new Event(false, true); - - std::queue > sockets; - - this->process_flag = true; - - std::function > &)> serverCycleQueue = std::mem_fn(&Server::cycleQueue); - std::thread threadQueue(serverCycleQueue, this, std::ref(sockets) ); - - std::vector accept_sockets; - std::vector accept_sockets_address; - - // Cycle for receiving new connections - do - { - if (sockets_list.accept(accept_sockets, accept_sockets_address) ) - { - this->sockets_queue_mtx.lock(); - - for (size_t i = 0; i < accept_sockets.size(); ++i) - { - const Socket &sock = accept_sockets[i]; - - if (sock.is_open() ) - { - sock.nonblock(true); - sock.tcp_nodelay(true); - - sockets.emplace( - std::tuple { - sock, - accept_sockets_address[i] - } - ); - } - } - - this->sockets_queue_mtx.unlock(); - - this->eventProcessQueue->notify(); - - if (sockets.size() >= queue_max_length) - { - this->eventNotFullQueue->reset(); - } - - accept_sockets.clear(); - accept_sockets_address.clear(); - - this->eventNotFullQueue->wait(); - } - } - while (this->process_flag || this->eventUpdateModule->notifed() ); - - this->eventProcessQueue->notify(); - - threadQueue.join(); - - sockets_list.destroy(); - - this->clear(); - - std::cout << "Log: complete server's cycle;" << std::endl; - - return EXIT_SUCCESS; - } - - void Server::stopProcess() - { - this->process_flag = false; - - if (this->eventNotFullQueue) - { - this->eventNotFullQueue->notify(); - } - - this->setProcessQueue(); - } - - void Server::unsetProcess() - { - this->process_flag = false; - } - - void Server::setRestart() - { - this->restart_flag = true; - } - - void Server::setUpdateModule() - { - if (this->eventUpdateModule) - { - this->eventUpdateModule->notify(); - } - } - - void Server::setProcessQueue() - { - if (this->eventProcessQueue) - { - this->eventProcessQueue->notify(); - } - } - - bool Server::get_start_args(const int argc, const char *argv[], struct server_start_args *st) - { - for (int i = 1; i < argc; ++i) - { - if (0 == ::strcmp(argv[i], "--start") ) - { - - } - else if (0 == ::strcmp(argv[i], "--force") ) - { - st->force = true; - } - else if (argv[i] == ::strstr(argv[i], "--config-path=") ) - { - st->config_path = std::string(argv[i] + sizeof("--config-path=") - 1); - } - else if (argv[i] == ::strstr(argv[i], "--server-name=") ) - { - st->server_name = std::string(argv[i] + sizeof("--server-name=") - 1); - } - else - { - std::cout << "The argument '" << argv[i] << "' can't be applied with --start;" << std::endl; - - return false; - } - } - - if (st->server_name.empty() ) - { - st->server_name = argv[0]; - } - - System::filterSharedMemoryName(st->server_name); - - return true; - } - - int Server::command_start(const int argc, const char *argv[]) - { - struct server_start_args st = {}; - - if (false == Server::get_start_args(argc, argv, &st) ) - { - return 0x1; - } - - if (false == st.config_path.empty() ) - { - if (false == System::changeCurrentDirectory(st.config_path) ) - { - std::cout << "Configuration path '" << st.config_path << "' has not been found;" << std::endl; - - return 0x2; - } - } - - if (st.force) - { - SharedMemory::destroy(st.server_name); - GlobalMutex::destory(st.server_name); - } - - GlobalMutex glob_mtx; - SharedMemory glob_mem; - - bool is_exists = false; - - if (glob_mtx.open(st.server_name) ) - { - glob_mtx.lock(); - - if (glob_mem.open(st.server_name) ) - { - System::native_processid_type pid = 0; - - if (glob_mem.read(&pid, sizeof(pid) ) ) - { - is_exists = System::isProcessExists(pid); - } - } - - glob_mtx.unlock(); - } - - if (is_exists) - { - std::cout << "The server instance with the name '" << st.server_name << "' is already running;" << std::endl; - - return 0x3; - } - - if (false == glob_mtx.open(st.server_name) ) - { - if (false == glob_mtx.create(st.server_name) ) - { - std::cout << "The global mutex could not been created;" << std::endl; - - return 0x4; - } - } - - glob_mtx.lock(); - - if (false == glob_mem.open(st.server_name) ) - { - if (false == glob_mem.create(st.server_name, sizeof(System::native_processid_type) ) ) - { - glob_mtx.unlock(); - - std::cout << "The shared memory could not been allocated;" << std::endl; - - return 0x5; - } - } - - System::native_processid_type pid = System::getProcessId(); - - if (false == glob_mem.write(&pid, sizeof(pid) ) ) - { - glob_mem.destroy(); - glob_mtx.unlock(); - - std::cout << "Writing data to the shared memory has failed;" << std::endl; - - return 0x6; - } - - glob_mtx.unlock(); - - int code = EXIT_FAILURE; - - do - { - this->process_flag = false; - this->restart_flag = false; - - code = this->run(); - } - while (this->process_flag || this->restart_flag); - - glob_mem.destroy(); - glob_mtx.destory(); - - return code; - } - - System::native_processid_type Server::getServerProcessId(const std::string &serverName) - { - System::native_processid_type pid = 0; - - GlobalMutex glob_mtx; - - if (glob_mtx.open(serverName) ) - { - SharedMemory glob_mem; - - glob_mtx.lock(); - - if (glob_mem.open(serverName) ) - { - glob_mem.read(&pid, sizeof(pid) ); - } - - glob_mtx.unlock(); - } - - return pid; - } - - int Server::command_help(const int argc, const char *argv[]) const - { - std::cout << std::left << "Available arguments:" << std::endl - << std::setw(4) << ' ' << std::setw(26) << "--start" << "Start the http server" << std::endl - << std::setw(8) << ' ' << std::setw(22) << "[options]" << std::endl - << std::setw(8) << ' ' << std::setw(22) << "--force" << "Forcibly start the http server (ignore the existing instance)" << std::endl - << std::setw(8) << ' ' << std::setw(22) << "--config-path=" << "The path to the directory with configuration files" << std::endl - << std::endl - << std::setw(4) << ' ' << std::setw(26) << "--restart" << "Restart the http server" << std::endl - << std::setw(4) << ' ' << std::setw(26) << "--update-module" << "Update the applications modules" << std::endl - << std::setw(4) << ' ' << std::setw(26) << "--kill" << "Shutdown the http server" << std::endl - << std::setw(4) << ' ' << std::setw(26) << "--help" << "This help" << std::endl - << std::endl<< "Optional arguments:" << std::endl - << std::setw(4) << ' ' << std::setw(26) << "--server-name=" << "The name of the server instance" << std::endl; - - return EXIT_SUCCESS; - } - - static std::string get_server_name(const int argc, const char *argv[]) - { - std::string server_name; - - for (int i = 1; i < argc; ++i) - { - if (argv[i] == ::strstr(argv[i], "--server-name=") ) - { - server_name = std::string(argv[i] + sizeof("--server-name=") - 1); - break; - } - } - - if (server_name.empty() ) - { - server_name = argv[0]; - } - - System::filterSharedMemoryName(server_name); - - return server_name; - } - - int Server::command_restart(const int argc, const char *argv[]) const - { - const System::native_processid_type pid = Server::getServerProcessId(get_server_name(argc, argv) ); - - if (1 < pid && System::sendSignal(pid, SIGUSR1) ) - { - return EXIT_SUCCESS; - } - - return EXIT_FAILURE; - } - - int Server::command_terminate(const int argc, const char *argv[]) const - { - const System::native_processid_type pid = Server::getServerProcessId(get_server_name(argc, argv) ); - - if (1 < pid && System::sendSignal(pid, SIGTERM) ) - { - return EXIT_SUCCESS; - } - - return EXIT_FAILURE; - } - - int Server::command_update_module(const int argc, const char *argv[]) const - { - const System::native_processid_type pid = Server::getServerProcessId(get_server_name(argc, argv) ); - - if (1 < pid && System::sendSignal(pid, SIGUSR2) ) - { - return EXIT_SUCCESS; - } - - return EXIT_FAILURE; - } -}; \ No newline at end of file diff --git a/src/Server.h b/src/Server.h deleted file mode 100644 index 54f1d2d..0000000 --- a/src/Server.h +++ /dev/null @@ -1,148 +0,0 @@ -#pragma once - -#include "SocketList.h" -#include "DataVariantAbstract.h" -#include "ServerApplicationsTree.h" -#include "ServerApplicationDefaultSettings.h" -#include "Module.h" -#include "Event.h" -#include "SocketAdapter.h" -#include "ServerStructuresArguments.h" - -#include -#include -#include -#include -#include -#include - -#include - -namespace HttpServer -{ - class Server - { - protected: - std::unordered_map variants; - - std::unordered_map settings; - std::unordered_map mimes_types; - - std::unordered_map > tls_data; - - std::vector modules; - - ServerApplicationsTree apps_tree; - - std::vector server_sockets; - - Event *eventNotFullQueue; - Event *eventProcessQueue; - Event *eventUpdateModule; - - mutable std::atomic_size_t threads_working_count; - mutable std::mutex sockets_queue_mtx; - - // Флаг, означающий - активированы ли главные циклы сервера - // (с помощью этого флага можно деактивировать циклы, чтобы завершить работу сервера) - sig_atomic_t process_flag; - sig_atomic_t restart_flag; - - protected: - static const int CONNECTION_CLOSED = 0; - static const int CONNECTION_KEEP_ALIVE = 1; - static const int CONNECTION_UPGRADE = 2; - - protected: - int cycleQueue(std::queue > &sockets); - - int threadRequestProc(SocketAdapter &clientSocket, const struct sockaddr_in &clientAddr) const; - - static bool getRequest(const SocketAdapter &clientSocket, std::vector &buf, std::string &str_buf, struct request_parameters &rp); - - int getRequestHeaders(std::string &str_buf, struct request_parameters &rp) const; - - static void runApplication(const SocketAdapter &clientSocket, const ServerApplicationSettings &appSets, struct request_parameters &rp); - - int getRequestData(const SocketAdapter &clientSocket, std::string &str_buf, const ServerApplicationSettings &appSets, struct request_parameters &rp) const; - - const ServerApplicationSettings *getApplicationSettings(const struct request_parameters &rp) const; - - static void getConnectionParams(struct request_parameters &rp); - - void xSendfile(const SocketAdapter &clientSocket, struct request_parameters &rp) const; - - static bool isConnectionKeepAlive(const struct request_parameters &rp); - static bool isConnectionUpgrade(const struct request_parameters &rp); - - void threadRequestCycle(std::queue > &sockets, Event &eventThreadCycle) const; - - std::string getMimeTypeByFileName(const std::string &fileName) const; - - std::vector > getRanges( - const std::string &rangeHeader, - const size_t posSymEqual, - const size_t fileSize, - std::string &resultRangeHeader, - size_t &contentLength - ) const; - - int transferFilePart( - const SocketAdapter &clientSocket, - const std::chrono::milliseconds &timeout, - const std::string &fileName, - const time_t fileTime, - const size_t fileSize, - const std::string &rangeHeader, - const std::string &connectionHeader, - const std::string &dateHeader, - const bool headersOnly - ) const; - - int transferFile( - const SocketAdapter &clientSocket, - const std::string &fileName, - const std::string &connectionHeader, - const bool headersOnly, - struct request_parameters &rp - ) const; - - static bool parseIncomingVars(std::unordered_multimap ¶ms, const std::string &uriParams); - static void sendStatus(const SocketAdapter &clientSocket, const std::chrono::milliseconds &timeout, const size_t statusCode); - - static bool tlsInit(const ServerApplicationSettings &app, std::tuple &data); - - bool tryBindPort(const int port, std::unordered_set &ports); - void initAppsPorts(); - - bool init(); - int run(); - void clear(); - - static System::native_processid_type getServerProcessId(const std::string &serverName); - - void updateModules(); - bool updateModule(Module &module, std::unordered_set &applications, const size_t moduleIndex); - - private: - void addDataVariant(DataVariantAbstract *dataVariant); - - static bool get_start_args(const int argc, const char *argv[], struct server_start_args *st); - - public: - Server(); - ~Server() = default; - - void stopProcess(); - void unsetProcess(); - void setRestart(); - void setUpdateModule(); - void setProcessQueue(); - - int command_help(const int argc, const char *argv[]) const; - int command_start(const int argc, const char *argv[]); - int command_restart(const int argc, const char *argv[]) const; - int command_terminate(const int argc, const char *argv[]) const; - int command_update_module(const int argc, const char *argv[]) const; - }; -}; \ No newline at end of file diff --git a/src/ServerApplicationDefaultSettings.h b/src/ServerApplicationDefaultSettings.h deleted file mode 100644 index c0d59d1..0000000 --- a/src/ServerApplicationDefaultSettings.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -namespace HttpServer -{ - struct ServerApplicationDefaultSettings - { - std::string temp_dir; - size_t request_max_size; - }; -}; \ No newline at end of file diff --git a/src/ServerRequest.h b/src/ServerRequest.h deleted file mode 100644 index dc80893..0000000 --- a/src/ServerRequest.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "RawData.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; - }; -}; diff --git a/src/ServerResponse.h b/src/ServerResponse.h deleted file mode 100644 index 7573e3a..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; - }; -}; diff --git a/src/SignalHandlers.cpp b/src/SignalHandlers.cpp index cdc4bd4..a187c36 100644 --- a/src/SignalHandlers.cpp +++ b/src/SignalHandlers.cpp @@ -1,6 +1,6 @@  #include "SignalHandlers.h" -#include "System.h" +#include "system/System.h" #ifdef WIN32 #include @@ -17,47 +17,47 @@ static HttpServer::Server *globalServerPtr = nullptr; /** * Terminate signal */ -static void handlerSigTerm(const int) +static void handlerSigTerm(const int) noexcept { if (globalServerPtr) { - globalServerPtr->stopProcess(); + globalServerPtr->controls.stopProcess(); } } /** * Interrupt signal */ -static void handlerSigInt(const int) +static void handlerSigInt(const int) noexcept { if (globalServerPtr) { - globalServerPtr->stopProcess(); + globalServerPtr->controls.stopProcess(); } } /** * Signal to restart */ -static void handlerSigUsr1(const int) +static void handlerSigUsr1(const int) noexcept { if (globalServerPtr) { - globalServerPtr->setRestart(); - globalServerPtr->stopProcess(); + globalServerPtr->controls.setRestart(); + globalServerPtr->controls.stopProcess(); } } /** * Signal to update modules */ -static void handlerSigUsr2(const int) +static void handlerSigUsr2(const int) noexcept { if (globalServerPtr) { - globalServerPtr->setUpdateModule(); - globalServerPtr->unsetProcess(); - globalServerPtr->setProcessQueue(); + globalServerPtr->controls.setUpdateModule(); + globalServerPtr->controls.setProcess(false); + globalServerPtr->controls.setProcessQueue(); } } @@ -67,7 +67,7 @@ static void handlerSigUsr2(const int) * It doesn't work in case the program was launched and was * attempted to finish under different remote sessions. */ -static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const ::WPARAM wParam, const ::LPARAM lParam) +static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const ::WPARAM wParam, const ::LPARAM lParam) noexcept { switch (message) { @@ -123,7 +123,7 @@ static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const return 0; } -static ::WPARAM mainMessageLoop(const ::HINSTANCE hInstance, HttpServer::Event * const eventWindowCreation) +static ::WPARAM mainMessageLoop(const ::HINSTANCE hInstance, HttpServer::Event * const eventWindowCreation) noexcept { const ::HWND hWnd = ::CreateWindow(myWndClassName, nullptr, 0, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, nullptr, nullptr, hInstance, nullptr); @@ -146,7 +146,7 @@ static ::WPARAM mainMessageLoop(const ::HINSTANCE hInstance, HttpServer::Event * } #ifdef _CONSOLE -static ::BOOL consoleSignalHandler(const ::DWORD ctrlType) +static ::BOOL consoleSignalHandler(const ::DWORD ctrlType) noexcept { switch (ctrlType) { @@ -175,7 +175,7 @@ static ::BOOL consoleSignalHandler(const ::DWORD ctrlType) #endif // _CONSOLE #endif // WIN32 -bool bindSignalHandlers(HttpServer::Server *server) +bool bindSignalHandlers(HttpServer::Server *server) noexcept { globalServerPtr = server; @@ -234,10 +234,10 @@ bool bindSignalHandlers(HttpServer::Server *server) return true; } -void stopSignalHandlers() +void stopSignalHandlers() noexcept { #ifdef WIN32 System::sendSignal(::GetCurrentProcessId(), SIGINT); gThreadMessageLoop.join(); #endif -} \ No newline at end of file +} diff --git a/src/SignalHandlers.h b/src/SignalHandlers.h index 17bcc1e..3db4da3 100644 --- a/src/SignalHandlers.h +++ b/src/SignalHandlers.h @@ -1,7 +1,7 @@ #pragma once -#include "Server.h" +#include "server/Server.h" -bool bindSignalHandlers(HttpServer::Server *server); +bool bindSignalHandlers(HttpServer::Server *server) noexcept; -void stopSignalHandlers(); \ No newline at end of file +void stopSignalHandlers() noexcept; diff --git a/src/Socket.h b/src/Socket.h deleted file mode 100644 index 738abc8..0000000 --- a/src/Socket.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include "System.h" - -#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(); - - bool is_open() const; - System::native_socket_type get_handle() 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; - - 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; - - 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 2860db7..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 static_cast(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/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/server/Request.cpp b/src/server/Request.cpp new file mode 100644 index 0000000..f8bfcea --- /dev/null +++ b/src/server/Request.cpp @@ -0,0 +1,20 @@ + +#include "Request.h" + +namespace HttpServer +{ + void Request::clear() noexcept + { + incoming_headers.clear(); + incoming_data.clear(); + incoming_files.clear(); + + outgoing_headers.clear(); + + host.clear(); + path.clear(); + method.clear(); + + // timeout = std::chrono::milliseconds::zero(); + } +}; diff --git a/src/server/Request.h b/src/server/Request.h new file mode 100644 index 0000000..dd2b5d5 --- /dev/null +++ b/src/server/Request.h @@ -0,0 +1,44 @@ +#pragma once + +#include "../transfer/AppRequest.h" +#include "../transfer/ProtocolVariant.h" + +#include +#include + +namespace HttpServer +{ + enum ConnectionParams + { + CONNECTION_CLOSE = 0, + CONNECTION_REUSE = 1, + CONNECTION_LEAVE_OPEN = 2 + }; + + struct Request : public Transfer::request_data + { + std::unordered_map outgoing_headers; + + std::string host; + std::string path; + std::string method; + + std::chrono::milliseconds timeout; + + size_t keep_alive_count; + int connection_params; + int app_exit_code; + + Transfer::ProtocolVariant protocol_variant; + // void *protocol_data; + + public: + void clear() noexcept; + }; + + struct DataTransfer + { + size_t full_size; + size_t send_total; + }; +}; diff --git a/src/server/Server.cpp b/src/server/Server.cpp new file mode 100644 index 0000000..d46caf0 --- /dev/null +++ b/src/server/Server.cpp @@ -0,0 +1,1109 @@ + +#include "Server.h" + +#include "config/ConfigParser.h" +#include "data-variant/FormUrlencoded.h" +#include "data-variant/MultipartFormData.h" +#include "data-variant/TextPlain.h" +#include "protocol/ServerHttp1.h" +#include "protocol/ServerHttp2.h" +#include "protocol/ServerHttp2Stream.h" + +#include "ServerStructuresArguments.h" + +#include "../socket/List.h" +#include "../socket/AdapterDefault.h" +#include "../socket/AdapterTls.h" +#include "../system/GlobalMutex.h" +#include "../system/SharedMemory.h" +#include "../system/System.h" +#include "../utils/Utils.h" + +#include +#include +#include +#include +#include + +namespace HttpServer +{ + static std::unique_ptr getProtocolVariant( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls, + SocketsQueue &sockets, + Http2::IncStream *stream + ) + { + std::unique_ptr prot; + + // If request is HTTP/2 Stream + if (stream) + { + prot.reset(new ServerHttp2Stream(sock, settings, controls, stream) ); + + return prot; + } + + if (sock.get_tls_session() ) + { + ::gnutls_datum_t datum; + + if (0 == ::gnutls_alpn_get_selected_protocol(sock.get_tls_session(), &datum) ) + { + const std::string protocol(reinterpret_cast(datum.data), datum.size); + + if ("h2" == protocol) + { + prot.reset(new ServerHttp2(sock, settings, controls, sockets) ); + } + else if ("http/1.1" == protocol) + { + prot.reset(new ServerHttp1(sock, settings, controls) ); + } + } + + return prot; + } + + prot.reset(new ServerHttp1(sock, settings, controls) ); + + return prot; + } + + /** + * Метод для обработки запроса + */ + void Server::threadRequestProc(Socket::Adapter &sock, SocketsQueue &sockets, Http2::IncStream *stream) const + { + std::unique_ptr prot = getProtocolVariant(sock, this->settings, this->controls, sockets, stream); + + if (prot) + { + // Check if switching protocol + for (ServerProtocol *ret = nullptr; ; ) + { + ret = prot->process(); + + if (prot.get() == ret) + { + break; + } + + prot.reset(ret); + } + + prot->close(); + } + } + + /** + * Метод для обработки запросов (запускается в отдельном потоке) + * извлекает сокет клиенты из очереди и передаёт его на обслуживание + */ + void Server::threadRequestCycle(SocketsQueue &sockets, Utils::Event &eventThreadCycle) const + { + while (true) + { + Socket::Socket sock; + Http2::IncStream *stream = nullptr; + + eventThreadCycle.wait(); + + if (false == this->controls.process_flag) + { + break; + } + + sockets.lock(); + + if (sockets.size() ) + { + std::tie(sock, stream) = sockets.front(); +/* + sockaddr_in addr {}; + socklen_t addr_size = sizeof(sockaddr_in); + ::getpeername(sock.get_handle(), reinterpret_cast(&addr), &addr_size); +*/ + sockets.pop(); + } + + if (sockets.empty() ) + { + eventThreadCycle.reset(); + + this->controls.eventNotFullQueue->notify(); + } + + sockets.unlock(); + + if (sock.is_open() ) + { + ++this->threads_working_count; + + ::sockaddr_in sock_addr {}; + ::socklen_t sock_addr_len = sizeof(sock_addr); + + ::getsockname(sock.get_handle(), reinterpret_cast(&sock_addr), &sock_addr_len); + + const int port = ntohs(sock_addr.sin_port); + + auto const it = this->tls_data.find(port); + + if (this->tls_data.cend() != it) // if TLS connection + { + if (stream) + { + Socket::AdapterTls socket_adapter(reinterpret_cast(stream->reserved) ); + + this->threadRequestProc(socket_adapter, sockets, stream); + } + else + { + const std::tuple &data = it->second; + + Socket::AdapterTls socket_adapter( + sock, + std::get(data), + std::get(data) + ); + + if (socket_adapter.handshake() ) + { + this->threadRequestProc(socket_adapter, sockets, nullptr); + } + } + } + else + { + Socket::AdapterDefault socket_adapter(sock); + + this->threadRequestProc(socket_adapter, sockets, stream); + } + + --this->threads_working_count; + } + } + } + + /** + * Цикл управления количеством рабочих потоков + */ + int Server::cycleQueue(SocketsQueue &sockets) + { + auto const it_option = this->settings.global.find("threads_max_count"); + + size_t threads_max_count = 0; + + if (this->settings.global.cend() != it_option) + { + const std::string &option = it_option->second; + + threads_max_count = std::strtoull(option.c_str(), nullptr, 10); + } + + if (0 == threads_max_count) + { + threads_max_count = std::thread::hardware_concurrency(); + + if (0 == threads_max_count) + { + threads_max_count = 1; + } + + threads_max_count *= 2; + } + + this->threads_working_count = 0; + + Utils::Event eventThreadCycle(false, true); + + std::function serverThreadRequestCycle + = std::mem_fn(&Server::threadRequestCycle); + + std::vector active_threads; + active_threads.reserve(threads_max_count); + + // For update applications modules + do + { + if (this->controls.eventUpdateModule->notifed() ) + { + updateModules(); + } + + // Cycle creation threads applications requests + do + { + while (this->threads_working_count == active_threads.size() && active_threads.size() < threads_max_count && sockets.empty() == false) + { + active_threads.emplace_back(serverThreadRequestCycle, this, std::ref(sockets), std::ref(eventThreadCycle) ); + } + + size_t notify_count = active_threads.size() - this->threads_working_count; + + if (notify_count > sockets.size() ) + { + notify_count = sockets.size(); + } + + eventThreadCycle.notify(notify_count); + + this->controls.eventProcessQueue->wait(); + } + while (this->controls.process_flag); + + // Data clear + + eventThreadCycle.notify(); + + if (false == active_threads.empty() ) + { + // Join threads (wait completion) + for (auto &th : active_threads) + { + th.join(); + } + + active_threads.clear(); + } + + this->controls.eventNotFullQueue->notify(); + } + while (this->controls.eventUpdateModule->notifed() ); + + return 0; + } + + bool Server::updateModule(System::Module &module, std::unordered_set &applications, const size_t moduleIndex) + { + std::unordered_set same; + + for (auto &app : applications) + { + if (app->module_index == moduleIndex) + { + same.emplace(app); + + try + { + if (app->application_final) + { + app->application_final(); + } + } + catch (std::exception &exc) + { + std::cout << "Warning: error when the application finishes '" << app->server_module << "':" << exc.what() << std::endl; + } + + app->application_call = std::function(); + app->application_clear = std::function(); + app->application_init = std::function(); + app->application_final = std::function(); + } + } + + module.close(); + + auto const app = *(same.cbegin() ); + + const std::string &module_name = app->server_module; + + #ifdef WIN32 + std::ifstream src(app->server_module_update, std::ifstream::binary); + + if ( ! src) + { + std::cout << "Error: file '" << app->server_module_update << "' cannot be open;" << std::endl; + return false; + } + + std::ofstream dst(module_name, std::ofstream::binary | std::ofstream::trunc); + + if ( ! dst) + { + std::cout << "Error: file '" << module_name << "' cannot be open;" << std::endl; + return false; + } + + // Copy (rewrite) file + dst << src.rdbuf(); + + src.close(); + dst.close(); + + // Open updated module + module.open(module_name); + + #elif POSIX + // HACK: for posix system — load new version shared library + + const size_t dir_pos = module_name.rfind('/'); + const size_t ext_pos = module_name.rfind('.'); + + std::string module_name_temp; + + if (std::string::npos != ext_pos && (std::string::npos == dir_pos || dir_pos < ext_pos) ) + { + module_name_temp = module_name.substr(0, ext_pos) + '-' + Utils::getUniqueName() + module_name.substr(ext_pos); + } + else + { + module_name_temp = module_name + '-' + Utils::getUniqueName(); + } + + std::ifstream src(app->server_module_update, std::ifstream::binary); + + if ( ! src) + { + std::cout << "Error: file '" << app->server_module_update << "' cannot be open;" << std::endl; + return false; + } + + std::ofstream dst(module_name_temp, std::ofstream::binary | std::ofstream::trunc); + + if ( ! dst) + { + std::cout << "Error: file '" << module_name << "' cannot be open;" << std::endl; + return false; + } + + // Copy (rewrite) file + dst << src.rdbuf(); + + src.close(); + dst.close(); + + // Open updated module + module.open(module_name_temp); + + if (0 != std::remove(module_name.c_str() ) ) + { + std::cout << "Error: file '" << module_name << "' could not be removed;" << std::endl; + return false; + } + + if (0 != std::rename(module_name_temp.c_str(), module_name.c_str() ) ) + { + std::cout << "Error: file '" << module_name_temp << "' could not be renamed;" << std::endl; + return false; + } + #else + #error "Undefined platform" + #endif + + if (false == module.is_open() ) + { + std::cout << "Error: the application module '" << module_name << "' can not be opened;" << std::endl; + return false; + } + + void *(*addr)(void *) = nullptr; + + if (false == module.find("application_call", &addr) ) + { + std::cout << "Error: function 'application_call' was not found in the module '" << module_name << "';" << std::endl; + return false; + } + + std::function app_call = reinterpret_cast(addr); + + if ( ! app_call) + { + std::cout << "Error: invalid function 'application_call' is in the module '" << module_name << "';" << std::endl; + return false; + } + + if (false == module.find("application_clear", &addr) ) + { + std::cout << "Error: function 'application_clear' was not found in the module '" << module_name << "';" << std::endl; + return false; + } + + std::function app_clear = reinterpret_cast(addr); + + std::function app_init = std::function(); + + if (module.find("application_init", &addr) ) + { + app_init = reinterpret_cast(addr); + } + + std::function app_final = std::function(); + + if (module.find("application_final", &addr) ) + { + app_final = reinterpret_cast(addr); + } + + for (auto &app : same) + { + app->application_call = app_call; + app->application_clear = app_clear; + app->application_init = app_init; + app->application_final = app_final; + + try + { + if (app->application_init) + { + app->application_init(); + } + } + catch (std::exception &exc) + { + std::cout << "Warning: error when initializing the application '" << module_name << "':" << exc.what() << std::endl; + } + } + + return true; + } + + void Server::updateModules() + { + // Applications settings list + std::unordered_set applications; + // Get full applications settings list + this->settings.apps_tree.collectApplicationSettings(applications); + + std::unordered_set updated; + + for (auto const &app : applications) + { + const size_t module_index = app->module_index; + + // If module is not updated (not checked) + if (updated.cend() == updated.find(module_index) ) + { + if (false == app->server_module_update.empty() && app->server_module_update != app->server_module) + { + size_t module_size_new = 0; + time_t module_time_new = 0; + + if (System::getFileSizeAndTimeGmt(app->server_module_update, &module_size_new, &module_time_new) ) + { + size_t module_size_cur = 0; + time_t module_time_cur = 0; + + System::Module &module = this->modules[module_index]; + + if (System::getFileSizeAndTimeGmt(app->server_module, &module_size_cur, &module_time_cur) ) + { + if (module_size_cur != module_size_new || module_time_cur < module_time_new) + { + this->updateModule(module, applications, module_index); + } + } + } + } + + updated.emplace(module_index); + } + } + + std::cout << "Notice: applications' modules have been updated;" << std::endl; + + this->controls.setProcess(); + this->controls.eventUpdateModule->reset(); + } + + bool Server::init() + { + ConfigParser conf_parser; + + if (Socket::Socket::Startup() && conf_parser.loadConfig("main.conf", this->settings, this->modules) ) + { + this->settings.addDataVariant(new DataVariant::FormUrlencoded() ); + this->settings.addDataVariant(new DataVariant::MultipartFormData() ); + this->settings.addDataVariant(new DataVariant::TextPlain() ); + + ::gnutls_global_init(); + + return true; + } + + return false; + } + + void Server::clear() + { + this->controls.clear(); + + if (false == this->tls_data.empty() ) + { + for (auto &pair : this->tls_data) + { + std::tuple &data = pair.second; + + ::gnutls_certificate_free_credentials(std::get(data) ); + ::gnutls_priority_deinit(std::get(data) ); + } + } + + this->settings.clear(); + + if (false == this->modules.empty() ) + { + for (auto &module : this->modules) + { + module.close(); + } + + this->modules.empty(); + } + + ::gnutls_global_deinit(); + + Socket::Socket::Cleanup(); + } + + static bool tlsInit(const ServerApplicationSettings &app, std::tuple &data) + { + ::gnutls_certificate_credentials_t x509_cred; + + int ret = ::gnutls_certificate_allocate_credentials(&x509_cred); + + if (ret < 0) + { + std::cout << "Error [tls]: certificate credentials has not been allocated;" << std::endl; + + return false; + } + + if (false == app.chain_file.empty() ) + { + ret = ::gnutls_certificate_set_x509_trust_file(x509_cred, app.chain_file.c_str(), GNUTLS_X509_FMT_PEM); + + if (ret < 0) + { + std::cout << "Warning [tls]: (CA) chain file has not been accepted;" << std::endl; + } + } + + if (false == app.crl_file.empty() ) + { + ret = ::gnutls_certificate_set_x509_crl_file(x509_cred, app.crl_file.c_str(), GNUTLS_X509_FMT_PEM); + + if (ret < 0) + { + std::cout << "Warning [tls]: (CLR) clr file has not been accepted;" << std::endl; + } + } + + ret = ::gnutls_certificate_set_x509_key_file(x509_cred, app.cert_file.c_str(), app.key_file.c_str(), GNUTLS_X509_FMT_PEM); + + if (ret < 0) + { + std::cout << "Error [tls]: (CERT) cert file or/and (KEY) key file has not been accepted;" << std::endl; + + return false; + } + + if (false == app.stapling_file.empty() ) + { + ret = ::gnutls_certificate_set_ocsp_status_request_file(x509_cred, app.stapling_file.c_str(), 0); + + if (ret < 0) + { + std::cout << "Warning [tls]: (OCSP) stapling file has not been accepted;" << std::endl; + } + } + + ::gnutls_dh_params_t dh_params; + + ::gnutls_dh_params_init(&dh_params); + + if (app.dh_file.empty() ) + { + const unsigned int bits = ::gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_HIGH); + + ret = ::gnutls_dh_params_generate2(dh_params, bits); + } + else + { + std::ifstream dh_file(app.dh_file); + + if (dh_file) + { + const size_t max_file_size = 1024 * 1024; + + std::vector buf(max_file_size); + + dh_file.read(buf.data(), buf.size() ); + + gnutls_datum_t datum { + reinterpret_cast(buf.data() ), + static_cast(dh_file.gcount() ) + }; + + ret = ::gnutls_dh_params_import_pkcs3(dh_params, &datum, GNUTLS_X509_FMT_PEM); + } + else + { + ret = -1; + + std::cout << "Error [tls]: DH params file has not been opened;" << std::endl;; + } + + dh_file.close(); + } + + if (ret < 0) + { + ::gnutls_certificate_free_credentials(x509_cred); + + std::cout << "Error [tls]: DH params were not loaded;" << std::endl; + + return false; + } + + ::gnutls_certificate_set_dh_params(x509_cred, dh_params); + + ::gnutls_priority_t priority_cache; + + ret = ::gnutls_priority_init(&priority_cache, "NORMAL", nullptr); + + if (ret < 0) + { + ::gnutls_certificate_free_credentials(x509_cred); + + std::cout << "Error [tls]: priority cache cannot be init;" << std::endl; + + return false; + } + + data = std::tuple { x509_cred, priority_cache }; + + return true; + } + + bool Server::tryBindPort(const int port, std::unordered_set &ports) + { + // Only unique ports + if (ports.cend() != ports.find(port) ) + { + return false; + } + + Socket::Socket sock; + + if (false == sock.open() ) + { + std::cout << "Error: socket cannot be open; errno " << Socket::Socket::getLastError() << ";" << std::endl; + return false; + } + + if (false == sock.bind(port) ) + { + std::cout << "Error: port " << port << " cannot be bind; errno " << Socket::Socket::getLastError() << ";" << std::endl; + return false; + } + + if (false == sock.listen() ) + { + std::cout << "Error: socket " << port << " cannot be listen; errno " << Socket::Socket::getLastError() << ";" << std::endl; + return false; + } + + sock.nonblock(true); + + this->liseners.emplace_back(std::move(sock) ); + + ports.emplace(port); + + return true; + } + + void Server::initAppsPorts() + { + // Applications settings list + std::unordered_set applications; + // Get full applications settings list + this->settings.apps_tree.collectApplicationSettings(applications); + + // Bind ports set + std::unordered_set ports; + + // Open applications sockets + for (auto const &app : applications) + { + const std::unordered_set &tls = app->tls_ports; + + if (false == tls.empty() ) + { + std::tuple data; + + if (tlsInit(*app, data) ) + { + for (const int port : tls) + { + if (this->tryBindPort(port, ports) ) + { + this->tls_data.emplace(port, data); + } + } + } + } + + const std::unordered_set &list = app->ports; + + for (const int port : list) + { + this->tryBindPort(port, ports); + } + } + } + + int Server::run() + { + if (false == this->init() ) + { + return 0x10; + } + + this->initAppsPorts(); + + if (this->liseners.empty() ) + { + std::cout << "Error: any socket was not open;" << std::endl; + this->clear(); + return 0x20; + } + + Socket::List sockets_list; + + sockets_list.create(this->liseners.size() ); + + for (auto const &sock : this->liseners) + { + sockets_list.addSocket(sock); + } + + std::cout << "Log: launch server's cycle;" << std::endl << std::endl; + + constexpr size_t queue_max_length = 1024; + this->controls.eventNotFullQueue = new Utils::Event(true, true); + this->controls.eventProcessQueue = new Utils::Event(); + this->controls.eventUpdateModule = new Utils::Event(false, true); + + SocketsQueue sockets; + + this->controls.setProcess(); + + std::function serverCycleQueue = std::mem_fn(&Server::cycleQueue); + std::thread threadQueue(serverCycleQueue, this, std::ref(sockets) ); + + std::vector accept_sockets; + + // Cycle for receiving new connections + do + { + if (sockets_list.accept(accept_sockets) ) + { + sockets.lock(); + + for (size_t i = 0; i < accept_sockets.size(); ++i) + { + const Socket::Socket &sock = accept_sockets[i]; + + if (sock.is_open() ) + { + sock.nonblock(true); + sock.tcp_nodelay(true); + + sockets.emplace( + std::tuple { + sock, + nullptr + } + ); + } + } + + sockets.unlock(); + + this->controls.eventProcessQueue->notify(); + + if (sockets.size() >= queue_max_length) + { + this->controls.eventNotFullQueue->reset(); + } + + accept_sockets.clear(); + + this->controls.eventNotFullQueue->wait(); + } + } + while (this->controls.process_flag || this->controls.eventUpdateModule->notifed() ); + + this->controls.eventProcessQueue->notify(); + + threadQueue.join(); + + sockets_list.destroy(); + + if (false == this->liseners.empty() ) + { + for (Socket::Socket &sock : this->liseners) + { + sock.close(); + } + + this->liseners.clear(); + } + + this->clear(); + + std::cout << "Log: complete server's cycle;" << std::endl; + + return EXIT_SUCCESS; + } + + bool Server::get_start_args(const int argc, const char *argv[], struct server_start_args *st) + { + for (int i = 1; i < argc; ++i) + { + if (0 == ::strcmp(argv[i], "--start") ) + { + + } + else if (0 == ::strcmp(argv[i], "--force") ) + { + st->force = true; + } + else if (argv[i] == ::strstr(argv[i], "--config-path=") ) + { + st->config_path = std::string(argv[i] + sizeof("--config-path=") - 1); + } + else if (argv[i] == ::strstr(argv[i], "--server-name=") ) + { + st->server_name = std::string(argv[i] + sizeof("--server-name=") - 1); + } + else + { + std::cout << "Argument '" << argv[i] << "' can't be applied with --start;" << std::endl; + + return false; + } + } + + if (st->server_name.empty() ) + { + st->server_name = argv[0]; + } + + System::filterSharedMemoryName(st->server_name); + + return true; + } + + int Server::command_start(const int argc, const char *argv[]) + { + struct server_start_args st = {}; + + if (false == Server::get_start_args(argc, argv, &st) ) + { + return 0x1; + } + + if (false == st.config_path.empty() ) + { + if (false == System::changeCurrentDirectory(st.config_path) ) + { + std::cout << "Configuration path '" << st.config_path << "' has not been found;" << std::endl; + + return 0x2; + } + } + + if (st.force) + { + System::SharedMemory::destroy(st.server_name); + System::GlobalMutex::destory(st.server_name); + } + + System::GlobalMutex glob_mtx; + System::SharedMemory glob_mem; + + bool is_exists = false; + + if (glob_mtx.open(st.server_name) ) + { + glob_mtx.lock(); + + if (glob_mem.open(st.server_name) ) + { + System::native_processid_type pid = 0; + + if (glob_mem.read(&pid, sizeof(pid) ) ) + { + is_exists = System::isProcessExists(pid); + } + } + + glob_mtx.unlock(); + } + + if (is_exists) + { + std::cout << "Server instance with the name '" << st.server_name << "' is already running;" << std::endl; + + return 0x3; + } + + if (false == glob_mtx.open(st.server_name) ) + { + if (false == glob_mtx.create(st.server_name) ) + { + std::cout << "Global mutex could not been created;" << std::endl; + + return 0x4; + } + } + + glob_mtx.lock(); + + if (false == glob_mem.open(st.server_name) ) + { + if (false == glob_mem.create(st.server_name, sizeof(System::native_processid_type) ) ) + { + glob_mtx.unlock(); + + std::cout << "Shared memory could not been allocated;" << std::endl; + + return 0x5; + } + } + + System::native_processid_type pid = System::getProcessId(); + + if (false == glob_mem.write(&pid, sizeof(pid) ) ) + { + glob_mem.destroy(); + glob_mtx.unlock(); + + std::cout << "Writing data to shared memory has failed;" << std::endl; + + return 0x6; + } + + glob_mtx.unlock(); + + int code = EXIT_FAILURE; + + do + { + this->controls.setProcess(false); + this->controls.setRestart(false); + + code = this->run(); + } + while (this->controls.process_flag || this->controls.restart_flag); + + glob_mem.destroy(); + glob_mtx.destory(); + + return code; + } + + System::native_processid_type Server::getServerProcessId(const std::string &serverName) + { + System::native_processid_type pid = 0; + + System::GlobalMutex glob_mtx; + + if (glob_mtx.open(serverName) ) + { + System::SharedMemory glob_mem; + + glob_mtx.lock(); + + if (glob_mem.open(serverName) ) + { + glob_mem.read(&pid, sizeof(pid) ); + } + + glob_mtx.unlock(); + } + + return pid; + } + + int Server::command_help(const int argc, const char *argv[]) const + { + std::cout << std::left << "Available arguments:" << std::endl + << std::setw(4) << ' ' << std::setw(26) << "--start" << "Start http server" << std::endl + << std::setw(8) << ' ' << std::setw(22) << "[options]" << std::endl + << std::setw(8) << ' ' << std::setw(22) << "--force" << "Forcibly start http server (ignore existing instance)" << std::endl + << std::setw(8) << ' ' << std::setw(22) << "--config-path=" << "Path to directory with configuration files" << std::endl + << std::endl + << std::setw(4) << ' ' << std::setw(26) << "--restart" << "Restart http server" << std::endl + << std::setw(4) << ' ' << std::setw(26) << "--update-module" << "Update applications modules" << std::endl + << std::setw(4) << ' ' << std::setw(26) << "--kill" << "Shutdown http server" << std::endl + << std::setw(4) << ' ' << std::setw(26) << "--help" << "This help" << std::endl + << std::endl<< "Optional arguments:" << std::endl + << std::setw(4) << ' ' << std::setw(26) << "--server-name=" << "Name of server instance" << std::endl; + + return EXIT_SUCCESS; + } + + static std::string get_server_name(const int argc, const char *argv[]) + { + std::string server_name; + + for (int i = 1; i < argc; ++i) + { + if (argv[i] == ::strstr(argv[i], "--server-name=") ) + { + server_name = std::string(argv[i] + sizeof("--server-name=") - 1); + break; + } + } + + if (server_name.empty() ) + { + server_name = argv[0]; + } + + System::filterSharedMemoryName(server_name); + + return server_name; + } + + int Server::command_restart(const int argc, const char *argv[]) const + { + const System::native_processid_type pid = Server::getServerProcessId(get_server_name(argc, argv) ); + + if (1 < pid && System::sendSignal(pid, SIGUSR1) ) + { + return EXIT_SUCCESS; + } + + return EXIT_FAILURE; + } + + int Server::command_terminate(const int argc, const char *argv[]) const + { + const System::native_processid_type pid = Server::getServerProcessId(get_server_name(argc, argv) ); + + if (1 < pid && System::sendSignal(pid, SIGTERM) ) + { + return EXIT_SUCCESS; + } + + return EXIT_FAILURE; + } + + int Server::command_update_module(const int argc, const char *argv[]) const + { + const System::native_processid_type pid = Server::getServerProcessId(get_server_name(argc, argv) ); + + if (1 < pid && System::sendSignal(pid, SIGUSR2) ) + { + return EXIT_SUCCESS; + } + + return EXIT_FAILURE; + } +}; diff --git a/src/server/Server.h b/src/server/Server.h new file mode 100644 index 0000000..4218ad8 --- /dev/null +++ b/src/server/Server.h @@ -0,0 +1,62 @@ +#pragma once + +#include "../socket/Adapter.h" +#include "../system/Module.h" + +#include "ServerControls.h" +#include "ServerSettings.h" +#include "SocketsQueue.h" + +#include + +namespace HttpServer +{ + class Server + { + protected: + ServerSettings settings; + + std::unordered_map > tls_data; + // std::unordered_map > > http_streams; + + std::vector modules; + std::vector liseners; + + mutable std::atomic_size_t threads_working_count; + System::CachePadding padding_1; + + public: + mutable ServerControls controls; + + protected: + int cycleQueue(SocketsQueue &sockets); + + void threadRequestProc(Socket::Adapter &sock, SocketsQueue &sockets, Http2::IncStream *stream) const; + + void threadRequestCycle(SocketsQueue &sockets, Utils::Event &eventThreadCycle) const; + + bool tryBindPort(const int port, std::unordered_set &ports); + void initAppsPorts(); + + bool init(); + int run(); + void clear(); + + static System::native_processid_type getServerProcessId(const std::string &serverName); + + void updateModules(); + bool updateModule(System::Module &module, std::unordered_set &applications, const size_t moduleIndex); + + private: + static bool get_start_args(const int argc, const char *argv[], struct server_start_args *st); + + public: + Server() = default; + + int command_help(const int argc, const char *argv[]) const; + int command_start(const int argc, const char *argv[]); + int command_restart(const int argc, const char *argv[]) const; + int command_terminate(const int argc, const char *argv[]) const; + int command_update_module(const int argc, const char *argv[]) const; + }; +}; diff --git a/src/ServerApplicationSettings.h b/src/server/ServerApplicationSettings.h similarity index 73% rename from src/ServerApplicationSettings.h rename to src/server/ServerApplicationSettings.h index 7d61acc..7d2cb38 100644 --- a/src/ServerApplicationSettings.h +++ b/src/server/ServerApplicationSettings.h @@ -1,8 +1,7 @@ #pragma once -#include "ServerRequest.h" -#include "ServerResponse.h" -#include "RawData.h" +#include "../transfer/AppRequest.h" +#include "../transfer/AppResponse.h" #include #include @@ -30,9 +29,9 @@ namespace HttpServer std::string stapling_file; std::string dh_file; - std::function application_call; - std::function application_clear; + std::function application_call; + std::function application_clear; std::function application_init; std::function application_final; }; -}; \ No newline at end of file +}; diff --git a/src/ServerApplicationsTree.cpp b/src/server/ServerApplicationsTree.cpp similarity index 75% rename from src/ServerApplicationsTree.cpp rename to src/server/ServerApplicationsTree.cpp index e548925..250e432 100644 --- a/src/ServerApplicationsTree.cpp +++ b/src/server/ServerApplicationsTree.cpp @@ -3,14 +3,19 @@ namespace HttpServer { - ServerApplicationsTree::ServerApplicationsTree(): app_sets(nullptr) + ServerApplicationsTree::ServerApplicationsTree() noexcept : app_sets(nullptr) { } - ServerApplicationsTree::~ServerApplicationsTree() + ServerApplicationsTree::~ServerApplicationsTree() noexcept { - clear(); + this->clear(); + } + + bool ServerApplicationsTree::empty() const noexcept + { + return this->list.empty(); } void ServerApplicationsTree::addApplication(const std::string &name, ServerApplicationSettings *sets) @@ -46,31 +51,31 @@ namespace HttpServer name_parts.emplace_back(name); } - addApplication(name_parts, sets); + this->addApplication(name_parts, sets); } void ServerApplicationsTree::addApplication(std::vector &nameParts, ServerApplicationSettings *sets) { if (nameParts.empty() ) { - app_sets = sets; + this->app_sets = sets; } else { std::string &part = nameParts.back(); - auto it = list.find(part); + auto it = this->list.find(part); ServerApplicationsTree *sub; - if (list.cend() != it) + if (this->list.cend() != it) { sub = it->second; } else { sub = new ServerApplicationsTree(); - list.emplace(std::move(part), sub); + this->list.emplace(std::move(part), sub); } nameParts.pop_back(); @@ -105,14 +110,14 @@ namespace HttpServer name_parts.emplace_back(name); } - return find(name_parts); + return this->find(name_parts); } const ServerApplicationSettings *ServerApplicationsTree::find(std::vector &nameParts) const { if (nameParts.empty() ) { - return app_sets; + return this->app_sets; } else { @@ -120,15 +125,15 @@ namespace HttpServer nameParts.pop_back(); - auto it = list.find(part); + auto it = this->list.find(part); - if (list.cend() == it) + if (this->list.cend() == it) { - it = list.find("*"); + it = this->list.find("*"); - if (list.end() != it) + if (this->list.end() != it) { - return app_sets; + return this->app_sets; } } else @@ -142,7 +147,7 @@ namespace HttpServer void ServerApplicationsTree::collectApplicationSettings(std::unordered_set &set) const { - for (auto &node : list) + for (auto &node : this->list) { const ServerApplicationsTree *tree = node.second; @@ -155,16 +160,16 @@ namespace HttpServer } } - void ServerApplicationsTree::clear() + void ServerApplicationsTree::clear() noexcept { - if (false == list.empty() ) + if (false == this->list.empty() ) { - for (auto &it : list) + for (auto &it : this->list) { delete it.second; } - list.clear(); + this->list.clear(); } } -}; \ No newline at end of file +}; diff --git a/src/ServerApplicationsTree.h b/src/server/ServerApplicationsTree.h similarity index 84% rename from src/ServerApplicationsTree.h rename to src/server/ServerApplicationsTree.h index 84ce430..6fe2b24 100644 --- a/src/ServerApplicationsTree.h +++ b/src/server/ServerApplicationsTree.h @@ -16,10 +16,10 @@ namespace HttpServer ServerApplicationSettings *app_sets; public: - ServerApplicationsTree(); - ~ServerApplicationsTree(); + ServerApplicationsTree() noexcept; + ~ServerApplicationsTree() noexcept; - inline bool empty() const { return list.empty(); } + bool empty() const noexcept; void addApplication(const std::string &name, ServerApplicationSettings *sets); void addApplication(std::vector &nameParts, ServerApplicationSettings *sets); @@ -29,6 +29,6 @@ namespace HttpServer void collectApplicationSettings(std::unordered_set &set) const; - void clear(); + void clear() noexcept; }; -}; \ No newline at end of file +}; diff --git a/src/server/ServerControls.cpp b/src/server/ServerControls.cpp new file mode 100644 index 0000000..6bc57ed --- /dev/null +++ b/src/server/ServerControls.cpp @@ -0,0 +1,75 @@ + +#include "ServerControls.h" + +namespace HttpServer +{ + ServerControls::ServerControls() + : eventProcessQueue(nullptr), eventNotFullQueue(nullptr), eventUpdateModule(nullptr) + { + + } + + ServerControls::~ServerControls() + { + this->clear(); + } + + void ServerControls::clear() + { + if (this->eventNotFullQueue) + { + delete this->eventNotFullQueue; + this->eventNotFullQueue = nullptr; + } + + if (this->eventProcessQueue) + { + delete this->eventProcessQueue; + this->eventProcessQueue = nullptr; + } + + if (this->eventUpdateModule) + { + delete this->eventUpdateModule; + this->eventUpdateModule = nullptr; + } + } + + void ServerControls::setProcess(const bool flag) + { + this->process_flag = flag; + } + + void ServerControls::stopProcess() + { + this->process_flag = false; + + if (this->eventNotFullQueue) + { + this->eventNotFullQueue->notify(); + } + + this->setProcessQueue(); + } + + void ServerControls::setRestart(const bool flag) + { + this->restart_flag = flag; + } + + void ServerControls::setUpdateModule() + { + if (this->eventUpdateModule) + { + this->eventUpdateModule->notify(); + } + } + + void ServerControls::setProcessQueue() + { + if (this->eventProcessQueue) + { + this->eventProcessQueue->notify(); + } + } +}; diff --git a/src/server/ServerControls.h b/src/server/ServerControls.h new file mode 100644 index 0000000..ab811f0 --- /dev/null +++ b/src/server/ServerControls.h @@ -0,0 +1,37 @@ +#pragma once + +#include "../utils/Event.h" +#include "../system/Cache.h" + +#include +#include + +namespace HttpServer +{ + class ServerControls + { + public: + Utils::Event *eventProcessQueue; + Utils::Event *eventNotFullQueue; + Utils::Event *eventUpdateModule; + + System::CachePaddingSize padding_1; + + // Флаг, означающий - активированы ли главные циклы сервера + // (с помощью этого флага можно деактивировать циклы, чтобы завершить работу сервера) + sig_atomic_t process_flag; + sig_atomic_t restart_flag; + + public: + ServerControls(); + ~ServerControls(); + + void clear(); + + void setProcess(const bool flag = true); + void stopProcess(); + void setRestart(const bool flag = true); + void setUpdateModule(); + void setProcessQueue(); + }; +}; diff --git a/src/server/ServerSettings.cpp b/src/server/ServerSettings.cpp new file mode 100644 index 0000000..7890fb6 --- /dev/null +++ b/src/server/ServerSettings.cpp @@ -0,0 +1,61 @@ + +#include "ServerSettings.h" + +#include + +namespace HttpServer +{ + ServerSettings::~ServerSettings() + { + this->clear(); + } + + void ServerSettings::addDataVariant(DataVariant::Abstract *dataVariant) + { + this->variants.emplace(dataVariant->getName(), dataVariant); + } + + void ServerSettings::clear() + { + if (false == this->variants.empty() ) + { + for (auto &variant : this->variants) + { + delete variant.second; + } + + this->variants.clear(); + } + + if (false == this->apps_tree.empty() ) + { + std::unordered_set applications; + this->apps_tree.collectApplicationSettings(applications); + + for (auto &app : applications) + { + try + { + if (app->application_final) + { + app->application_final(); + } + } + catch (std::exception &exc) + { + std::cout << "Warning: the error of the application's finalize '" << app->server_module << "':" << exc.what() << std::endl; + } + + delete app; + } + + applications.clear(); + this->apps_tree.clear(); + } + + if (false == this->global.empty() ) + { + this->global.clear(); + } + } +}; diff --git a/src/server/ServerSettings.h b/src/server/ServerSettings.h new file mode 100644 index 0000000..2ef64a2 --- /dev/null +++ b/src/server/ServerSettings.h @@ -0,0 +1,25 @@ +#pragma once + +#include "data-variant/Abstract.h" + +#include "ServerApplicationsTree.h" + +namespace HttpServer +{ + class ServerSettings + { + public: + std::unordered_map global; + std::unordered_map variants; + std::unordered_map mimes_types; + ServerApplicationsTree apps_tree; + + public: + ServerSettings() = default; + ~ServerSettings(); + + void addDataVariant(DataVariant::Abstract *dataVariant); + + void clear(); + }; +}; diff --git a/src/ServerStructuresArguments.h b/src/server/ServerStructuresArguments.h similarity index 98% rename from src/ServerStructuresArguments.h rename to src/server/ServerStructuresArguments.h index 6877ab0..0e10b8b 100644 --- a/src/ServerStructuresArguments.h +++ b/src/server/ServerStructuresArguments.h @@ -10,4 +10,4 @@ namespace HttpServer std::string config_path; bool force; }; -}; \ No newline at end of file +}; diff --git a/src/server/SocketsQueue.h b/src/server/SocketsQueue.h new file mode 100644 index 0000000..ff6ec83 --- /dev/null +++ b/src/server/SocketsQueue.h @@ -0,0 +1,20 @@ +#pragma once + +#include "../socket/Socket.h" +#include "../system/Cache.h" + +#include "../transfer/http2/Http2.h" + +#include +#include + +namespace HttpServer +{ + class SocketsQueue : + public std::queue >, + System::CachePadding > >, + public std::mutex + { + + }; +}; diff --git a/src/ConfigParser.cpp b/src/server/config/ConfigParser.cpp similarity index 90% rename from src/ConfigParser.cpp rename to src/server/config/ConfigParser.cpp index 7f65321..0767cd8 100644 --- a/src/ConfigParser.cpp +++ b/src/server/config/ConfigParser.cpp @@ -1,8 +1,8 @@ #include "ConfigParser.h" -#include "ServerApplicationSettings.h" -#include "Utils.h" +#include "../ServerApplicationSettings.h" +#include "../../utils/Utils.h" #include #include @@ -20,7 +20,7 @@ namespace HttpServer { file.close(); - std::cout << "Error: " << fileName << " - cannot be open;" << std::endl; + std::cout << "Error: file " << fileName << " cannot be open;" << std::endl; return false; } @@ -29,13 +29,13 @@ namespace HttpServer std::streamsize file_size = file.tellg(); file.seekg(0, std::ifstream::beg); - const std::streamsize file_size_max = 2 * 1024 * 1024; + constexpr std::streamsize file_size_max = 2 * 1024 * 1024; if (file_size_max < file_size) { file.close(); - std::cout << "Error: " << fileName << " - is too large; max include file size = " << file_size_max << " bytes;" << std::endl; + std::cout << "Error: file " << fileName << " is too large; max include file size = " << file_size_max << " bytes;" << std::endl; return false; } @@ -59,7 +59,7 @@ namespace HttpServer bool ConfigParser::addApplication( const std::unordered_multimap &app, const ServerApplicationDefaultSettings &defaults, - std::vector &modules, + std::vector &modules, ServerApplicationsTree &apps_tree ) { @@ -212,7 +212,7 @@ namespace HttpServer // TODO: get module realpath - Module module(it_module->second); + System::Module module(it_module->second); if (false == module.is_open() ) { @@ -228,7 +228,7 @@ namespace HttpServer return false; } - std::function app_call = reinterpret_cast(addr); + std::function app_call = reinterpret_cast(addr); if ( ! app_call) { @@ -242,7 +242,7 @@ namespace HttpServer return false; } - std::function app_clear = reinterpret_cast(addr); + std::function app_clear = reinterpret_cast(addr); std::function app_init = std::function(); @@ -494,13 +494,7 @@ namespace HttpServer /** * Config - parse */ - bool ConfigParser::loadConfig( - const std::string &conf_file_name, - std::unordered_map &settings, - std::unordered_map &mimes_types, - std::vector &modules, - ServerApplicationsTree &apps_tree - ) + bool ConfigParser::loadConfig(const std::string &conf_file_name, ServerSettings &settings, std::vector &modules) { std::string str_buf; @@ -509,6 +503,10 @@ namespace HttpServer return false; } + std::unordered_map &global = settings.global; + std::unordered_map &mimes_types = settings.mimes_types; + ServerApplicationsTree &apps_tree = settings.apps_tree; + std::vector > applications; const std::string whitespace(" \t\n\v\f\r"); @@ -543,7 +541,7 @@ namespace HttpServer } else { - settings.emplace(std::move(param_name), std::move(param_value) ); + global.emplace(std::move(param_name), std::move(param_value) ); } } else // if comment line @@ -659,9 +657,9 @@ namespace HttpServer end_pos = str_buf.find(';', cur_pos); } - auto const it_mimes = settings.find("mimes"); + auto const it_mimes = global.find("mimes"); - if (settings.cend() != it_mimes) + if (global.cend() != it_mimes) { this->parseMimes(it_mimes->second, mimes_types); } @@ -672,13 +670,13 @@ namespace HttpServer if (false == applications.empty() ) { - auto const it_default_temp_dir = settings.find("default_temp_dir"); + auto const it_default_temp_dir = global.find("default_temp_dir"); - const std::string default_temp_dir = settings.cend() != it_default_temp_dir ? it_default_temp_dir->second : System::getTempDir(); + const std::string default_temp_dir = global.cend() != it_default_temp_dir ? it_default_temp_dir->second : System::getTempDir(); - auto const it_default_request_max_size = settings.find("request_max_size"); + auto const it_default_request_max_size = global.find("request_max_size"); - const size_t default_request_max_size = settings.cend() != it_default_request_max_size ? std::strtoull(it_default_request_max_size->second.c_str(), nullptr, 10) : 0; + const size_t default_request_max_size = global.cend() != it_default_request_max_size ? std::strtoull(it_default_request_max_size->second.c_str(), nullptr, 10) : 0; ServerApplicationDefaultSettings defaults { default_temp_dir, @@ -698,4 +696,4 @@ namespace HttpServer return true; } -}; \ No newline at end of file +}; diff --git a/src/ConfigParser.h b/src/server/config/ConfigParser.h similarity index 56% rename from src/ConfigParser.h rename to src/server/config/ConfigParser.h index 07af9c9..5614237 100644 --- a/src/ConfigParser.h +++ b/src/server/config/ConfigParser.h @@ -1,10 +1,8 @@ #pragma once -#include "ServerApplicationDefaultSettings.h" -#include "ServerApplicationsTree.h" -#include "Module.h" +#include "../ServerSettings.h" +#include "../../system/Module.h" -#include #include namespace HttpServer @@ -12,24 +10,24 @@ namespace HttpServer class ConfigParser { private: + struct ServerApplicationDefaultSettings + { + std::string temp_dir; + size_t request_max_size; + }; + static bool includeConfigFile(const std::string &fileName, std::string &strBuf, const size_t offset = 0); static bool addApplication( const std::unordered_multimap &app, const ServerApplicationDefaultSettings &defaults, - std::vector &modules, + std::vector &modules, ServerApplicationsTree &apps_tree ); static bool parseMimes(const std::string &fileName, std::unordered_map &mimes_types); public: - bool loadConfig( - const std::string &conf, - std::unordered_map &settings, - std::unordered_map &mimes_types, - std::vector &modules, - ServerApplicationsTree &apps_tree - ); + bool loadConfig(const std::string &conf, ServerSettings &settings, std::vector &modules); }; -}; \ No newline at end of file +}; diff --git a/src/server/data-variant/Abstract.cpp b/src/server/data-variant/Abstract.cpp new file mode 100644 index 0000000..5a13e4a --- /dev/null +++ b/src/server/data-variant/Abstract.cpp @@ -0,0 +1,20 @@ + +#include "Abstract.h" + +namespace DataVariant +{ + const std::string &Abstract::getName() const noexcept + { + return this->data_variant_name; + } + + void *Abstract::createStateStruct(const Transfer::request_data *rd, const std::unordered_map &contentParams) const + { + return nullptr; + } + + void Abstract::destroyStateStruct(void *st) const noexcept + { + + } +}; diff --git a/src/server/data-variant/Abstract.h b/src/server/data-variant/Abstract.h new file mode 100644 index 0000000..0ec2e0a --- /dev/null +++ b/src/server/data-variant/Abstract.h @@ -0,0 +1,40 @@ +#pragma once + +#include "../../socket/Adapter.h" +#include "../Request.h" + +namespace DataVariant +{ + struct DataReceiver; + + class Abstract + { + protected: + std::string data_variant_name; + + public: + const std::string &getName() const noexcept; + + public: + /** + * virtual destructor + */ + virtual ~Abstract() noexcept = default; + + virtual void *createStateStruct(const Transfer::request_data *rd, const std::unordered_map &contentParams) const; + + virtual bool parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const = 0; + + virtual void destroyStateStruct(void *st) const noexcept; + }; + + struct DataReceiver + { + const Abstract *data_variant; + void *ss; + size_t full_size; + size_t recv_total; + size_t left; + void *reserved; + }; +}; diff --git a/src/server/data-variant/FormUrlencoded.cpp b/src/server/data-variant/FormUrlencoded.cpp new file mode 100644 index 0000000..5535b14 --- /dev/null +++ b/src/server/data-variant/FormUrlencoded.cpp @@ -0,0 +1,63 @@ + +#include "FormUrlencoded.h" + +#include "../../utils/Utils.h" + +namespace DataVariant +{ + FormUrlencoded::FormUrlencoded() noexcept + { + this->data_variant_name = "application/x-www-form-urlencoded"; + } + + bool FormUrlencoded::parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const + { + if (buf.empty() ) + { + return 0 == dr->full_size || dr->full_size != dr->recv_total; + } + + for (size_t var_pos = 0, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) + { + // Поиск следующего параметра + var_end = buf.find('&', var_pos); + + if (std::string::npos == var_end) + { + if (dr->full_size != dr->recv_total) + { + dr->left = buf.size() - var_pos; + + return true; + } + } + + // Поиск значения параметра + size_t delimiter = buf.find('=', var_pos); + + if (delimiter >= var_end) + { + // Получить имя параметра + std::string var_name = Utils::urlDecode(buf.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos) ); + + // Сохранить параметр с пустым значением + rd->incoming_data.emplace(std::move(var_name), std::string() ); + } + else + { + // Получить имя параметра + std::string var_name = Utils::urlDecode(buf.substr(var_pos, delimiter - var_pos) ); + + ++delimiter; + + // Получить значение параметра + std::string var_value = Utils::urlDecode(buf.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos) ); + + // Сохранить параметр и значение + rd->incoming_data.emplace(std::move(var_name), std::move(var_value) ); + } + } + + return true; + } +}; diff --git a/src/server/data-variant/FormUrlencoded.h b/src/server/data-variant/FormUrlencoded.h new file mode 100644 index 0000000..c52b575 --- /dev/null +++ b/src/server/data-variant/FormUrlencoded.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Abstract.h" + +namespace DataVariant +{ + class FormUrlencoded: public Abstract + { + public: + FormUrlencoded() noexcept; + + public: + virtual bool parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const override; + }; +}; diff --git a/src/server/data-variant/MultipartFormData.cpp b/src/server/data-variant/MultipartFormData.cpp new file mode 100644 index 0000000..2c24504 --- /dev/null +++ b/src/server/data-variant/MultipartFormData.cpp @@ -0,0 +1,411 @@ + +#include "../../utils/Utils.h" +#include "MultipartFormData.h" + +#include + +namespace DataVariant +{ + MultipartFormData::MultipartFormData() noexcept + { + this->data_variant_name = "multipart/form-data"; + } + + enum class ParsingState : uint8_t + { + INITIALIZATION = 0, + FIND_DATA_BLOCK, + GET_DATA_BLOCK_TYPE, + COPY_DATA_BLOCK, + SAVE_DATA_BLOCK, + }; + + enum class BlockType : uint8_t + { + UNKNOWN = 0, + DATA, + FILE, + }; + + struct StateMultipartFormData + { + std::string block_name; + std::string block_value; + std::string file_tmp_name; + std::string file_name; + std::string file_type; + std::ofstream file; + std::string boundary; + ParsingState state; + BlockType block_type; + }; + + void *MultipartFormData::createStateStruct(const Transfer::request_data *rd, const std::unordered_map &contentParams) const + { + std::string boundary; + + auto const it = contentParams.find("boundary"); + + if (contentParams.cend() != it) + { + boundary = it->second; + } + + return new StateMultipartFormData { + std::string(), std::string(), std::string(), std::string(), std::string(), std::ofstream(), + std::move(boundary), ParsingState::INITIALIZATION, BlockType::UNKNOWN + }; + } + + void MultipartFormData::destroyStateStruct(void *st) const noexcept + { + delete reinterpret_cast(st); + } + + static std::unordered_map parseHeader(const std::string &buf, size_t cur, const size_t end) + { + const std::string nl("\r\n"); + + std::unordered_map headers; + + for (size_t line_end = buf.find(nl.data(), cur); cur < end; line_end = buf.find(nl.data(), cur) ) + { + size_t delimiter = buf.find(':', cur); + + if (std::string::npos == delimiter || delimiter > line_end) + { + std::string header_name = buf.substr(cur, line_end - cur); + Utils::trim(header_name); + Utils::toLower(header_name); + headers.emplace(std::move(header_name), std::string() ); + } + else + { + std::string header_name = buf.substr(cur, delimiter - cur); + Utils::trim(header_name); + Utils::toLower(header_name); + + ++delimiter; + + std::string header_value = buf.substr(delimiter, line_end - delimiter); + Utils::trim(header_value); + + headers.emplace(std::move(header_name), std::move(header_value) ); + } + + // Перейти к следующему заголовку + cur = line_end + nl.length(); + } + + return headers; + } + + static std::unordered_map parseMainHeaderParams(const std::string &header) + { + // Разобрать значение заголовка данных на параметры + std::unordered_map header_params; + + size_t delimiter = header.find(';'); + + if (std::string::npos == delimiter) + { + return header_params; + } + + std::string content_disposition(header.substr(0, delimiter) ); + Utils::trim(content_disposition); + + // Проверить соответствие указанного формата + if ("form-data" != content_disposition) + { + return header_params; + } + + // Получить параметры блока данных + for (size_t cur = delimiter + 1, end; std::string::npos != cur; cur = end) + { + end = header.find(';', cur); + delimiter = header.find('=', cur); + + if (std::string::npos == delimiter || delimiter > end) + { + std::string param_name = header.substr(cur, (std::string::npos != end) ? end - cur: std::string::npos); + Utils::trim(param_name); + Utils::toLower(param_name); + header_params.emplace(std::move(param_name), std::string() ); + } + else + { + std::string param_name = header.substr(cur, delimiter - cur); + Utils::trim(param_name); + Utils::toLower(param_name); + + ++delimiter; + + delimiter = header.find('"', delimiter); + + if (std::string::npos == delimiter) + { + end = header.find(';', cur); + + std::string param_value = header.substr(delimiter, (std::string::npos != end) ? end - delimiter : std::string::npos); + Utils::trim(param_value); + + header_params.emplace(std::move(param_name), std::move(param_value) ); + } + else + { + ++delimiter; + + cur = header.find('"', delimiter); + end = header.find(';', cur); + + std::string param_value = header.substr(delimiter, (std::string::npos != cur) ? cur - delimiter : std::string::npos); + + header_params.emplace(std::move(param_name), std::move(param_value) ); + } + } + + if (std::string::npos != end) + { + ++end; + } + } + + return header_params; + } + + bool MultipartFormData::parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const + { + StateMultipartFormData *ss = reinterpret_cast(dr->ss); + + size_t cur = 0; + + while (cur < buf.size() ) + { + switch (ss->state) + { + case ParsingState::INITIALIZATION: + { + if (ss->boundary.empty() ) + { + return false; + } + + const std::string data_end("--" + ss->boundary + "--\r\n"); + + if (buf.size() < data_end.length() ) + { + dr->left = buf.size(); + + return dr->full_size != dr->recv_total; + } + + if (0 == buf.find(data_end) ) + { + return dr->full_size == data_end.length() && dr->full_size == dr->recv_total; + } + + const std::string first_block("--" + ss->boundary); + + cur = buf.find(first_block); + + if (0 != cur) + { + return false; + } + + cur += first_block.length() + 2; + + ss->state = ParsingState::GET_DATA_BLOCK_TYPE; + + break; + } + + case ParsingState::FIND_DATA_BLOCK: + { + dr->left = buf.size() - cur; + + const std::string data_end("\r\n--" + ss->boundary + "--\r\n"); + + if (data_end.length() > dr->left) + { + return dr->full_size != dr->recv_total; + } + + const size_t end = buf.find(data_end, cur); + + if (end == cur) + { + dr->left -= data_end.length(); + + return dr->full_size == dr->recv_total; + } + + const std::string block_delimiter("\r\n--" + ss->boundary); + + cur = buf.find(block_delimiter, cur); + + if (std::string::npos == cur) + { + return dr->full_size != dr->recv_total; + } + + cur += block_delimiter.length() + 2; + + ss->state = ParsingState::GET_DATA_BLOCK_TYPE; + + // break; + } + + case ParsingState::GET_DATA_BLOCK_TYPE: + { + const size_t end = buf.find("\r\n\r\n", cur); + + if (std::string::npos == end) + { + dr->left = buf.size() - cur; + + return dr->full_size != dr->recv_total; + } + + // Разобрать заголовки блока данных + const std::unordered_map headers = parseHeader(buf, cur, end); + + // Определить параметры блока данных + auto const it = headers.find("content-disposition"); + + // Если заголовок не определён + if (headers.cend() == it) + { + return false; + } + + const std::unordered_map header_params = parseMainHeaderParams(it->second); + + // Поиск имени блока данных + auto const it_name = header_params.find("name"); + + if (header_params.cend() == it_name) + { + return false; + } + + ss->block_name = it_name->second; + + auto const it_filename = header_params.find("filename"); + + ss->block_type = header_params.cend() == it_filename ? BlockType::DATA : BlockType::FILE; + + if (BlockType::FILE == ss->block_type) + { + ss->file_name = it_filename->second; + + // Найти тип файла + auto const it_filetype = headers.find("content-type"); + + if (headers.cend() != it_filetype) + { + ss->file_type = it_filetype->second; + } + + // Сгенерировать уникальное имя + ss->file_tmp_name = System::getTempDir() + Utils::getUniqueName(); + + // Создать файл + ss->file.open(ss->file_tmp_name, std::ofstream::trunc | std::ofstream::binary); + + if (false == ss->file.is_open() ) + { + return false; + } + } + + // Перейти к данным + cur = end + 4; + + ss->state = ParsingState::COPY_DATA_BLOCK; + + // break; + } + + case ParsingState::COPY_DATA_BLOCK: + { + const std::string block_delimiter("\r\n--" + ss->boundary); + + // Поиск конца блока данных (возможное начало следующего блока) + const size_t block_end = buf.find(block_delimiter, cur); + + const size_t end = (std::string::npos == block_end) ? buf.size() - block_delimiter.length() : block_end; + + switch (ss->block_type) + { + case BlockType::DATA: + { + ss->block_value.append(buf.cbegin() + cur, buf.cbegin() + end); + + break; + } + + case BlockType::FILE: + { + ss->file.write(&buf[cur], end - cur); + + break; + } + + default: + return false; + } + + if (std::string::npos == block_end) + { + dr->left = buf.size() - end; + + return dr->full_size != dr->recv_total; + } + + cur = end; + + ss->state = ParsingState::SAVE_DATA_BLOCK; + + // break; + } + + case ParsingState::SAVE_DATA_BLOCK: + { + switch (ss->block_type) + { + case BlockType::DATA: + { + rd->incoming_data.emplace(std::move(ss->block_name), std::move(ss->block_value) ); + + break; + } + + case BlockType::FILE: + { + rd->incoming_files.emplace(std::move(ss->block_name), Transfer::FileIncoming(std::move(ss->file_tmp_name), std::move(ss->file_name), std::move(ss->file_type), ss->file.tellp() ) ); + + ss->file.close(); + + break; + } + + default: + return false; + } + + ss->state = ParsingState::FIND_DATA_BLOCK; + + break; + } + + default: + return false; + } + } + + return dr->full_size != dr->recv_total; + } +}; diff --git a/src/server/data-variant/MultipartFormData.h b/src/server/data-variant/MultipartFormData.h new file mode 100644 index 0000000..65e9071 --- /dev/null +++ b/src/server/data-variant/MultipartFormData.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Abstract.h" + +namespace DataVariant +{ + class MultipartFormData: public Abstract + { + public: + MultipartFormData() noexcept; + + public: + virtual void *createStateStruct(const Transfer::request_data *rd, const std::unordered_map &contentParams) const override; + + virtual bool parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const override; + + virtual void destroyStateStruct(void *st) const noexcept override; + }; +}; diff --git a/src/server/data-variant/TextPlain.cpp b/src/server/data-variant/TextPlain.cpp new file mode 100644 index 0000000..1f4333c --- /dev/null +++ b/src/server/data-variant/TextPlain.cpp @@ -0,0 +1,61 @@ + +#include "TextPlain.h" + +namespace DataVariant +{ + TextPlain::TextPlain() noexcept + { + this->data_variant_name = "text/plain"; + } + + bool TextPlain::parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const + { + if (buf.empty() ) + { + return 0 == dr->full_size || dr->full_size != dr->recv_total; + } + + for (size_t var_pos = 0, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) + { + // Поиск следующего параметра + var_end = buf.find('&', var_pos); + + if (std::string::npos == var_end) + { + if (dr->full_size != dr->recv_total) + { + dr->left = buf.size() - var_pos; + + return true; + } + } + + // Поиск значения параметра + size_t delimiter = buf.find('=', var_pos); + + if (delimiter >= var_end) + { + // Получить имя параметра + std::string var_name = buf.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos); + + // Сохранить параметр с пустым значением + rd->incoming_data.emplace(std::move(var_name), std::string() ); + } + else + { + // Получить имя параметра + std::string var_name = buf.substr(var_pos, delimiter - var_pos); + + ++delimiter; + + // Получить значение параметра + std::string var_value = buf.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos); + + // Сохранить параметр и значение + rd->incoming_data.emplace(std::move(var_name), std::move(var_value) ); + } + } + + return true; + } +}; diff --git a/src/server/data-variant/TextPlain.h b/src/server/data-variant/TextPlain.h new file mode 100644 index 0000000..8d98766 --- /dev/null +++ b/src/server/data-variant/TextPlain.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Abstract.h" + +namespace DataVariant +{ + class TextPlain: public Abstract + { + public: + TextPlain() noexcept; + + public: + virtual bool parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const override; + }; +}; diff --git a/src/server/protocol/ServerHttp1.cpp b/src/server/protocol/ServerHttp1.cpp new file mode 100644 index 0000000..c8c24c1 --- /dev/null +++ b/src/server/protocol/ServerHttp1.cpp @@ -0,0 +1,563 @@ + +#include "ServerHttp1.h" + +#include "extensions/Sendfile.h" +#include "ServerWebSocket.h" + +#include "../../utils/Utils.h" + +#include + +namespace HttpServer +{ + ServerHttp1::ServerHttp1(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls) noexcept + : ServerProtocol(sock, settings, controls) + { + + } + + bool ServerHttp1::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const + { + static const std::unordered_map status_list { + { 200, "OK" }, + { 206, "Partial Content" }, + { 304, "Not Modified" }, + { 400, "Bad Request" }, + { 404, "Not Found" }, + { 413, "Request Entity Too Large" }, + { 416, "Requested Range Not Satisfiable" }, + { 500, "Internal Server Error" }, + }; + + std::string str = "HTTP/1.1 " + std::to_string(static_cast(status) ); + + auto const it = status_list.find(static_cast(status) ); + + if (status_list.cend() != it) + { + const std::string &status = it->second; + + str += ' ' + status; + } + + str += "\r\n"; + + for (auto const &header : headers) + { + str += header.first + ": " + header.second + "\r\n"; + } + + str += "\r\n"; + + return this->sock.nonblock_send(str, timeout) > 0; // >= 0 + } + + long ServerHttp1::sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const + { + long send_size = this->sock.nonblock_send(src, size, timeout); + + dt->send_total += send_size; + + return send_size; + } + + void ServerHttp1::close() + { + this->sock.close(); + } + + bool ServerHttp1::packRequestParameters(std::vector &buf, const struct Request &req, const std::string &rootDir) const + { + Utils::packNumber(buf, static_cast(Transfer::ProtocolVariant::HTTP_1) ); + Utils::packString(buf, rootDir); + Utils::packString(buf, req.host); + Utils::packString(buf, req.path); + Utils::packString(buf, req.method); + Utils::packContainer(buf, req.incoming_headers); + Utils::packContainer(buf, req.incoming_data); + Utils::packFilesIncoming(buf, req.incoming_files); + + return true; + } + + void ServerHttp1::unpackResponseParameters(struct Request &req, const void *src) const + { + Utils::unpackContainer(req.outgoing_headers, reinterpret_cast(src) ); + } + + static bool getRequest(const Socket::Adapter &sock, struct Request &req, std::vector &buf, std::string &str_buf) + { + // Получить данные запроса от клиента + const long recv_size = sock.nonblock_recv(buf, req.timeout); + + if (recv_size < 0 && str_buf.empty() ) + { + return false; + } + + if (recv_size > 0) // Если данные были получены + { + str_buf.append(buf.cbegin(), buf.cbegin() + recv_size); + } + + return true; + } + + static Http::StatusCode getRequestHeaders(struct Request &req, std::string &str_buf) + { + // Если запрос пустой + if (str_buf.empty() ) + { + return Http::StatusCode::BAD_REQUEST; + } + + // Поиск конца заголовков (пустая строка) + size_t headers_end = str_buf.find("\r\n\r\n"); + + // Если найден конец заголовков + if (std::string::npos == headers_end) + { + return Http::StatusCode::BAD_REQUEST; + } + + headers_end += 2; + + size_t str_cur = 0; + // Поиск конца первого заголовка + size_t str_end = str_buf.find("\r\n"); + + // Если не найден конец заголовка + if (std::string::npos == str_end) + { + return Http::StatusCode::BAD_REQUEST; + } + + // Установка конца строки (для поиска) + str_buf[str_end] = '\0'; + + // Разделить метод запроса и параметры запроса + size_t delimiter = str_buf.find(' ', str_cur); + + // Получить метод запроса (GET, POST, PUT, DELETE, ...) + req.method = str_buf.substr(str_cur, delimiter - str_cur); + Utils::toLower(req.method); + + // Сохранить метод и параметры запроса + // rp.incoming_headers[rp.method] = str_buf.substr(delimiter + 1, str_end - delimiter - 1); + + delimiter += 1; + // Найти окончание URI + size_t uri_end = str_buf.find(' ', delimiter); + + // Если окончание не найдено + if (std::string::npos == uri_end) + { + uri_end = str_end; + // то версия протокола HTTP - 0.9 + // const std::string version = "0.9"; + } + else // Если окончание найдено + { + str_buf[uri_end] = '\0'; + const size_t ver_beg = uri_end + 6; // Пропустить "HTTP/" + + if (ver_beg < str_end) + { + // Получить версию протокола HTTP + // const std::string version = str_buf.substr(ver_beg, str_end - ver_beg); + } + } + + // Сохранить полную ссылку URI + req.path = str_buf.substr(delimiter, uri_end - delimiter); + + // Переход к обработке следующего заголовка + str_cur = str_end + 2; + // Поиск конца заголовка + str_end = str_buf.find("\r\n", str_cur); + // Установка конца заголовка + str_buf[str_end] = '\0'; + + // Цикл извлечения заголовков запроса + for (; str_cur != headers_end; str_end = str_buf.find("\r\n", str_cur), str_buf[str_end] = '\0') + { + // Поиск разделителя названия заголовка и его значения + delimiter = str_buf.find(':', str_cur); + + // Если разделитель найден в текущей строке + if (delimiter < str_end) + { + std::string header_name = str_buf.substr(str_cur, delimiter - str_cur); + Utils::toLower(header_name); + + std::string header_value = str_buf.substr(delimiter + 1, str_end - delimiter - 1); + // Удалить лишние пробелы в начале и в конце строки + Utils::trim(header_value); + + // Сохранить заголовок и его значение + req.incoming_headers.emplace(std::move(header_name), std::move(header_value) ); + } + + // Перейти к следующей строке + str_cur = str_end + 2; + } + + str_buf.erase(str_buf.begin(), str_buf.begin() + headers_end + 2); + + return Http::StatusCode::EMPTY; + } + + const ServerApplicationSettings *ServerHttp1::getApplicationSettings(struct Request &req, const bool isSecureConnection) const + { + // Получить доменное имя (или адрес) назначения запроса + auto const it_host = req.incoming_headers.find("host"); + + // Если имя задано - продолжить обработку запроса + if (req.incoming_headers.cend() != it_host) + { + const std::string &host_header = it_host->second; + + // Поиск разделителя, за которым помещается номер порта, если указан + const size_t delimiter = host_header.find(':'); + + // Получить имя (или адрес) + req.host = host_header.substr(0, delimiter); + + const int default_port = isSecureConnection ? 443 : 80; + + // Получить номер порта + const int port = (std::string::npos != delimiter) ? std::strtol(host_header.substr(delimiter + 1).c_str(), nullptr, 10) : default_port; + + // Поиск настроек приложения по имени + const ServerApplicationSettings *app_sets = this->settings.apps_tree.find(req.host); + + // Если приложение найдено + if (app_sets && (app_sets->ports.cend() != app_sets->ports.find(port) || app_sets->tls_ports.cend() != app_sets->tls_ports.find(port) ) ) + { + return app_sets; + } + } + + return nullptr; + } + + Http::StatusCode ServerHttp1::getRequestData(struct Request &req, std::string &str_buf, const ServerApplicationSettings &appSets) const + { + // Определить вариант данных запроса (заодно проверить, есть ли данные) + auto const it = req.incoming_headers.find("content-type"); + + if (req.incoming_headers.cend() == it) + { + return Http::StatusCode::EMPTY; + } + + // Получить значение заголовка + const std::string &header_value = it->second; + + std::string data_variant_name; // Название варианта данных запроса + + std::unordered_map content_params; + + // Определить, содержит ли тип данных запроса дополнительные параметры + size_t delimiter = header_value.find(';'); + + // Если есть дополнительные параметры - извлекаем их + if (std::string::npos != delimiter) + { + data_variant_name = header_value.substr(0, delimiter); + Utils::trim(data_variant_name); + + for (size_t str_param_cur = delimiter + 1, str_param_end = 0; std::string::npos != str_param_end; str_param_cur = str_param_end + 1) + { + str_param_end = header_value.find(';', str_param_cur); + delimiter = header_value.find('=', str_param_cur); + + if (delimiter >= str_param_end) + { + std::string param_name = header_value.substr(str_param_cur, std::string::npos != str_param_end ? str_param_end - str_param_cur : std::string::npos); + Utils::trim(param_name); + content_params.emplace(std::move(param_name), std::string() ); + } + else + { + std::string param_name = header_value.substr(str_param_cur, delimiter - str_param_cur); + Utils::trim(param_name); + + ++delimiter; + + std::string param_value = header_value.substr(delimiter, std::string::npos != str_param_end ? str_param_end - delimiter : std::string::npos); + Utils::trim(param_value); + + content_params.emplace(std::move(param_name), std::move(param_value) ); + } + } + } + else + { + data_variant_name = header_value; + } + + // Поиск варианта данных по имени типа + auto const variant = this->settings.variants.find(data_variant_name); + + // Если сервер не поддерживает формат полученных данных + if (this->settings.variants.cend() == variant) + { + return Http::StatusCode::BAD_REQUEST; + } + + const DataVariant::Abstract *data_variant = variant->second; + + // Получить длину запроса в байтах + size_t data_length = 0; + + auto const it_len = req.incoming_headers.find("content-length"); + + if (req.incoming_headers.cend() != it_len) + { + data_length = std::strtoull(it_len->second.c_str(), nullptr, 10); + } + + // Если размер запроса превышает лимит (если лимит был установлен) + if (data_length > appSets.request_max_size && 0 != appSets.request_max_size) + { + return Http::StatusCode::REQUEST_ENTITY_TOO_LARGE; + } + + Transfer::request_data *rd = static_cast(&req); + + DataVariant::DataReceiver dr { + data_variant, + data_variant->createStateStruct(rd, content_params), + data_length, + 0, 0, nullptr, + }; + + std::string data_buf; + + if (data_length >= str_buf.length() ) + { + dr.recv_total = str_buf.length(); + + data_buf.swap(str_buf); + } + else + { + data_buf.assign(str_buf.cbegin(), str_buf.cbegin() + data_length); + str_buf.erase(str_buf.begin(), str_buf.begin() + data_length); + + dr.recv_total = data_buf.size(); + } + + bool result = data_variant->parse(data_buf, rd, &dr); + + while (result && dr.full_size > dr.recv_total) + { + std::vector buf(dr.full_size - dr.recv_total >= 512 * 1024 ? 512 * 1024 : dr.full_size - dr.recv_total); + + long recv_size = this->sock.nonblock_recv(buf.data(), buf.size(), req.timeout); + + if (recv_size <= 0) + { + result = false; + + break; + } + + dr.recv_total += recv_size; + + data_buf.erase(data_buf.begin(), data_buf.end() - dr.left); + data_buf.append(buf.cbegin(), buf.cbegin() + recv_size); + + dr.left = 0; + + result = data_variant->parse(data_buf, rd, &dr); + } + + data_variant->destroyStateStruct(dr.ss); + + // Разобрать данные на составляющие + if (false == result) + { + for (auto const &it : req.incoming_files) + { + std::remove(it.second.getTmpName().c_str() ); + } + + return Http::StatusCode::BAD_REQUEST; + } + + if (dr.left) + { + str_buf.assign(data_buf.cend() - dr.left, data_buf.cend() ); + } + + return Http::StatusCode::EMPTY; + } + + static void sendStatus(const Socket::Adapter &sock, const struct Request &req, const Http::StatusCode statusCode) + { + static const std::unordered_map status_list { + { 400, "Bad Request" }, + { 404, "Not Found" }, + { 413, "Request Entity Too Large" }, + }; + + auto const it = status_list.find(static_cast(statusCode) ); + + if (status_list.cend() != it) + { + const std::string &status = it->second; + + std::string headers("HTTP/1.1 " + std::to_string(static_cast(statusCode) ) + ' ' + status + "\r\n\r\n"); + + sock.nonblock_send(headers, req.timeout); + } + } + + static void getConnectionParams(struct Request &req, const bool isSecureConnection) + { + auto const it_in_connection = req.incoming_headers.find("connection"); + auto const it_out_connection = req.outgoing_headers.find("connection"); + + if (req.incoming_headers.cend() != it_in_connection && req.outgoing_headers.cend() != it_out_connection) + { + const std::string connection_in = Utils::getLowerString(it_in_connection->second); + const std::string connection_out = Utils::getLowerString(it_out_connection->second); + + auto const incoming_params = Utils::explode(connection_in, ','); + + auto const it = std::find(incoming_params.cbegin(), incoming_params.cend(), connection_out); + + if (incoming_params.cend() != it) + { + const std::string &inc = *it; + + if ("keep-alive" == inc) + { + --req.keep_alive_count; + + if (0 < req.keep_alive_count) + { + req.connection_params |= ConnectionParams::CONNECTION_REUSE; + } + } + else if ("upgrade" == inc) + { + auto const it_out_upgrade = req.outgoing_headers.find("upgrade"); + + if (req.outgoing_headers.cend() != it_out_upgrade) + { + const std::string upgrade = Utils::getLowerString(it_out_upgrade->second); + + if ("h2" == upgrade) + { + if (isSecureConnection) + { + req.protocol_variant = Transfer::ProtocolVariant::HTTP_2; + req.connection_params |= ConnectionParams::CONNECTION_REUSE; + } + } + else if ("h2c" == upgrade) + { + if (false == isSecureConnection) + { + req.protocol_variant = Transfer::ProtocolVariant::HTTP_2; + req.connection_params |= ConnectionParams::CONNECTION_REUSE; + } + } + else if ("websocket" == upgrade) + { + req.connection_params |= ConnectionParams::CONNECTION_LEAVE_OPEN; + } + } + } + } + } + } + + void ServerHttp1::useHttp1Protocol(struct Request &req, std::vector &buf, std::string &str_buf) const + { + if (false == getRequest(this->sock, req, buf, str_buf) ) + { + return; + } + + Http::StatusCode error_code = getRequestHeaders(req, str_buf); + + if (error_code != Http::StatusCode::EMPTY) + { + sendStatus(this->sock, req, error_code); + + return; + } + + const ServerApplicationSettings *app_sets = this->getApplicationSettings(req, this->sock.get_tls_session() != 0); + + // Если приложение не найдено + if (nullptr == app_sets) + { + sendStatus(this->sock, req, Http::StatusCode::NOT_FOUND); + + return; + } + + error_code = this->getRequestData(req, str_buf, *app_sets); + + if (error_code != Http::StatusCode::EMPTY) + { + sendStatus(this->sock, req, error_code); + + return; + } + + this->runApplication(req, *app_sets); + + for (auto const &it : req.incoming_files) + { + std::remove(it.second.getTmpName().c_str() ); + } + + if (EXIT_SUCCESS == req.app_exit_code) + { + getConnectionParams(req, this->sock.get_tls_session() != 0); + + Sendfile::xSendfile(std::ref(*this), req, this->settings.mimes_types); + } + } + + static bool isConnectionLeaveOpen(const struct Request &req) + { + return (req.connection_params & ConnectionParams::CONNECTION_LEAVE_OPEN) == ConnectionParams::CONNECTION_LEAVE_OPEN; + } + + ServerProtocol *ServerHttp1::process() + { + struct Request req; + req.timeout = std::chrono::milliseconds(5000); + req.protocol_variant = Transfer::ProtocolVariant::HTTP_1; + req.keep_alive_count = 100; + + std::vector buf(4096); + std::string str_buf; + + do + { + // Подготовить параметры для получения данных + req.connection_params = ConnectionParams::CONNECTION_CLOSE; + req.app_exit_code = EXIT_FAILURE; + + this->useHttp1Protocol(req, buf, str_buf); + + req.clear(); + } + while (Sendfile::isConnectionReuse(req) ); + + if (isConnectionLeaveOpen(req) ) + { + return new ServerWebSocket(*this); + } + + return this; + } +}; diff --git a/src/server/protocol/ServerHttp1.h b/src/server/protocol/ServerHttp1.h new file mode 100644 index 0000000..cc7f2c3 --- /dev/null +++ b/src/server/protocol/ServerHttp1.h @@ -0,0 +1,29 @@ +#pragma once + +#include "ServerProtocol.h" +#include "../../transfer/HttpStatusCode.h" + +namespace HttpServer +{ + class ServerHttp1 : public ServerProtocol + { + private: + const ServerApplicationSettings *getApplicationSettings(struct Request &rp, const bool isSecureConnection) const; + Http::StatusCode getRequestData(struct Request &rp, std::string &str_buf, const ServerApplicationSettings &appSets) const; + + protected: + void useHttp1Protocol(struct Request &rp, std::vector &buf, std::string &str_buf) const; + + public: + ServerHttp1(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls) noexcept; + + virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const override; + virtual long sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const override; + + virtual bool packRequestParameters(std::vector &buf, const struct Request &rp, const std::string &rootDir) const override; + virtual void unpackResponseParameters(struct Request &req, const void *src) const override; + + virtual ServerProtocol *process() override; + virtual void close() override; + }; +}; diff --git a/src/server/protocol/ServerHttp2.cpp b/src/server/protocol/ServerHttp2.cpp new file mode 100644 index 0000000..b04fceb --- /dev/null +++ b/src/server/protocol/ServerHttp2.cpp @@ -0,0 +1,728 @@ + +#include "ServerHttp2.h" +#include "../../utils/Utils.h" +#include "../../transfer/http2/HPack.h" + +namespace HttpServer +{ + ServerHttp2::ServerHttp2(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, SocketsQueue &sockets) noexcept + : ServerHttp2Protocol(sock, settings, controls, nullptr), sockets(sockets) + { + + } + + void ServerHttp2::close() + { + this->sock.close(); + } + + static uint8_t *setHttp2FrameHeader(uint8_t *addr, const uint32_t frameSize, const Http2::FrameType frameType, const Http2::FrameFlag frameFlags, const uint32_t streamId) noexcept + { + Utils::hton24(addr, frameSize); + *(addr + 3) = static_cast(frameType); + *(addr + 4) = static_cast(frameFlags); + *reinterpret_cast(addr + 5) = ::htonl(streamId); + + return (addr + Http2::FRAME_HEADER_SIZE); + } + + static Http2::IncStream &getStreamData(std::unordered_map &streams, const uint32_t streamId, Http2::ConnectionData &conn) noexcept + { + auto it = streams.find(streamId); + + if (streams.end() != it) + { + return it->second; + } + + return streams.emplace(streamId, Http2::IncStream(streamId, conn) ).first->second; + } + + static void sendWindowUpdate(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, Http2::IncStream &stream, const uint32_t size) noexcept + { + std::array buf; + uint8_t *addr = buf.data(); + + addr = setHttp2FrameHeader(addr, sizeof(uint32_t), Http2::FrameType::WINDOW_UPDATE, Http2::FrameFlag::EMPTY, stream.stream_id); + + *reinterpret_cast(addr) = ::htonl(size); + + sock.nonblock_send(buf.data(), buf.size(), timeout); + } + + static Http2::ErrorCode parseHttp2Data(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) + { + if (0 == meta.stream_id) + { + return Http2::ErrorCode::PROTOCOL_ERROR; + } + + if (Http2::StreamState::OPEN != stream.state) + { + return Http2::ErrorCode::STREAM_CLOSED; + } + + if (stream.window_size_inc <= 0) + { + return Http2::ErrorCode::FLOW_CONTROL_ERROR; + } + + uint8_t padding = 0; + + if (meta.flags & Http2::FrameFlag::PADDED) + { + padding = *src; + + if (padding >= meta.length) + { + return Http2::ErrorCode::PROTOCOL_ERROR; + } + + src += sizeof(uint8_t); + } + + Http2::ErrorCode error_code = Http2::ErrorCode::NO_ERROR; + + if (stream.reserved) + { + Transfer::request_data *rd = static_cast(&stream); + + DataVariant::DataReceiver *dr = reinterpret_cast(stream.reserved); + + std::string &buf = *reinterpret_cast(dr->reserved); + + buf.append(src, end - padding); + + dr->recv_total += end - padding - src; + + if (dr->data_variant->parse(buf, rd, dr) ) + { + buf.erase(buf.begin(), buf.end() - dr->left); + } + else + { + error_code = Http2::ErrorCode::PROTOCOL_ERROR; + } + } + else + { + error_code = Http2::ErrorCode::PROTOCOL_ERROR; + } + + if (meta.flags & Http2::FrameFlag::END_STREAM) + { + stream.state = Http2::StreamState::HALF_CLOSED; + + ServerProtocol::destroyDataReceiver(stream.reserved); + stream.reserved = nullptr; + } + + return error_code; + } + + static Http2::ErrorCode parseHttp2Headers(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) + { + stream.state = (meta.flags & Http2::FrameFlag::END_STREAM) ? Http2::StreamState::HALF_CLOSED : Http2::StreamState::OPEN; + + uint8_t padding = 0; + + if (meta.flags & Http2::FrameFlag::PADDED) + { + padding = *src; + + if (padding >= meta.length) + { + return Http2::ErrorCode::PROTOCOL_ERROR; + } + + src += sizeof(uint8_t); + } + + if (meta.flags & Http2::FrameFlag::PRIORITY) + { + // Stream id + const uint32_t depend_stream_id = ::ntohl(*reinterpret_cast(src) ) & ~(1 << 31); + + src += sizeof(uint32_t); + + // Priority weight + stream.priority = *src; + + src += sizeof(uint8_t); + } + + if (false == HPack::unpack(src, end - src - padding, stream) ) + { + return Http2::ErrorCode::COMPRESSION_ERROR; + } + + return Http2::ErrorCode::NO_ERROR; + } + + static Http2::ErrorCode parseHttp2rstStream(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) + { + if (Http2::StreamState::IDLE == stream.state) + { + return Http2::ErrorCode::PROTOCOL_ERROR; + } + + stream.state = Http2::StreamState::CLOSED; + + if (0 == meta.stream_id) + { + return Http2::ErrorCode::PROTOCOL_ERROR; + } + + if (sizeof(uint32_t) != meta.length) + { + return Http2::ErrorCode::FRAME_SIZE_ERROR; + } + + const Http2::ErrorCode error_code = static_cast(::ntohl(*reinterpret_cast(src) ) ); + + if (Http2::ErrorCode::NO_ERROR != error_code) + { + // DEBUG + } + + return Http2::ErrorCode::NO_ERROR; + } + + static Http2::ErrorCode parseHttp2Settings(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) + { + if (0 != meta.stream_id) + { + return Http2::ErrorCode::PROTOCOL_ERROR; + } + + if (meta.length % (sizeof(uint16_t) + sizeof(uint32_t) ) ) + { + return Http2::ErrorCode::FRAME_SIZE_ERROR; + } + + if (Http2::StreamState::OPEN != stream.state) + { + stream.state = Http2::StreamState::OPEN; + } + + Http2::ConnectionSettings &settings = stream.conn.client_settings; + + while (src != end) + { + const Http2::ConnectionSetting setting = static_cast(ntohs(*reinterpret_cast(src) ) ); + + src += sizeof(uint16_t); + + const uint32_t value = ::ntohl(*reinterpret_cast(src) ); + + src += sizeof(uint32_t); + + switch (setting) + { + case Http2::ConnectionSetting::SETTINGS_HEADER_TABLE_SIZE: + settings.header_table_size = value; + break; + + case Http2::ConnectionSetting::SETTINGS_ENABLE_PUSH: + { + if (value > 1) + { + return Http2::ErrorCode::PROTOCOL_ERROR; + } + + settings.enable_push = value; + + break; + } + + case Http2::ConnectionSetting::SETTINGS_MAX_CONCURRENT_STREAMS: + settings.max_concurrent_streams = value; + break; + + case Http2::ConnectionSetting::SETTINGS_INITIAL_WINDOW_SIZE: + { + if (value >= uint32_t(1 << 31) ) + { + return Http2::ErrorCode::FLOW_CONTROL_ERROR; + } + + settings.initial_window_size = value; + + break; + } + + case Http2::ConnectionSetting::SETTINGS_MAX_FRAME_SIZE: + { + if (value < (1 << 14) || value >= (1 << 24) ) + { + return Http2::ErrorCode::PROTOCOL_ERROR; + } + + settings.max_frame_size = value; + + break; + } + + case Http2::ConnectionSetting::SETTINGS_MAX_HEADER_LIST_SIZE: + settings.max_header_list_size = value; + break; + + default: + break; + } + } + + return Http2::ErrorCode::NO_ERROR; + } + + static Http2::ErrorCode parseHttp2GoAway(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) + { + if (0 != meta.stream_id) + { + return Http2::ErrorCode::PROTOCOL_ERROR; + } + + stream.state = Http2::StreamState::CLOSED; + + const uint32_t last_stream_id = ::ntohl(*reinterpret_cast(src) ); + + if (last_stream_id > 0) + { + + } + + src += sizeof(uint32_t); + + const Http2::ErrorCode error_code = static_cast(::ntohl(*reinterpret_cast(src) ) ); + + if (Http2::ErrorCode::NO_ERROR != error_code) + { + + } + + return Http2::ErrorCode::NO_ERROR; + } + + static void ping(const Socket::Adapter &sock, const struct Request &req, const uint64_t pingData) + { + constexpr uint32_t frame_size = sizeof(uint64_t); + + std::array buf; + uint8_t *addr = buf.data(); + + addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::PING, Http2::FrameFlag::ACK, 0); + + *reinterpret_cast(addr) = pingData; + + sock.nonblock_send(buf.data(), buf.size(), req.timeout); + } + + static Http2::ErrorCode parseHttp2Ping(Http2::FrameMeta &meta) + { + if (0 != meta.stream_id) + { + return Http2::ErrorCode::PROTOCOL_ERROR; + } + + if (sizeof(uint64_t) != meta.length) + { + return Http2::ErrorCode::FRAME_SIZE_ERROR; + } + + return Http2::ErrorCode::NO_ERROR; + } + + static Http2::ErrorCode parseHttp2WindowUpdate(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) + { + if (Http2::StreamState::RESERVED == stream.state) + { + return Http2::ErrorCode::PROTOCOL_ERROR; + } + else if (Http2::StreamState::OPEN != stream.state) + { + return Http2::ErrorCode::NO_ERROR; + } + + if (sizeof(uint32_t) != meta.length) + { + return Http2::ErrorCode::FRAME_SIZE_ERROR; + } + + const uint32_t window_size_increment = ::ntohl(*reinterpret_cast(src) ); + + if (0 == window_size_increment) + { + return Http2::ErrorCode::PROTOCOL_ERROR; + } + else if (window_size_increment >= uint32_t(1 << 31) ) + { + return Http2::ErrorCode::FLOW_CONTROL_ERROR; + } + + if (0 == meta.stream_id) + { + // TODO: update all streams + stream.window_size_out += window_size_increment; + } + else + { + stream.window_size_out += window_size_increment; + } + + return Http2::ErrorCode::NO_ERROR; + } + + static void rstStream(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, const uint32_t streamId, const Http2::ErrorCode errorCode) + { + constexpr uint32_t frame_size = sizeof(uint32_t); + + std::array buf; + uint8_t *addr = buf.data(); + + addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::RST_STREAM, Http2::FrameFlag::EMPTY, streamId); + + *reinterpret_cast(addr) = ::htonl(static_cast(errorCode) ); + + sock.nonblock_send(buf.data(), buf.size(), timeout); + } + + static void sendSettings(const Socket::Adapter &sock, const struct Request &req, const uint8_t *src, const uint8_t *end) + { + const uint32_t frame_size = end - src; + + std::vector buf(Http2::FRAME_HEADER_SIZE + frame_size); + + uint8_t *addr = buf.data(); + + constexpr uint32_t stream_id = 0; + + addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::SETTINGS, Http2::FrameFlag::EMPTY, stream_id); + + std::copy(src, end, addr); + + sock.nonblock_send(buf.data(), buf.size(), req.timeout); + } + + static void goAway(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, const uint32_t lastStreamId, const Http2::ErrorCode errorCode) + { + constexpr uint32_t frame_size = sizeof(uint32_t) * 2; + + std::array buf; + + uint8_t *addr = buf.data(); + + addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::RST_STREAM, Http2::FrameFlag::EMPTY, 0); + + *reinterpret_cast(addr) = ::htonl(static_cast(lastStreamId) ); + *reinterpret_cast(addr + sizeof(uint32_t) ) = ::htonl(static_cast(errorCode) ); + + sock.nonblock_send(buf.data(), buf.size(), timeout); + } + + static bool getClientPreface(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout) + { + std::array buf; + + const long read_size = sock.nonblock_recv(buf.data(), buf.size(), timeout); + + if (read_size != buf.size() ) + { + return false; + } + + static constexpr char client_preface_data[] = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; + + const uint64_t *left = reinterpret_cast(client_preface_data); + const uint64_t *right = reinterpret_cast(buf.data() ); + + uint64_t compare = 0; + + compare |= left[0] ^ right[0]; + compare |= left[1] ^ right[1]; + compare |= left[2] ^ right[2]; + + return 0 == compare; + } + + static void sendEmptySettings(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, const Http2::FrameFlag flags) + { + constexpr uint32_t frame_size = 0; + + std::array buf; + uint8_t *addr = buf.data(); + + constexpr uint32_t stream_id = 0; + + addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::SETTINGS, flags, stream_id); + + sock.nonblock_send(buf.data(), buf.size(), timeout); + } + + static void windowUpdate(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout) + { + constexpr uint32_t frame_size = 4; + + std::array buf; + uint8_t *addr = buf.data(); + + constexpr uint32_t stream_id = 0; + + addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::WINDOW_UPDATE, Http2::FrameFlag::EMPTY, stream_id); + + *reinterpret_cast(addr) = ::htonl(static_cast(1 << 16) - 1); + + sock.nonblock_send(buf.data(), buf.size(), timeout); + } + + static bool getNextHttp2FrameMeta(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, std::vector &buf, Http2::FrameMeta &meta, long &read_size) + { + if (read_size <= meta.length + Http2::FRAME_HEADER_SIZE) + { + if (read_size == meta.length + Http2::FRAME_HEADER_SIZE) + { + read_size = 0; + } + + read_size = sock.nonblock_recv(buf.data() + read_size, buf.size() - read_size, timeout); + + if (read_size < Http2::FRAME_HEADER_SIZE) + { + return false; + } + } + else + { + std::copy(buf.cbegin() + meta.length + Http2::FRAME_HEADER_SIZE, buf.cbegin() + read_size, buf.begin() ); + + read_size -= meta.length + Http2::FRAME_HEADER_SIZE; + } + + const uint8_t *addr = reinterpret_cast(buf.data() ); + + meta.length = Utils::ntoh24(addr); + meta.type = static_cast(*(addr + 3) ); + meta.flags = static_cast(*(addr + 4) ); + meta.stream_id = ::ntohl(*reinterpret_cast(addr + 5) ); + + return true; + } + + ServerProtocol *ServerHttp2::process() + { + struct Request req; + req.timeout = std::chrono::milliseconds(5000); + req.protocol_variant = Transfer::ProtocolVariant::HTTP_2; + + sendEmptySettings(this->sock, req.timeout, Http2::FrameFlag::EMPTY); + + if (false == getClientPreface(this->sock, req.timeout) ) + { + constexpr uint32_t last_stream_id = 0; + + goAway(this->sock, req.timeout, last_stream_id, Http2::ErrorCode::PROTOCOL_ERROR); + + return this; + } + + Http2::ConnectionData conn; + + conn.client_settings = Http2::ConnectionSettings::defaultSettings(); + conn.server_settings = Http2::ConnectionSettings::defaultSettings(); + + std::vector buf(conn.server_settings.max_frame_size); + + std::unordered_map streams { + { 0, Http2::IncStream(0, conn) } + }; + + Http2::IncStream &primary = streams.find(0)->second; + this->stream = &primary; + + size_t streams_process_count = 0; + uint32_t last_stream_id = 0; + + Http2::FrameMeta meta {}; + long read_size = 0; + + do + { + if (false == getNextHttp2FrameMeta(this->sock, req.timeout, buf, meta, read_size) ) + { + break; + } + + const uint8_t *addr = reinterpret_cast(buf.data() ) + Http2::FRAME_HEADER_SIZE; + const uint8_t *end = addr + meta.length; + + if (meta.stream_id > last_stream_id) + { + last_stream_id = meta.stream_id; + } + + Http2::IncStream &stream = getStreamData(streams, meta.stream_id, conn); + + if (Http2::StreamState::CLOSED == stream.state) + { + rstStream(this->sock, req.timeout, stream.stream_id, Http2::ErrorCode::STREAM_CLOSED); + + continue; + } + + if (meta.type != Http2::FrameType::CONTINUATION) + { + stream.frame_type = meta.type; + } + + Http2::ErrorCode result = Http2::ErrorCode::NO_ERROR; + + switch (stream.frame_type) + { + case Http2::FrameType::DATA: + { + result = parseHttp2Data(meta, stream, addr, end); + + stream.window_size_inc -= meta.length; + + if (stream.reserved) + { + DataVariant::DataReceiver *dr = reinterpret_cast(stream.reserved); + + if (static_cast(stream.window_size_inc - conn.server_settings.max_frame_size) <= 0) + { + size_t update_size = conn.server_settings.initial_window_size + (dr->full_size - dr->recv_total) - stream.window_size_inc; + + if (update_size > Http2::MAX_WINDOW_UPDATE) + { + update_size = Http2::MAX_WINDOW_UPDATE; + } + + sendWindowUpdate(this->sock, req.timeout, stream, static_cast(update_size) ); + sendWindowUpdate(this->sock, req.timeout, primary, static_cast(update_size) ); + + stream.window_size_inc += update_size; + } + } + + break; + } + + case Http2::FrameType::HEADERS: + { + result = parseHttp2Headers(meta, stream, addr, end); + + if (meta.flags & Http2::FrameFlag::END_HEADERS) + { + Transfer::request_data *rd = static_cast(&stream); + + stream.reserved = createDataReceiver(rd, this->settings.variants); + + if (stream.reserved) + { + DataVariant::DataReceiver *dr = reinterpret_cast(stream.reserved); + + dr->reserved = new std::string(); + } + } + + break; + } + + case Http2::FrameType::PRIORITY: + result = Http2::ErrorCode::NO_ERROR; + break; + + case Http2::FrameType::RST_STREAM: + result = parseHttp2rstStream(meta, stream, addr, end); + break; + + case Http2::FrameType::SETTINGS: + { + result = parseHttp2Settings(meta, stream, addr, end); + + if (Http2::ErrorCode::NO_ERROR == result && false == (meta.flags & Http2::FrameFlag::ACK) ) + { + conn.decoding_dynamic_table.changeHeaderTableSize(conn.client_settings.header_table_size); + conn.decoding_dynamic_table.changeMaxHeaderListSize(conn.client_settings.max_header_list_size); + + sendEmptySettings(this->sock, req.timeout, Http2::FrameFlag::ACK); + } + + break; + } + + case Http2::FrameType::PUSH_PROMISE: + result = Http2::ErrorCode::NO_ERROR; + break; + + case Http2::FrameType::PING: + { + result = parseHttp2Ping(meta); + + if (Http2::ErrorCode::NO_ERROR == result && false == (meta.flags & Http2::FrameFlag::ACK) ) + { + const uint64_t ping_data = *reinterpret_cast(addr); + + ping(this->sock, req, ping_data); + } + + break; + } + + case Http2::FrameType::GOAWAY: + result = parseHttp2GoAway(meta, stream, addr, end); + break; + + case Http2::FrameType::WINDOW_UPDATE: + result = parseHttp2WindowUpdate(meta, stream, addr, end); + break; + + default: + result = Http2::ErrorCode::PROTOCOL_ERROR; + break; + } + + if (result != Http2::ErrorCode::NO_ERROR) + { + stream.state = Http2::StreamState::CLOSED; + + rstStream(this->sock, req.timeout, meta.stream_id, result); + + // TODO: remove closed stream(s) from unordered map + } + else if ( (meta.flags & Http2::FrameFlag::END_STREAM) && meta.stream_id != 0) + { + stream.reserved = this->sock.get_tls_session(); + + sockets.lock(); + + sockets.emplace( + std::tuple { + Socket::Socket(this->sock.get_handle() ), + &stream + } + ); + + sockets.unlock(); + + this->controls.eventProcessQueue->notify(); + + ++streams_process_count; + } + } + while (Http2::StreamState::CLOSED != primary.state); + + while (conn.sync.completed.load() < streams_process_count) + { + conn.sync.event.wait(); + } + + goAway(this->sock, req.timeout, last_stream_id, Http2::ErrorCode::NO_ERROR); + + for (auto &pair : streams) + { + destroyDataReceiver(pair.second.reserved); + } + + return this; + } +}; diff --git a/src/server/protocol/ServerHttp2.h b/src/server/protocol/ServerHttp2.h new file mode 100644 index 0000000..54658d4 --- /dev/null +++ b/src/server/protocol/ServerHttp2.h @@ -0,0 +1,21 @@ +#pragma once + +#include "../SocketsQueue.h" + +#include "ServerHttp2Protocol.h" +#include "../../transfer/HttpStatusCode.h" + +namespace HttpServer +{ + class ServerHttp2 : public ServerHttp2Protocol + { + protected: + SocketsQueue &sockets; + + public: + ServerHttp2(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, SocketsQueue &sockets) noexcept; + + virtual ServerProtocol *process() override; + virtual void close() override; + }; +}; diff --git a/src/server/protocol/ServerHttp2Protocol.cpp b/src/server/protocol/ServerHttp2Protocol.cpp new file mode 100644 index 0000000..00f305c --- /dev/null +++ b/src/server/protocol/ServerHttp2Protocol.cpp @@ -0,0 +1,178 @@ + +#include "ServerHttp2Protocol.h" +#include "../../utils/Utils.h" +#include "../../transfer/http2/HPack.h" + +#include + +namespace HttpServer +{ + ServerHttp2Protocol::ServerHttp2Protocol(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, Http2::IncStream *stream) noexcept + : ServerProtocol(sock, settings, controls), stream(stream) + { + + } + + uint8_t ServerHttp2Protocol::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 ServerHttp2Protocol::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const + { + headers.emplace(headers.begin(), ":status", std::to_string(static_cast(status) ) ); + + std::vector buf; + buf.reserve(4096); + + HPack::pack(buf, headers, this->stream->conn.encoding_dynamic_table); + + const uint32_t frame_size = buf.size(); + + buf.insert(buf.begin(), Http2::FRAME_HEADER_SIZE, 0); + + Http2::FrameFlag flags = Http2::FrameFlag::END_HEADERS; + + if (endStream) + { + flags |= Http2::FrameFlag::END_STREAM; + } + + this->stream->setHttp2FrameHeader(reinterpret_cast(buf.data() ), frame_size, Http2::FrameType::HEADERS, flags); + + return this->sock.nonblock_send(buf.data(), buf.size(), timeout) > 0; // >= 0 + } + + long ServerHttp2Protocol::sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const + { + const uint8_t *data = reinterpret_cast(src); + + const Http2::ConnectionSettings &setting = this->stream->conn.client_settings; + + std::vector buf; + buf.reserve(setting.max_frame_size + Http2::FRAME_HEADER_SIZE); + + long send_size = 0; + + while (size != 0) + { + buf.resize(0); + + // TODO: test with data_size == 1 (padding length == 0) + size_t data_size = setting.max_frame_size < size ? setting.max_frame_size : 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 > setting.max_frame_size) + { + data_size = setting.max_frame_size - padding_size; + } + } + + const size_t frame_size = data_size + padding_size; + + /* if (this->stream->window_size_out - frame_size <= 0) + { + size_t update_size = (dt->full_size - dt->send_total) - this->stream->window_size_out; + + if (update_size > Http2::MAX_WINDOW_UPDATE) + { + update_size = Http2::MAX_WINDOW_UPDATE; + } + + sendWindowUpdate(this->sock, rp, static_cast(update_size) ); + + this->stream->window_size_out += update_size; + }*/ + + Http2::FrameFlag flags = Http2::FrameFlag::EMPTY; + + if (dt->send_total + data_size >= dt->full_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; + } + + data += data_size; + send_size += data_size; + dt->send_total += data_size; + // stream->window_size_out -= frame_size; + + size -= data_size; + } + + return send_size; + } + + bool ServerHttp2Protocol::packRequestParameters(std::vector &buf, const struct Request &req, const std::string &rootDir) const + { + Utils::packNumber(buf, static_cast(Transfer::ProtocolVariant::HTTP_2) ); + Utils::packString(buf, rootDir); + Utils::packString(buf, req.host); + Utils::packString(buf, req.path); + Utils::packString(buf, req.method); + + Utils::packNumber(buf, this->stream->stream_id); + Utils::packNumber(buf, this->stream->conn.client_settings.header_table_size); + Utils::packNumber(buf, this->stream->conn.client_settings.enable_push); + Utils::packNumber(buf, this->stream->conn.client_settings.max_concurrent_streams); + Utils::packNumber(buf, this->stream->conn.client_settings.initial_window_size); + Utils::packNumber(buf, this->stream->conn.client_settings.max_frame_size); + Utils::packNumber(buf, this->stream->conn.client_settings.max_header_list_size); + Utils::packContainer(buf, this->stream->conn.encoding_dynamic_table.getList() ); + Utils::packContainer(buf, req.incoming_headers); + Utils::packContainer(buf, req.incoming_data); + Utils::packFilesIncoming(buf, req.incoming_files); + + return true; + } + + void ServerHttp2Protocol::unpackResponseParameters(struct Request &req, const void *src) const + { + Utils::unpackContainer(req.outgoing_headers, reinterpret_cast(src) ); + } +}; + diff --git a/src/server/protocol/ServerHttp2Protocol.h b/src/server/protocol/ServerHttp2Protocol.h new file mode 100644 index 0000000..7c84ba4 --- /dev/null +++ b/src/server/protocol/ServerHttp2Protocol.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ServerProtocol.h" +#include "../../transfer/http2/Http2.h" + +namespace HttpServer +{ + class ServerHttp2Protocol : public ServerProtocol + { + protected: + Http2::IncStream *stream; + + protected: + static uint8_t getPaddingSize(const size_t dataSize); + + public: + ServerHttp2Protocol(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, Http2::IncStream *stream) noexcept; + + virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const override; + virtual long sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const override; + + virtual bool packRequestParameters(std::vector &buf, const struct Request &rp, const std::string &rootDir) const override; + virtual void unpackResponseParameters(struct Request &rp, const void *src) const override; + }; +}; diff --git a/src/server/protocol/ServerHttp2Stream.cpp b/src/server/protocol/ServerHttp2Stream.cpp new file mode 100644 index 0000000..8a20c8a --- /dev/null +++ b/src/server/protocol/ServerHttp2Stream.cpp @@ -0,0 +1,110 @@ + +#include "ServerHttp2Stream.h" + +#include "extensions/Sendfile.h" + +namespace HttpServer +{ + ServerHttp2Stream::ServerHttp2Stream(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, Http2::IncStream *stream) noexcept + : ServerHttp2Protocol(sock, settings, controls, stream) + { + + } + + void ServerHttp2Stream::close() + { + this->stream->close(); + } + + ServerProtocol *ServerHttp2Stream::process() + { + struct Request req; + + req.timeout = std::chrono::milliseconds(5000); + req.protocol_variant = Transfer::ProtocolVariant::HTTP_2; + + req.incoming_headers = std::move(this->stream->incoming_headers); + req.incoming_data = std::move(this->stream->incoming_data); + req.incoming_files = std::move(this->stream->incoming_files); + + auto const &headers = req.incoming_headers; + + auto const it_scheme = headers.find(":scheme"); + + if (headers.cend() == it_scheme) + { + return this; + } + + const std::string &scheme = it_scheme->second; + + const int default_port = (scheme == "https") ? 443 : (scheme == "http") ? 80 : 0; + + auto const it_host = headers.find(":authority"); + + if (headers.cend() == it_host) + { + return this; + } + + const std::string &host_header = it_host->second; + + // Поиск разделителя, за которым помещается номер порта, если указан + const size_t delimiter = host_header.find(':'); + + // Получить имя (или адрес) + req.host = host_header.substr(0, delimiter); + + // Получить номер порта + const int port = (std::string::npos != delimiter) ? std::strtol(host_header.substr(delimiter + 1).c_str(), nullptr, 10) : default_port; + + const ServerApplicationSettings *app_sets = this->settings.apps_tree.find(req.host); + + // Если приложение найдено + if (nullptr == app_sets || (app_sets->ports.cend() == app_sets->ports.find(port) && app_sets->tls_ports.cend() == app_sets->tls_ports.find(port) ) ) + { + return this; + } + + auto const it_method = headers.find(":method"); + + if (headers.cend() == it_method) + { + return this; + } + + req.method = it_method->second; + + auto const it_path = headers.find(":path"); + + if (headers.cend() == it_path) + { + return this; + } + + req.path = it_path->second; + + req.app_exit_code = EXIT_FAILURE; + + this->runApplication(req, *app_sets); + + for (auto const &it : req.incoming_files) + { + std::remove(it.second.getTmpName().c_str() ); + } + + if (EXIT_SUCCESS == req.app_exit_code) + { + // Http2::OutStream out(*stream); + + // auto tmp = req.protocol_data; + // req.protocol_data = &out; + + Sendfile::xSendfile(std::ref(*this), req, this->settings.mimes_types); + + // req.protocol_data = tmp; + } + + return this; + } +}; diff --git a/src/server/protocol/ServerHttp2Stream.h b/src/server/protocol/ServerHttp2Stream.h new file mode 100644 index 0000000..a4c18c1 --- /dev/null +++ b/src/server/protocol/ServerHttp2Stream.h @@ -0,0 +1,16 @@ +#pragma once + +#include "ServerHttp2Protocol.h" +#include "../../transfer/http2/Http2.h" + +namespace HttpServer +{ + class ServerHttp2Stream : public ServerHttp2Protocol + { + public: + ServerHttp2Stream(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, Http2::IncStream *stream) noexcept; + + virtual ServerProtocol *process() override; + virtual void close() override; + }; +}; diff --git a/src/server/protocol/ServerProtocol.cpp b/src/server/protocol/ServerProtocol.cpp new file mode 100644 index 0000000..9adc151 --- /dev/null +++ b/src/server/protocol/ServerProtocol.cpp @@ -0,0 +1,166 @@ + +#include "ServerProtocol.h" +#include "../../utils/Utils.h" + +namespace HttpServer +{ + ServerProtocol::ServerProtocol(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls) noexcept + : sock(sock), settings(settings), controls(controls) + { + + } + + ServerProtocol::ServerProtocol(const ServerProtocol &prot) noexcept + : sock(prot.sock), settings(prot.settings), controls(prot.controls) + { + + } + + DataVariant::DataReceiver *ServerProtocol::createDataReceiver(const Transfer::request_data *rd, const std::unordered_map &variants) + { + auto const it = rd->incoming_headers.find("content-type"); + + if (rd->incoming_headers.cend() == it) + { + return nullptr; + } + + // Получить значение заголовка + const std::string &header_value = it->second; + + std::string data_variant_name; // Название варианта данных запроса + + std::unordered_map content_params; + + // Определить, содержит ли тип данных запроса дополнительные параметры + size_t delimiter = header_value.find(';'); + + // Если есть дополнительные параметры - извлекаем их + if (std::string::npos != delimiter) + { + data_variant_name = header_value.substr(0, delimiter); + Utils::trim(data_variant_name); + + for (size_t str_param_cur = delimiter + 1, str_param_end = 0; std::string::npos != str_param_end; str_param_cur = str_param_end + 1) + { + str_param_end = header_value.find(';', str_param_cur); + delimiter = header_value.find('=', str_param_cur); + + if (delimiter >= str_param_end) + { + std::string param_name = header_value.substr(str_param_cur, std::string::npos != str_param_end ? str_param_end - str_param_cur : std::string::npos); + Utils::trim(param_name); + content_params.emplace(std::move(param_name), std::string() ); + } + else + { + std::string param_name = header_value.substr(str_param_cur, delimiter - str_param_cur); + Utils::trim(param_name); + + ++delimiter; + + std::string param_value = header_value.substr(delimiter, std::string::npos != str_param_end ? str_param_end - delimiter : std::string::npos); + Utils::trim(param_value); + + content_params.emplace(std::move(param_name), std::move(param_value) ); + } + } + } + else + { + data_variant_name = header_value; + } + + auto const variant = variants.find(data_variant_name); + + if (variants.cend() == variant) + { + return nullptr; + } + + const DataVariant::Abstract *data_variant = variant->second; + + size_t data_length = 0; + + auto const it_len = rd->incoming_headers.find("content-length"); + + if (rd->incoming_headers.cend() != it_len) + { + data_length = std::strtoull(it_len->second.c_str(), nullptr, 10); + } + + return new DataVariant::DataReceiver { + data_variant, + data_variant->createStateStruct(rd, content_params), + data_length, + 0, 0, nullptr, + }; + } + + void ServerProtocol::destroyDataReceiver(void *src) + { + DataVariant::DataReceiver *dr = reinterpret_cast(src); + + if (dr) + { + dr->data_variant->destroyStateStruct(dr->ss); + + if (dr->reserved) + { + delete reinterpret_cast(dr->reserved); + dr->reserved = nullptr; + } + } + + delete dr; + } + + void ServerProtocol::runApplication(struct Request &req, const ServerApplicationSettings &appSets) const + { + std::vector buf; + buf.reserve(4096); + + if (false == this->packRequestParameters(buf, req, appSets.root_dir) ) + { + return; + } + + Transfer::app_request request { + this->sock.get_handle(), + this->sock.get_tls_session(), + buf.data() + }; + + Transfer::app_response response { + nullptr, 0 + }; + + try + { + // Launch application + req.app_exit_code = appSets.application_call(&request, &response); + } + catch (std::exception &exc) + { + // TODO: exception output + } + + if (response.response_data && response.data_size) + { + if (EXIT_SUCCESS == req.app_exit_code) + { + this->unpackResponseParameters(req, response.response_data); + } + + // Clear outgoing data of application + try + { + appSets.application_clear(response.response_data, response.data_size); + } + catch (std::exception &exc) + { + // TODO: exception output + } + } + } +}; diff --git a/src/server/protocol/ServerProtocol.h b/src/server/protocol/ServerProtocol.h new file mode 100644 index 0000000..91f5b3a --- /dev/null +++ b/src/server/protocol/ServerProtocol.h @@ -0,0 +1,39 @@ +#pragma once + +#include "../Request.h" +#include "../ServerControls.h" +#include "../ServerSettings.h" + +#include "../../transfer/HttpStatusCode.h" + +namespace HttpServer +{ + class ServerProtocol + { + protected: + Socket::Adapter &sock; + const ServerSettings &settings; + ServerControls &controls; + + public: + ServerProtocol(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls) noexcept; + ServerProtocol(const ServerProtocol &prot) noexcept; + virtual ~ServerProtocol() noexcept = default; + + static DataVariant::DataReceiver *createDataReceiver(const Transfer::request_data *rd, const std::unordered_map &variants); + static void destroyDataReceiver(void *src); + + protected: + void runApplication(struct Request &req, const ServerApplicationSettings &appSets) const; + + public: + 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, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const = 0; + + virtual bool packRequestParameters(std::vector &buf, const struct Request &req, const std::string &rootDir) const = 0; + virtual void unpackResponseParameters(struct Request &req, const void *src) const = 0; + + virtual ServerProtocol *process() = 0; + virtual void close() = 0; + }; +}; diff --git a/src/server/protocol/ServerWebSocket.cpp b/src/server/protocol/ServerWebSocket.cpp new file mode 100644 index 0000000..5c03f1a --- /dev/null +++ b/src/server/protocol/ServerWebSocket.cpp @@ -0,0 +1,47 @@ + +#include "ServerWebSocket.h" + +namespace HttpServer +{ + ServerWebSocket::ServerWebSocket(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls) noexcept + : ServerProtocol(sock, settings, controls) + { + + } + + ServerWebSocket::ServerWebSocket(const ServerProtocol &prot) noexcept + : ServerProtocol(prot) + { + + } + + bool ServerWebSocket::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const + { + return false; + } + + long ServerWebSocket::sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const + { + return 0; + } + + bool ServerWebSocket::packRequestParameters(std::vector &buf, const struct Request &rp, const std::string &rootDir) const + { + return false; + } + + void ServerWebSocket::unpackResponseParameters(struct Request &req, const void *src) const + { + + } + + ServerProtocol *ServerWebSocket::process() + { + return this; + } + + void ServerWebSocket::close() + { + + } +}; diff --git a/src/server/protocol/ServerWebSocket.h b/src/server/protocol/ServerWebSocket.h new file mode 100644 index 0000000..094293f --- /dev/null +++ b/src/server/protocol/ServerWebSocket.h @@ -0,0 +1,22 @@ +#pragma once + +#include "ServerProtocol.h" + +namespace HttpServer +{ + class ServerWebSocket : public ServerProtocol + { + public: + ServerWebSocket(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls) noexcept; + ServerWebSocket(const ServerProtocol &prot) noexcept; + + virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const override; + virtual long sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const override; + + virtual bool packRequestParameters(std::vector &buf, const struct Request &rp, const std::string &rootDir) const override; + virtual void unpackResponseParameters(struct Request &req, const void *src) const override; + + virtual ServerProtocol *process() override; + virtual void close() override; + }; +}; diff --git a/src/server/protocol/extensions/Sendfile.cpp b/src/server/protocol/extensions/Sendfile.cpp new file mode 100644 index 0000000..9c557ba --- /dev/null +++ b/src/server/protocol/extensions/Sendfile.cpp @@ -0,0 +1,375 @@ + +#include "Sendfile.h" +#include "../../../utils/Utils.h" + +#include + +namespace HttpServer +{ + static std::string getMimeTypeByFileName(const std::string &fileName, const std::unordered_map &mimesTypes) noexcept + { + const size_t ext_pos = fileName.rfind('.'); + + const std::string file_ext = Utils::getLowerString(std::string::npos != ext_pos ? fileName.substr(ext_pos + 1) : std::string() ); + + auto const it_mime = mimesTypes.find(file_ext); + + return mimesTypes.cend() != it_mime ? it_mime->second : std::string("application/octet-stream"); + } + + static std::vector > getRanges( + const std::string &rangeHeader, + const size_t posSymEqual, + const size_t fileSize, + std::string *resultRangeHeader, + size_t *contentLength + ) noexcept + { + std::vector > ranges; + + *contentLength = 0; + + size_t delimiter = posSymEqual; // rangeHeader.find('='); + + const std::string range_unit_name(rangeHeader.cbegin(), rangeHeader.cbegin() + delimiter); + + static const std::unordered_map ranges_units { + { "bytes", 1 } + }; + + auto const it_unit = ranges_units.find(range_unit_name); + + if (ranges_units.cend() == it_unit) + { + return ranges; + } + + const size_t range_unit = it_unit->second; + + for (size_t str_pos; std::string::npos != delimiter; ) + { + str_pos = delimiter + 1; + + delimiter = rangeHeader.find(',', str_pos); + + const size_t range_pos = rangeHeader.find('-', str_pos); + + if (range_pos < delimiter) + { + const std::string range_begin_str(rangeHeader.cbegin() + str_pos, rangeHeader.cbegin() + range_pos); + const std::string range_end_str(rangeHeader.cbegin() + range_pos + 1, std::string::npos == delimiter ? rangeHeader.cend() : rangeHeader.cbegin() + delimiter); + + if (false == range_begin_str.empty() ) + { + const size_t range_begin = std::strtoull(range_begin_str.c_str(), nullptr, 10) * range_unit; + + if (range_begin < fileSize) + { + if (false == range_end_str.empty() ) + { + size_t range_end = std::strtoull(range_end_str.c_str(), nullptr, 10) * range_unit; + + if (range_end >= range_begin) + { + if (range_end > fileSize) + { + range_end = fileSize; + } + + const size_t length = range_end - range_begin + 1; + + *contentLength += length; + + *resultRangeHeader += std::to_string(range_begin) + '-' + std::to_string(range_end) + ','; + + ranges.emplace_back(std::tuple {range_begin, length}); + } + } + else // if range_end_str empty + { + const size_t length = fileSize - range_begin; + + *contentLength += length; + + *resultRangeHeader += std::to_string(range_begin) + '-' + std::to_string(fileSize - 1) + ','; + + ranges.emplace_back(std::tuple {range_begin, length}); + } + } + } + else if (false == range_end_str.empty() ) // if range_begin_str empty + { + size_t range_end = std::strtoull(range_end_str.c_str(), nullptr, 10) * range_unit; + + const size_t length = range_end < fileSize ? fileSize - range_end : fileSize; + + const size_t range_begin = fileSize - length; + + range_end = fileSize - range_begin - 1; + + *contentLength += length; + + *resultRangeHeader += std::to_string(range_begin) + '-' + std::to_string(range_end) + ','; + + ranges.emplace_back(std::tuple {range_begin, length}); + } + } + } + + if (false == ranges.empty() ) + { + (*resultRangeHeader).back() = '/'; + + *resultRangeHeader = "bytes " + *resultRangeHeader + std::to_string(fileSize); + } + + return ranges; + } + + int Sendfile::transferFilePart( + const ServerProtocol &prot, + const struct Request &req, + const std::string &fileName, + const std::unordered_map &mimesTypes, + const time_t fileTime, + const size_t fileSize, + const std::string &rangeHeader, + std::vector > &additionalHeaders, + const bool headersOnly + ) noexcept + { + const size_t pos_sym_equal = rangeHeader.find('='); + + if (std::string::npos == pos_sym_equal) + { + prot.sendHeaders(Http::StatusCode::BAD_REQUEST, additionalHeaders, req.timeout); + + return 1; + } + + std::string content_range_header; + + size_t content_length; + + const std::vector > ranges = getRanges(rangeHeader, pos_sym_equal, fileSize, &content_range_header, &content_length); + + if (0 == content_length) + { + prot.sendHeaders(Http::StatusCode::REQUESTED_RANGE_NOT_SATISFIABLE, additionalHeaders, req.timeout); + + return 2; + } + + // Ranges transfer + std::ifstream file(fileName, std::ifstream::binary); + + if ( ! file) + { + file.close(); + + prot.sendHeaders(Http::StatusCode::INTERNAL_SERVER_ERROR, additionalHeaders, req.timeout); + + return 3; + } + + const std::string file_mime_type = getMimeTypeByFileName(fileName, mimesTypes); + + additionalHeaders.emplace_back("content-type", file_mime_type); + additionalHeaders.emplace_back("content-length", std::to_string(content_length) ); + additionalHeaders.emplace_back("accept-ranges", "bytes"); + additionalHeaders.emplace_back("content-range", content_range_header); + additionalHeaders.emplace_back("last-modified", Utils::getDatetimeAsString(fileTime, true) ); + + // Отправить заголовки (206 Partial Content) + if (false == prot.sendHeaders(Http::StatusCode::PARTIAL_CONTENT, additionalHeaders, req.timeout, headersOnly) ) + { + file.close(); + + return 4; + } + + if (false == headersOnly) + { + size_t position, length; + + std::vector buf; + + DataTransfer dt { + content_length, + 0 + }; + + for (auto const &range : ranges) + { + std::tie(position, length) = range; + + buf.resize(length < 512 * 1024 ? length : 512 * 1024); + + file.seekg(position, file.beg); + + size_t send_size_left = length; + + long send_size; + + do + { + if (send_size_left < 512 * 1024) + { + buf.resize(send_size_left); + } + + file.read(buf.data(), buf.size() ); + + auto const read_size = file.gcount(); + + send_size = prot.sendData(buf.data(), read_size, req.timeout, &dt); + + send_size_left -= send_size; + } + while (false == file.eof() && false == file.fail() && send_size > 0 && send_size_left); + } + } + + file.close(); + + return 0; + } + + /** + * Передача файла (или его части) + */ + int Sendfile::transferFile( + const ServerProtocol &prot, + const struct Request &req, + const std::string &fileName, + const std::unordered_map &mimesTypes, + std::vector > &additionalHeaders, + const bool headersOnly + ) noexcept + { + // Get current time in GMT + additionalHeaders.emplace_back("date", Utils::getDatetimeAsString() ); + + time_t file_time; + size_t file_size; + + // Получить размер файла и дату последнего изменения + if (false == System::getFileSizeAndTimeGmt(fileName, &file_size, &file_time) ) + { + prot.sendHeaders(Http::StatusCode::NOT_FOUND, additionalHeaders, req.timeout); + + return 1; + } + + // Check for If-Modified header + auto const it_modified = req.incoming_headers.find("if-modified-since"); + + // Если найден заголовок проверки изменения файла (проверить, изменялся ли файл) + if (req.incoming_headers.cend() != it_modified) + { + const time_t time_in_request = Utils::rfc822DatetimeToTimestamp(it_modified->second); + + if (file_time == time_in_request) + { + prot.sendHeaders(Http::StatusCode::NOT_MODIFIED, additionalHeaders, req.timeout); + + return 2; + } + } + + auto const it_range = req.incoming_headers.find("range"); + + // Range transfer + if (req.incoming_headers.cend() != it_range) + { + return transferFilePart(prot, req, fileName, mimesTypes, file_time, file_size, it_range->second, additionalHeaders, headersOnly); + } + + // File transfer + std::ifstream file(fileName, std::ifstream::binary); + + if ( ! file) + { + file.close(); + + prot.sendHeaders(Http::StatusCode::INTERNAL_SERVER_ERROR, additionalHeaders, req.timeout); + + return 3; + } + + const std::string file_mime_type = getMimeTypeByFileName(fileName, mimesTypes); + + additionalHeaders.emplace_back("content-type", file_mime_type); + additionalHeaders.emplace_back("content-length", std::to_string(file_size) ); + additionalHeaders.emplace_back("accept-ranges", "bytes"); + additionalHeaders.emplace_back("last-modified", Utils::getDatetimeAsString(file_time, true) ); + + // Отправить заголовки (200 OK) + if (false == prot.sendHeaders(Http::StatusCode::OK, additionalHeaders, req.timeout, headersOnly || 0 == file_size) ) + { + file.close(); + + return 4; + } + + // Отправить файл + if (false == headersOnly && file_size) + { + std::vector buf(file_size < 512 * 1024 ? file_size : 512 * 1024); + + long send_size; + + DataTransfer dt { + file_size, + 0 + }; + + do + { + file.read(buf.data(), buf.size() ); + send_size = prot.sendData(buf.data(), file.gcount(), req.timeout, &dt); + } + while (false == file.eof() && false == file.fail() && send_size > 0 && (dt.full_size - dt.send_total) ); + } + + file.close(); + + return 0; + } + + bool Sendfile::isConnectionReuse(const struct Request &req) noexcept + { + return (req.connection_params & ConnectionParams::CONNECTION_REUSE) == ConnectionParams::CONNECTION_REUSE; + } + + void Sendfile::xSendfile( + const ServerProtocol &prot, + struct Request &req, + const std::unordered_map &mimesTypes + ) noexcept + { + auto const it_x_sendfile = req.outgoing_headers.find("x-sendfile"); + + if (req.outgoing_headers.cend() != it_x_sendfile) + { + std::vector > additional_headers; + + if (Transfer::ProtocolVariant::HTTP_1 == req.protocol_variant) + { + if (isConnectionReuse(req) ) + { + additional_headers.emplace_back("connection", "keep-alive"); + additional_headers.emplace_back("keep-alive", "timeout=5; max=" + std::to_string(req.keep_alive_count) ); + } + else + { + additional_headers.emplace_back("connection", "close"); + } + } + + const bool headers_only = ("head" == req.method); + + transferFile(prot, req, it_x_sendfile->second, mimesTypes, additional_headers, headers_only); + } + } +}; diff --git a/src/server/protocol/extensions/Sendfile.h b/src/server/protocol/extensions/Sendfile.h new file mode 100644 index 0000000..eb2823b --- /dev/null +++ b/src/server/protocol/extensions/Sendfile.h @@ -0,0 +1,41 @@ +#pragma once + +#include "../ServerProtocol.h" +#include "../../Request.h" + +namespace HttpServer +{ + class Sendfile + { + private: + static int transferFilePart( + const ServerProtocol &prot, + const struct Request &rp, + const std::string &fileName, + const std::unordered_map &mimesTypes, + const time_t fileTime, + const size_t fileSize, + const std::string &rangeHeader, + std::vector > &additionalHeaders, + const bool headersOnly + ) noexcept; + + static int transferFile( + const ServerProtocol &prot, + const struct Request &req, + const std::string &fileName, + const std::unordered_map &mimesTypes, + std::vector > &additionalHeaders, + const bool headersOnly + ) noexcept; + + public: + static bool isConnectionReuse(const struct Request &req) noexcept; + + static void xSendfile( + const ServerProtocol &prot, + struct Request &req, + const std::unordered_map &mimesTypes + ) 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/SocketList.cpp b/src/socket/List.cpp similarity index 83% rename from src/SocketList.cpp rename to src/socket/List.cpp index e016ed8..2d07b23 100644 --- a/src/SocketList.cpp +++ b/src/socket/List.cpp @@ -1,5 +1,5 @@  -#include "SocketList.h" +#include "List.h" #ifdef POSIX #include @@ -7,9 +7,9 @@ #include #endif -namespace HttpServer +namespace Socket { - SocketList::SocketList() + List::List() noexcept { #ifdef WIN32 this->obj_list = INVALID_HANDLE_VALUE; @@ -20,9 +20,28 @@ namespace HttpServer #endif } - bool SocketList::create(const size_t startListSize) + List::List(List &&obj) noexcept + : obj_list(obj.obj_list) { - destroy(); + #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; @@ -52,9 +71,9 @@ namespace HttpServer #endif } - void SocketList::destroy() + void List::destroy() noexcept { - if (is_created() ) + if (this->is_created() ) { #ifdef WIN32 this->obj_list = INVALID_HANDLE_VALUE; @@ -69,7 +88,7 @@ namespace HttpServer } } - bool SocketList::is_created() const + bool List::is_created() const noexcept { #ifdef WIN32 return this->obj_list != INVALID_HANDLE_VALUE; @@ -80,9 +99,9 @@ namespace HttpServer #endif } - bool SocketList::addSocket(const Socket &sock) + bool List::addSocket(const Socket &sock) noexcept { - if (false == is_created() ) + if (false == this->is_created() ) { return false; } @@ -118,9 +137,9 @@ namespace HttpServer #endif } - bool SocketList::removeSocket(const Socket &sock) + bool List::removeSocket(const Socket &sock) noexcept { - if (false == is_created() ) + if (false == this->is_created() ) { return false; } @@ -152,9 +171,9 @@ namespace HttpServer #endif } - bool SocketList::accept(std::vector &sockets) const + bool List::accept(std::vector &sockets) const noexcept { - if (is_created() ) + if (this->is_created() ) { #ifdef WIN32 const int count = ::WSAPoll(this->poll_events.data(), static_cast<::ULONG>(this->poll_events.size() ), ~0); @@ -224,9 +243,9 @@ namespace HttpServer return false; } - bool SocketList::accept(std::vector &sockets, std::vector &socketsAddress) const + bool List::accept(std::vector &sockets, std::vector &socketsAddress) const noexcept { - if (is_created() ) + if (this->is_created() ) { #ifdef WIN32 const int count = ::WSAPoll(this->poll_events.data(), static_cast<::ULONG>(this->poll_events.size() ), ~0); @@ -249,7 +268,7 @@ namespace HttpServer struct ::sockaddr_in client_addr = {}; socklen_t client_addr_len = sizeof(client_addr); - client_socket = ::accept(event.fd, reinterpret_cast(&client_addr), &client_addr_len); + client_socket = ::accept(event.fd, static_cast(&client_addr), &client_addr_len); if (~0 != client_socket) { @@ -304,9 +323,9 @@ namespace HttpServer return false; } - bool SocketList::recv(std::vector &sockets, std::vector &disconnected, std::chrono::milliseconds timeout) const + bool List::recv(std::vector &sockets, std::vector &disconnected, std::chrono::milliseconds timeout) const noexcept { - if (false == is_created() ) + if (false == this->is_created() ) { return false; } @@ -361,4 +380,4 @@ namespace HttpServer #error "Undefine platform" #endif } -}; \ No newline at end of file +}; diff --git a/src/SocketList.h b/src/socket/List.h similarity index 60% rename from src/SocketList.h rename to src/socket/List.h index 06c8d56..650447f 100644 --- a/src/SocketList.h +++ b/src/socket/List.h @@ -7,9 +7,9 @@ #include #endif -namespace HttpServer +namespace Socket { - class SocketList + class List { protected: #ifdef WIN32 @@ -23,19 +23,21 @@ namespace HttpServer #endif public: - SocketList(); + List() noexcept; + List(List &&obj) noexcept; + ~List() noexcept; bool create(const size_t startListSize = 1); - void destroy(); + void destroy() noexcept; - bool is_created() const; + bool is_created() const noexcept; - bool addSocket(const Socket &sock); - bool removeSocket(const Socket &sock); + bool addSocket(const Socket &sock) noexcept; + bool removeSocket(const Socket &sock) noexcept; - bool accept(std::vector &sockets) const; - bool accept(std::vector &sockets, std::vector &socketsAddress) const; + 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; + bool recv(std::vector &sockets, std::vector &errors, std::chrono::milliseconds timeout = std::chrono::milliseconds(~0) ) const noexcept; }; -}; \ No newline at end of file +}; diff --git a/src/Socket.cpp b/src/socket/Socket.cpp similarity index 73% rename from src/Socket.cpp rename to src/socket/Socket.cpp index 158e2d0..d9b9043 100644 --- a/src/Socket.cpp +++ b/src/socket/Socket.cpp @@ -11,9 +11,9 @@ #include #endif -namespace HttpServer +namespace Socket { - bool Socket::Startup() + bool Socket::Startup() noexcept { #ifdef WIN32 unsigned short version = MAKEWORD(2, 2); @@ -26,7 +26,7 @@ namespace HttpServer #endif } - bool Socket::Cleanup() + bool Socket::Cleanup() noexcept { #ifdef WIN32 return 0 == ::WSACleanup(); @@ -37,7 +37,7 @@ namespace HttpServer #endif } - int Socket::getLastError() + int Socket::getLastError() noexcept { #ifdef WIN32 return ::WSAGetLastError(); @@ -48,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(); @@ -77,7 +77,7 @@ namespace HttpServer return this->is_open(); } - bool Socket::close() + bool Socket::close() noexcept { if (this->is_open() ) { @@ -100,7 +100,7 @@ namespace HttpServer return false; } - bool Socket::is_open() const + bool Socket::is_open() const noexcept { #ifdef WIN32 return INVALID_SOCKET != this->socket_handle; @@ -111,12 +111,12 @@ namespace HttpServer #endif } - System::native_socket_type Socket::get_handle() const + System::native_socket_type Socket::get_handle() const noexcept { return this->socket_handle; } - bool Socket::bind(const int port) const + bool Socket::bind(const int port) const noexcept { const ::sockaddr_in sock_addr = { AF_INET, @@ -128,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) ); @@ -145,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 @@ -176,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 @@ -207,7 +207,7 @@ namespace HttpServer return Socket(client_socket); } - bool Socket::shutdown() const + bool Socket::shutdown() const noexcept { if (is_open() ) { @@ -223,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; @@ -236,7 +236,7 @@ namespace HttpServer } /* - bool Socket::is_nonblock() const + bool Socket::is_nonblock() const noexcept { #ifdef WIN32 @@ -249,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; @@ -262,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(), static_cast(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, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLRDNORM) - { - recv_len = ::recv(this->socket_handle, buf.data(), static_cast(buf.size() ), 0); + { + 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" @@ -304,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; @@ -323,17 +333,17 @@ namespace HttpServer 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; @@ -348,7 +358,7 @@ namespace HttpServer { 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); + const long send_size = ::send(socket_handle, reinterpret_cast(data) + total, static_cast(length - total), 0); if (send_size < 0) { @@ -395,17 +405,17 @@ namespace HttpServer 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 = { @@ -428,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/Cache.h b/src/system/Cache.h new file mode 100644 index 0000000..f8998e2 --- /dev/null +++ b/src/system/Cache.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace System +{ + constexpr int cacheLine = 64; + + template + struct CachePadding + { + private: + static constexpr int padding_size = cacheLine - sizeof(T) % cacheLine; + + uint8_t padding[padding_size > 0 ? padding_size : sizeof(void *)]; + }; + + template + struct CachePaddingSize + { + private: + uint8_t padding[cacheLine - T % cacheLine]; + }; +} diff --git a/src/GlobalMutex.cpp b/src/system/GlobalMutex.cpp similarity index 92% rename from src/GlobalMutex.cpp rename to src/system/GlobalMutex.cpp index 68a0c3a..2079b4e 100644 --- a/src/GlobalMutex.cpp +++ b/src/system/GlobalMutex.cpp @@ -11,14 +11,14 @@ #include #endif -namespace HttpServer +namespace System { - GlobalMutex::GlobalMutex() : mtx_desc(nullptr) + GlobalMutex::GlobalMutex() noexcept : mtx_desc(nullptr) { } - GlobalMutex::~GlobalMutex() + GlobalMutex::~GlobalMutex() noexcept { this->close(); } @@ -150,7 +150,7 @@ namespace HttpServer return true; } - bool GlobalMutex::close() + bool GlobalMutex::close() noexcept { if (this->mtx_desc) { @@ -172,7 +172,7 @@ namespace HttpServer return false; } - bool GlobalMutex::is_open() const + bool GlobalMutex::is_open() const noexcept { #ifdef WIN32 return nullptr != this->mtx_desc; @@ -183,7 +183,7 @@ namespace HttpServer #endif } - bool GlobalMutex::lock() const + bool GlobalMutex::lock() const noexcept { #ifdef WIN32 return WAIT_OBJECT_0 == ::WaitForSingleObject(this->mtx_desc, INFINITE); @@ -194,7 +194,7 @@ namespace HttpServer #endif } - bool GlobalMutex::try_lock() const + bool GlobalMutex::try_lock() const noexcept { #ifdef WIN32 return WAIT_OBJECT_0 == ::WaitForSingleObject(this->mtx_desc, 0); @@ -205,7 +205,7 @@ namespace HttpServer #endif } - bool GlobalMutex::unlock() const + bool GlobalMutex::unlock() const noexcept { #ifdef WIN32 return 0 != ::ReleaseMutex(this->mtx_desc); @@ -215,4 +215,4 @@ namespace HttpServer #error "Undefine platform" #endif } -}; \ No newline at end of file +}; diff --git a/src/GlobalMutex.h b/src/system/GlobalMutex.h similarity index 67% rename from src/GlobalMutex.h rename to src/system/GlobalMutex.h index 42cee55..5250d78 100644 --- a/src/GlobalMutex.h +++ b/src/system/GlobalMutex.h @@ -9,7 +9,7 @@ #include -namespace HttpServer +namespace System { class GlobalMutex { @@ -25,8 +25,8 @@ namespace HttpServer std::string mtx_name; public: - GlobalMutex(); - ~GlobalMutex(); + GlobalMutex() noexcept; + ~GlobalMutex() noexcept; bool create(const std::string &mutexName); bool destory(); @@ -34,12 +34,12 @@ namespace HttpServer static bool destory(const std::string &mutexName); bool open(const std::string &mutexName); - bool close(); + bool close() noexcept; - bool is_open() const; + bool is_open() const noexcept; - bool lock() const; - bool try_lock() const; - bool unlock() const; + bool lock() const noexcept; + bool try_lock() const noexcept; + bool unlock() const noexcept; }; -}; \ No newline at end of file +}; diff --git a/src/Module.cpp b/src/system/Module.cpp similarity index 84% rename from src/Module.cpp rename to src/system/Module.cpp index 50aa0b5..8cbddb1 100644 --- a/src/Module.cpp +++ b/src/system/Module.cpp @@ -12,9 +12,9 @@ #include #endif -namespace HttpServer +namespace System { - Module::Module(): lib_handle(nullptr) + Module::Module() noexcept : lib_handle(nullptr) { } @@ -24,17 +24,17 @@ namespace HttpServer open(libPath); } - Module::Module(const Module &obj) : lib_handle(obj.lib_handle) + Module::Module(const Module &obj) noexcept : lib_handle(obj.lib_handle) { } - Module::Module(Module &&obj) : lib_handle(obj.lib_handle) + Module::Module(Module &&obj) noexcept : lib_handle(obj.lib_handle) { obj.lib_handle = nullptr; } - bool Module::is_open() const + bool Module::is_open() const noexcept { return nullptr != this->lib_handle; } @@ -100,7 +100,7 @@ namespace HttpServer return true; } - void Module::close() + void Module::close() noexcept { if (lib_handle) { @@ -116,7 +116,7 @@ namespace HttpServer } } - bool Module::find(const std::string &symbolName, void *(**addr)(void *) ) const + bool Module::find(const std::string &symbolName, void *(**addr)(void *) ) const noexcept { if (lib_handle) { @@ -140,7 +140,7 @@ namespace HttpServer return false; } - bool Module::find(const char *symbolName, void *(**addr)(void *) ) const + bool Module::find(const char *symbolName, void *(**addr)(void *) ) const noexcept { if (lib_handle) { @@ -164,17 +164,17 @@ namespace HttpServer return false; } - bool Module::operator ==(const Module &obj) const + bool Module::operator ==(const Module &obj) const noexcept { return this->lib_handle == obj.lib_handle; } - bool Module::operator !=(const Module &obj) const + bool Module::operator !=(const Module &obj) const noexcept { return this->lib_handle != obj.lib_handle; } - Module &Module::operator =(const Module &obj) + Module &Module::operator =(const Module &obj) noexcept { if (*this != obj) { @@ -186,7 +186,7 @@ namespace HttpServer return *this; } - Module &Module::operator =(Module &&obj) + Module &Module::operator =(Module &&obj) noexcept { if (*this != obj) { @@ -199,4 +199,4 @@ namespace HttpServer return *this; } -}; \ No newline at end of file +}; diff --git a/src/Module.h b/src/system/Module.h similarity index 51% rename from src/Module.h rename to src/system/Module.h index a1dc301..49e2e34 100644 --- a/src/Module.h +++ b/src/system/Module.h @@ -7,7 +7,7 @@ #include -namespace HttpServer +namespace System { class Module { @@ -21,25 +21,25 @@ namespace HttpServer #endif public: - Module(); + Module() noexcept; Module(const std::string &libPath); - Module(const Module &obj); - Module(Module &&obj); + Module(const Module &obj) noexcept; + Module(Module &&obj) noexcept; - ~Module() = default; + ~Module() noexcept = default; - bool is_open() const; + bool is_open() const noexcept; bool open(const std::string &libPath); - void close(); + void close() noexcept; - bool find(const std::string &symbolName, void *(**addr)(void *) ) const; - bool find(const char *symbolName, void *(**addr)(void *) ) const; + bool find(const std::string &symbolName, void *(**addr)(void *) ) const noexcept; + bool find(const char *symbolName, void *(**addr)(void *) ) const noexcept; - bool operator ==(const Module &obj) const; - bool operator !=(const Module &obj) const; + bool operator ==(const Module &obj) const noexcept; + bool operator !=(const Module &obj) const noexcept; - Module &operator =(const Module &obj); - Module &operator =(Module &&obj); + Module &operator =(const Module &obj) noexcept; + Module &operator =(Module &&obj) noexcept; }; -}; \ No newline at end of file +}; diff --git a/src/SharedMemory.cpp b/src/system/SharedMemory.cpp similarity index 95% rename from src/SharedMemory.cpp rename to src/system/SharedMemory.cpp index 878d3d4..1c0560f 100644 --- a/src/SharedMemory.cpp +++ b/src/system/SharedMemory.cpp @@ -15,9 +15,9 @@ #include -namespace HttpServer +namespace System { - SharedMemory::SharedMemory() + SharedMemory::SharedMemory() noexcept { #ifdef WIN32 this->shm_desc = nullptr; @@ -28,7 +28,7 @@ namespace HttpServer #endif } - SharedMemory::~SharedMemory() + SharedMemory::~SharedMemory() noexcept { this->close(); } @@ -129,7 +129,7 @@ namespace HttpServer return true; } - bool SharedMemory::is_open() const + bool SharedMemory::is_open() const noexcept { #ifdef WIN32 return nullptr != this->shm_desc; @@ -140,7 +140,7 @@ namespace HttpServer #endif } - bool SharedMemory::write(const void *src, const size_t size, const size_t offset) const + bool SharedMemory::write(const void *src, const size_t size, const size_t offset) const noexcept { #ifdef WIN32 @@ -175,7 +175,7 @@ namespace HttpServer return true; } - bool SharedMemory::read(void *dest, const size_t size, const size_t offset) const + bool SharedMemory::read(void *dest, const size_t size, const size_t offset) const noexcept { #ifdef WIN32 @@ -210,7 +210,7 @@ namespace HttpServer return true; } - bool SharedMemory::close() + bool SharedMemory::close() noexcept { if (this->is_open() ) { @@ -281,4 +281,4 @@ namespace HttpServer #error "Undefine platform" #endif } -}; \ No newline at end of file +}; diff --git a/src/SharedMemory.h b/src/system/SharedMemory.h similarity index 76% rename from src/SharedMemory.h rename to src/system/SharedMemory.h index 8ea5b24..d76608f 100644 --- a/src/SharedMemory.h +++ b/src/system/SharedMemory.h @@ -7,7 +7,7 @@ #include -namespace HttpServer +namespace System { class SharedMemory { @@ -23,20 +23,20 @@ namespace HttpServer std::string shm_name; public: - SharedMemory(); - ~SharedMemory(); + SharedMemory() noexcept; + ~SharedMemory() noexcept; bool create(const std::string &memName, const size_t memSize); bool open(const std::string &memName); - bool is_open() const; + bool is_open() const noexcept; - bool write(const void *data, const size_t size, const size_t offset = 0) const; - bool read(void *dest, const size_t size, const size_t offset = 0) const; + bool write(const void *data, const size_t size, const size_t offset = 0) const noexcept; + bool read(void *dest, const size_t size, const size_t offset = 0) const noexcept; - bool close(); + bool close() noexcept; bool destroy(); static bool destroy(const std::string &memName); }; -}; \ No newline at end of file +}; diff --git a/src/System.cpp b/src/system/System.cpp similarity index 97% rename from src/System.cpp rename to src/system/System.cpp index c903837..b32f51c 100644 --- a/src/System.cpp +++ b/src/system/System.cpp @@ -52,7 +52,7 @@ namespace System } #endif - native_processid_type getProcessId() + native_processid_type getProcessId() noexcept { #ifdef WIN32 return ::GetCurrentProcessId(); @@ -80,7 +80,7 @@ namespace System #endif } - bool isProcessExists(const native_processid_type pid) + bool isProcessExists(const native_processid_type pid) noexcept { #ifdef WIN32 HANDLE hProcess = ::OpenProcess(SYNCHRONIZE, false, pid); @@ -93,7 +93,7 @@ namespace System #endif } - bool sendSignal(const native_processid_type pid, const int signal) + bool sendSignal(const native_processid_type pid, const int signal) noexcept { #ifdef WIN32 EnumData ed = {pid, 0}; @@ -113,7 +113,7 @@ namespace System #endif } - bool isDoneThread(const std::thread::native_handle_type handle) + bool isDoneThread(const std::thread::native_handle_type handle) noexcept { #ifdef WIN32 return WAIT_OBJECT_0 == ::WaitForSingleObject(handle, 0); @@ -317,4 +317,4 @@ namespace System #error "Undefine platform" #endif } -}; \ No newline at end of file +}; diff --git a/src/System.h b/src/system/System.h similarity index 88% rename from src/System.h rename to src/system/System.h index 6d5e109..1ce46d2 100644 --- a/src/System.h +++ b/src/system/System.h @@ -3,6 +3,8 @@ #ifdef WIN32 #include + typedef long ssize_t; + ::TCHAR myWndClassName[]; #ifdef SIGTERM @@ -50,15 +52,15 @@ namespace System #error "Undefine platform" #endif - native_processid_type getProcessId(); + native_processid_type getProcessId() noexcept; bool changeCurrentDirectory(const std::string &dir); - bool isProcessExists(const native_processid_type pid); + bool isProcessExists(const native_processid_type pid) noexcept; - bool sendSignal(const native_processid_type pid, const int signal); + bool sendSignal(const native_processid_type pid, const int signal) noexcept; - bool isDoneThread(const std::thread::native_handle_type handle); + bool isDoneThread(const std::thread::native_handle_type handle) noexcept; std::string getTempDir(); @@ -67,4 +69,4 @@ namespace System bool getFileSizeAndTimeGmt(const std::string &filePath, size_t *fileSize, time_t *fileTime); void filterSharedMemoryName(std::string &memName); -}; \ No newline at end of file +}; 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/Event.cpp b/src/utils/Event.cpp similarity index 83% rename from src/Event.cpp rename to src/utils/Event.cpp index 77eeb40..6b23628 100644 --- a/src/Event.cpp +++ b/src/utils/Event.cpp @@ -1,9 +1,10 @@ #include "Event.h" -namespace HttpServer +namespace Utils { - Event::Event(const bool _signaled, const bool _manually): signaled(_signaled), manually(_manually) + Event::Event(const bool signaled, const bool manually) noexcept + : signaled(signaled), manually(manually) { } @@ -73,13 +74,13 @@ namespace HttpServer return is_timeout; } - void Event::notify() + void Event::notify() noexcept { this->signaled.store(true); this->cv.notify_all(); } - void Event::notify(const size_t threadsCount) + void Event::notify(const size_t threadsCount) noexcept { this->signaled.store(true); @@ -89,13 +90,13 @@ namespace HttpServer } } - void Event::reset() + void Event::reset() noexcept { this->signaled.store(false); } - bool Event::notifed() const + bool Event::notifed() const noexcept { return this->signaled.load(); } -}; \ No newline at end of file +}; diff --git a/src/Event.h b/src/utils/Event.h similarity index 59% rename from src/Event.h rename to src/utils/Event.h index c9f1174..ddacbe4 100644 --- a/src/Event.h +++ b/src/utils/Event.h @@ -4,7 +4,7 @@ #include #include -namespace HttpServer +namespace Utils { class Event { @@ -15,19 +15,19 @@ namespace HttpServer bool manually; public: - Event(const bool _signaled = false, const bool _manualy = false); - ~Event() = default; + 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(); - void notify(const size_t threadsCount); + void notify() noexcept; + void notify(const size_t threadsCount) noexcept; - void reset(); + void reset() noexcept; - bool notifed() const; + bool notifed() const noexcept; }; -}; \ No newline at end of file +}; 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 c25275de60ac1e0667f8865b197cb74c702ab6a8 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Fri, 31 Mar 2017 17:06:26 +0300 Subject: [PATCH 30/50] Fixed build for Windows platform (after refactor) --- projects/msvs/httpserver.vcxproj | 125 +++++++++------- projects/msvs/httpserver.vcxproj.filters | 173 ++++++++++++++++------- src/SignalHandlers.cpp | 4 +- src/server/protocol/ServerHttp2.cpp | 2 + src/socket/List.cpp | 4 +- src/socket/Socket.cpp | 4 +- src/transfer/http2/Http2.h | 6 +- 7 files changed, 212 insertions(+), 106 deletions(-) diff --git a/projects/msvs/httpserver.vcxproj b/projects/msvs/httpserver.vcxproj index 4808b5f..ce17aba 100644 --- a/projects/msvs/httpserver.vcxproj +++ b/projects/msvs/httpserver.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -19,57 +19,82 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + {A7023B84-DA18-3E3E-A9AE-B87F45CAC37F} @@ -84,7 +109,7 @@ MultiByte Application release\ - v140 + v141 true @@ -93,7 +118,7 @@ MultiByte Application release\ - v140 + v141 true @@ -102,7 +127,7 @@ MultiByte Application debug\ - v140 + v141 debug\ @@ -110,7 +135,7 @@ MultiByte Application debug\ - v140 + v141 diff --git a/projects/msvs/httpserver.vcxproj.filters b/projects/msvs/httpserver.vcxproj.filters index e539bf5..2968c4b 100644 --- a/projects/msvs/httpserver.vcxproj.filters +++ b/projects/msvs/httpserver.vcxproj.filters @@ -19,153 +19,228 @@ - + 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 - + 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 + + + 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/SignalHandlers.cpp b/src/SignalHandlers.cpp index a187c36..96f2c6c 100644 --- a/src/SignalHandlers.cpp +++ b/src/SignalHandlers.cpp @@ -123,7 +123,7 @@ static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const return 0; } -static ::WPARAM mainMessageLoop(const ::HINSTANCE hInstance, HttpServer::Event * const eventWindowCreation) noexcept +static ::WPARAM mainMessageLoop(const ::HINSTANCE hInstance, Utils::Event * const eventWindowCreation) noexcept { const ::HWND hWnd = ::CreateWindow(myWndClassName, nullptr, 0, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, nullptr, nullptr, hInstance, nullptr); @@ -202,7 +202,7 @@ bool bindSignalHandlers(HttpServer::Server *server) noexcept return false; } - HttpServer::Event eventWindowCreation; + Utils::Event eventWindowCreation; gMainThreadId = ::GetCurrentThreadId(); gThreadMessageLoop = std::thread(mainMessageLoop, hInstance, &eventWindowCreation); diff --git a/src/server/protocol/ServerHttp2.cpp b/src/server/protocol/ServerHttp2.cpp index b04fceb..5e25522 100644 --- a/src/server/protocol/ServerHttp2.cpp +++ b/src/server/protocol/ServerHttp2.cpp @@ -3,6 +3,8 @@ #include "../../utils/Utils.h" #include "../../transfer/http2/HPack.h" +#include + namespace HttpServer { ServerHttp2::ServerHttp2(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, SocketsQueue &sockets) noexcept 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 34afd975c2c78878c86ac6673ef5667250b8a617 Mon Sep 17 00:00:00 2001 From: awwit Date: Wed, 5 Apr 2017 00:40:37 +0300 Subject: [PATCH 31/50] Fixed bugs in the HTTP/2 protocol --- src/server/protocol/ServerHttp2.cpp | 8 ++--- src/server/protocol/ServerHttp2Protocol.cpp | 39 +++++++++++++++------ 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 ++ 11 files changed, 155 insertions(+), 40 deletions(-) diff --git a/src/server/protocol/ServerHttp2.cpp b/src/server/protocol/ServerHttp2.cpp index 5e25522..03813f1 100644 --- a/src/server/protocol/ServerHttp2.cpp +++ b/src/server/protocol/ServerHttp2.cpp @@ -478,16 +478,16 @@ namespace HttpServer static bool getNextHttp2FrameMeta(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, std::vector &buf, Http2::FrameMeta &meta, long &read_size) { - if (read_size <= meta.length + Http2::FRAME_HEADER_SIZE) + if (read_size <= static_cast(meta.length + Http2::FRAME_HEADER_SIZE) ) { - if (read_size == meta.length + Http2::FRAME_HEADER_SIZE) + if (read_size == static_cast(meta.length + Http2::FRAME_HEADER_SIZE) ) { read_size = 0; } read_size = sock.nonblock_recv(buf.data() + read_size, buf.size() - read_size, timeout); - if (read_size < Http2::FRAME_HEADER_SIZE) + if (read_size < static_cast(Http2::FRAME_HEADER_SIZE) ) { return false; } @@ -496,7 +496,7 @@ namespace HttpServer { std::copy(buf.cbegin() + meta.length + Http2::FRAME_HEADER_SIZE, buf.cbegin() + read_size, buf.begin() ); - read_size -= meta.length + Http2::FRAME_HEADER_SIZE; + read_size -= static_cast(meta.length + Http2::FRAME_HEADER_SIZE); } const uint8_t *addr = reinterpret_cast(buf.data() ); diff --git a/src/server/protocol/ServerHttp2Protocol.cpp b/src/server/protocol/ServerHttp2Protocol.cpp index 00f305c..f85417b 100644 --- a/src/server/protocol/ServerHttp2Protocol.cpp +++ b/src/server/protocol/ServerHttp2Protocol.cpp @@ -38,12 +38,11 @@ namespace HttpServer std::vector buf; buf.reserve(4096); + buf.resize(Http2::FRAME_HEADER_SIZE); HPack::pack(buf, headers, this->stream->conn.encoding_dynamic_table); - const uint32_t frame_size = buf.size(); - - buf.insert(buf.begin(), Http2::FRAME_HEADER_SIZE, 0); + const uint32_t frame_size = buf.size() - Http2::FRAME_HEADER_SIZE; Http2::FrameFlag flags = Http2::FrameFlag::END_HEADERS; @@ -54,7 +53,16 @@ namespace HttpServer this->stream->setHttp2FrameHeader(reinterpret_cast(buf.data() ), frame_size, Http2::FrameType::HEADERS, flags); - return this->sock.nonblock_send(buf.data(), buf.size(), timeout) > 0; // >= 0 + this->stream->lock(); + + auto const is_sended = this->sock.nonblock_send(buf.data(), buf.size(), timeout) > 0; // >= 0; + + if (endStream || false == is_sended) + { + this->stream->unlock(); + } + + return is_sended; } long ServerHttp2Protocol::sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const @@ -70,8 +78,6 @@ namespace HttpServer while (size != 0) { - buf.resize(0); - // TODO: test with data_size == 1 (padding length == 0) size_t data_size = setting.max_frame_size < size ? setting.max_frame_size : size; @@ -88,6 +94,8 @@ namespace HttpServer const size_t frame_size = data_size + padding_size; + buf.resize(frame_size + Http2::FRAME_HEADER_SIZE); + /* if (this->stream->window_size_out - frame_size <= 0) { size_t update_size = (dt->full_size - dt->send_total) - this->stream->window_size_out; @@ -109,30 +117,33 @@ namespace HttpServer 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) { + send_size = sended; break; } @@ -144,6 +155,11 @@ namespace HttpServer size -= data_size; } + if (0 >= send_size || dt->full_size == dt->send_total) + { + this->stream->unlock(); + } + return send_size; } @@ -163,6 +179,7 @@ namespace HttpServer Utils::packNumber(buf, this->stream->conn.client_settings.max_frame_size); Utils::packNumber(buf, this->stream->conn.client_settings.max_header_list_size); Utils::packContainer(buf, this->stream->conn.encoding_dynamic_table.getList() ); + Utils::packPointer(buf, &this->stream->conn.sync.mtx); Utils::packContainer(buf, req.incoming_headers); Utils::packContainer(buf, req.incoming_data); Utils::packFilesIncoming(buf, req.incoming_files); 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 cdc448fd298e72aa2cba341a65172be738c8688f Mon Sep 17 00:00:00 2001 From: awwit Date: Wed, 5 Apr 2017 16:48:46 +0300 Subject: [PATCH 32/50] Optimization of synchronization when sending HTTP/2 frames --- src/server/protocol/ServerHttp2.cpp | 68 ++++++++++----------- src/server/protocol/ServerHttp2Protocol.cpp | 27 +++----- 2 files changed, 41 insertions(+), 54 deletions(-) diff --git a/src/server/protocol/ServerHttp2.cpp b/src/server/protocol/ServerHttp2.cpp index 03813f1..5b1e56d 100644 --- a/src/server/protocol/ServerHttp2.cpp +++ b/src/server/protocol/ServerHttp2.cpp @@ -40,7 +40,7 @@ namespace HttpServer return streams.emplace(streamId, Http2::IncStream(streamId, conn) ).first->second; } - static void sendWindowUpdate(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, Http2::IncStream &stream, const uint32_t size) noexcept + static void sendWindowUpdate(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, const Http2::IncStream &stream, const uint32_t size) noexcept { std::array buf; uint8_t *addr = buf.data(); @@ -49,6 +49,8 @@ namespace HttpServer *reinterpret_cast(addr) = ::htonl(size); + const std::unique_lock lock(stream.conn.sync.mtx); + sock.nonblock_send(buf.data(), buf.size(), timeout); } @@ -305,18 +307,22 @@ namespace HttpServer return Http2::ErrorCode::NO_ERROR; } - static void ping(const Socket::Adapter &sock, const struct Request &req, const uint64_t pingData) + static void ping(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, Http2::ConnectionData &conn, const uint64_t pingData) { constexpr uint32_t frame_size = sizeof(uint64_t); std::array buf; uint8_t *addr = buf.data(); - addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::PING, Http2::FrameFlag::ACK, 0); + constexpr uint32_t stream_id = 0; + + addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::PING, Http2::FrameFlag::ACK, stream_id); *reinterpret_cast(addr) = pingData; - sock.nonblock_send(buf.data(), buf.size(), req.timeout); + const std::unique_lock lock(conn.sync.mtx); + + sock.nonblock_send(buf.data(), buf.size(), timeout); } static Http2::ErrorCode parseHttp2Ping(Http2::FrameMeta &meta) @@ -374,21 +380,23 @@ namespace HttpServer return Http2::ErrorCode::NO_ERROR; } - static void rstStream(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, const uint32_t streamId, const Http2::ErrorCode errorCode) + static void rstStream(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, Http2::IncStream &stream, const Http2::ErrorCode errorCode) { constexpr uint32_t frame_size = sizeof(uint32_t); std::array buf; uint8_t *addr = buf.data(); - addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::RST_STREAM, Http2::FrameFlag::EMPTY, streamId); + addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::RST_STREAM, Http2::FrameFlag::EMPTY, stream.stream_id); *reinterpret_cast(addr) = ::htonl(static_cast(errorCode) ); + const std::unique_lock lock(stream.conn.sync.mtx); + sock.nonblock_send(buf.data(), buf.size(), timeout); } - static void sendSettings(const Socket::Adapter &sock, const struct Request &req, const uint8_t *src, const uint8_t *end) + static void sendSettings(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, Http2::ConnectionData &conn, const uint8_t *src, const uint8_t *end) { const uint32_t frame_size = end - src; @@ -402,10 +410,12 @@ namespace HttpServer std::copy(src, end, addr); - sock.nonblock_send(buf.data(), buf.size(), req.timeout); + const std::unique_lock lock(conn.sync.mtx); + + sock.nonblock_send(buf.data(), buf.size(), timeout); } - static void goAway(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, const uint32_t lastStreamId, const Http2::ErrorCode errorCode) + static void goAway(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, Http2::ConnectionData &conn, const uint32_t lastStreamId, const Http2::ErrorCode errorCode) { constexpr uint32_t frame_size = sizeof(uint32_t) * 2; @@ -418,6 +428,8 @@ namespace HttpServer *reinterpret_cast(addr) = ::htonl(static_cast(lastStreamId) ); *reinterpret_cast(addr + sizeof(uint32_t) ) = ::htonl(static_cast(errorCode) ); + const std::unique_lock lock(conn.sync.mtx); + sock.nonblock_send(buf.data(), buf.size(), timeout); } @@ -446,7 +458,7 @@ namespace HttpServer return 0 == compare; } - static void sendEmptySettings(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, const Http2::FrameFlag flags) + static void sendEmptySettings(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, Http2::ConnectionData &conn, const Http2::FrameFlag flags) { constexpr uint32_t frame_size = 0; @@ -457,21 +469,7 @@ namespace HttpServer addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::SETTINGS, flags, stream_id); - sock.nonblock_send(buf.data(), buf.size(), timeout); - } - - static void windowUpdate(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout) - { - constexpr uint32_t frame_size = 4; - - std::array buf; - uint8_t *addr = buf.data(); - - constexpr uint32_t stream_id = 0; - - addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::WINDOW_UPDATE, Http2::FrameFlag::EMPTY, stream_id); - - *reinterpret_cast(addr) = ::htonl(static_cast(1 << 16) - 1); + const std::unique_lock lock(conn.sync.mtx); sock.nonblock_send(buf.data(), buf.size(), timeout); } @@ -512,22 +510,22 @@ namespace HttpServer ServerProtocol *ServerHttp2::process() { struct Request req; - req.timeout = std::chrono::milliseconds(5000); + req.timeout = std::chrono::milliseconds(15000); req.protocol_variant = Transfer::ProtocolVariant::HTTP_2; - sendEmptySettings(this->sock, req.timeout, Http2::FrameFlag::EMPTY); + Http2::ConnectionData conn; + + sendEmptySettings(this->sock, req.timeout, conn, Http2::FrameFlag::EMPTY); if (false == getClientPreface(this->sock, req.timeout) ) { constexpr uint32_t last_stream_id = 0; - goAway(this->sock, req.timeout, last_stream_id, Http2::ErrorCode::PROTOCOL_ERROR); + goAway(this->sock, req.timeout, conn, last_stream_id, Http2::ErrorCode::PROTOCOL_ERROR); return this; } - Http2::ConnectionData conn; - conn.client_settings = Http2::ConnectionSettings::defaultSettings(); conn.server_settings = Http2::ConnectionSettings::defaultSettings(); @@ -565,7 +563,7 @@ namespace HttpServer if (Http2::StreamState::CLOSED == stream.state) { - rstStream(this->sock, req.timeout, stream.stream_id, Http2::ErrorCode::STREAM_CLOSED); + rstStream(this->sock, req.timeout, stream, Http2::ErrorCode::STREAM_CLOSED); continue; } @@ -646,7 +644,7 @@ namespace HttpServer conn.decoding_dynamic_table.changeHeaderTableSize(conn.client_settings.header_table_size); conn.decoding_dynamic_table.changeMaxHeaderListSize(conn.client_settings.max_header_list_size); - sendEmptySettings(this->sock, req.timeout, Http2::FrameFlag::ACK); + sendEmptySettings(this->sock, req.timeout, conn, Http2::FrameFlag::ACK); } break; @@ -664,7 +662,7 @@ namespace HttpServer { const uint64_t ping_data = *reinterpret_cast(addr); - ping(this->sock, req, ping_data); + ping(this->sock, req.timeout, conn, ping_data); } break; @@ -687,7 +685,7 @@ namespace HttpServer { stream.state = Http2::StreamState::CLOSED; - rstStream(this->sock, req.timeout, meta.stream_id, result); + rstStream(this->sock, req.timeout, stream, result); // TODO: remove closed stream(s) from unordered map } @@ -718,7 +716,7 @@ namespace HttpServer conn.sync.event.wait(); } - goAway(this->sock, req.timeout, last_stream_id, Http2::ErrorCode::NO_ERROR); + goAway(this->sock, req.timeout, conn, last_stream_id, Http2::ErrorCode::NO_ERROR); for (auto &pair : streams) { diff --git a/src/server/protocol/ServerHttp2Protocol.cpp b/src/server/protocol/ServerHttp2Protocol.cpp index f85417b..df18c00 100644 --- a/src/server/protocol/ServerHttp2Protocol.cpp +++ b/src/server/protocol/ServerHttp2Protocol.cpp @@ -53,16 +53,9 @@ namespace HttpServer this->stream->setHttp2FrameHeader(reinterpret_cast(buf.data() ), frame_size, Http2::FrameType::HEADERS, flags); - this->stream->lock(); + const std::unique_lock lock(this->stream->conn.sync.mtx); - auto const is_sended = this->sock.nonblock_send(buf.data(), buf.size(), timeout) > 0; // >= 0; - - if (endStream || false == is_sended) - { - this->stream->unlock(); - } - - return is_sended; + return this->sock.nonblock_send(buf.data(), buf.size(), timeout) > 0; // >= 0; } long ServerHttp2Protocol::sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const @@ -128,9 +121,7 @@ namespace HttpServer ++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); @@ -139,7 +130,11 @@ namespace HttpServer 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) { @@ -155,11 +150,6 @@ namespace HttpServer size -= data_size; } - if (0 >= send_size || dt->full_size == dt->send_total) - { - this->stream->unlock(); - } - return send_size; } @@ -192,4 +182,3 @@ namespace HttpServer Utils::unpackContainer(req.outgoing_headers, reinterpret_cast(src) ); } }; - From db3d837d8c8990aab5312d38d01a2d209b417e8a Mon Sep 17 00:00:00 2001 From: awwit Date: Wed, 12 Apr 2017 22:17:39 +0300 Subject: [PATCH 33/50] The path to the application directory is passed to the initialization function --- src/server/Server.cpp | 28 ++++++++-------- src/server/ServerApplicationSettings.h | 4 +-- src/server/ServerSettings.cpp | 5 +-- src/server/config/ConfigParser.cpp | 46 ++++++++++++++------------ src/server/protocol/ServerHttp1.cpp | 7 ++-- 5 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/server/Server.cpp b/src/server/Server.cpp index d46caf0..114c045 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -289,18 +289,19 @@ namespace HttpServer { if (app->application_final) { - app->application_final(); + const std::string root = app->root_dir; + app->application_final(root.data() ); } } catch (std::exception &exc) { - std::cout << "Warning: error when the application finishes '" << app->server_module << "':" << exc.what() << std::endl; + std::cout << "Warning: an exception was thrown when the application '" << app->server_module << "' was finishes: " << exc.what() << std::endl; } app->application_call = std::function(); app->application_clear = std::function(); - app->application_init = std::function(); - app->application_final = std::function(); + app->application_init = std::function(); + app->application_final = std::function(); } } @@ -423,18 +424,18 @@ namespace HttpServer std::function app_clear = reinterpret_cast(addr); - std::function app_init = std::function(); + std::function app_init = std::function(); if (module.find("application_init", &addr) ) { - app_init = reinterpret_cast(addr); + app_init = reinterpret_cast(addr); } - std::function app_final = std::function(); + std::function app_final = std::function(); if (module.find("application_final", &addr) ) { - app_final = reinterpret_cast(addr); + app_final = reinterpret_cast(addr); } for (auto &app : same) @@ -448,12 +449,13 @@ namespace HttpServer { if (app->application_init) { - app->application_init(); + const std::string root = app->root_dir; + app->application_init(root.data() ); } } catch (std::exception &exc) { - std::cout << "Warning: error when initializing the application '" << module_name << "':" << exc.what() << std::endl; + std::cout << "Warning: an exception was thrown when the application '" << module_name << "' was initialized: " << exc.what() << std::endl; } } @@ -502,7 +504,7 @@ namespace HttpServer } } - std::cout << "Notice: applications' modules have been updated;" << std::endl; + std::cout << "Notice: application modules have been updated;" << std::endl; this->controls.setProcess(); this->controls.eventUpdateModule->reset(); @@ -780,7 +782,7 @@ namespace HttpServer sockets_list.addSocket(sock); } - std::cout << "Log: launch server's cycle;" << std::endl << std::endl; + std::cout << "Log: server started work;" << std::endl << std::endl; constexpr size_t queue_max_length = 1024; this->controls.eventNotFullQueue = new Utils::Event(true, true); @@ -855,7 +857,7 @@ namespace HttpServer this->clear(); - std::cout << "Log: complete server's cycle;" << std::endl; + std::cout << "Log: server work completed;" << std::endl; return EXIT_SUCCESS; } diff --git a/src/server/ServerApplicationSettings.h b/src/server/ServerApplicationSettings.h index 7d2cb38..b1bd9d6 100644 --- a/src/server/ServerApplicationSettings.h +++ b/src/server/ServerApplicationSettings.h @@ -31,7 +31,7 @@ namespace HttpServer std::function application_call; std::function application_clear; - std::function application_init; - std::function application_final; + std::function application_init; + std::function application_final; }; }; diff --git a/src/server/ServerSettings.cpp b/src/server/ServerSettings.cpp index 7890fb6..166f2dc 100644 --- a/src/server/ServerSettings.cpp +++ b/src/server/ServerSettings.cpp @@ -38,12 +38,13 @@ namespace HttpServer { if (app->application_final) { - app->application_final(); + const std::string root = app->root_dir; + app->application_final(root.data() ); } } catch (std::exception &exc) { - std::cout << "Warning: the error of the application's finalize '" << app->server_module << "':" << exc.what() << std::endl; + std::cout << "Warning: an exception was thrown when the application '" << app->server_module << "' was finishes: " << exc.what() << std::endl; } delete app; diff --git a/src/server/config/ConfigParser.cpp b/src/server/config/ConfigParser.cpp index 0767cd8..7ae4490 100644 --- a/src/server/config/ConfigParser.cpp +++ b/src/server/config/ConfigParser.cpp @@ -244,18 +244,33 @@ namespace HttpServer std::function app_clear = reinterpret_cast(addr); - std::function app_init = std::function(); + std::function app_init = std::function(); if (module.find("application_init", &addr) ) { - app_init = reinterpret_cast(addr); + app_init = reinterpret_cast(addr); } - std::function app_final = std::function(); + std::function app_final = std::function(); if (module.find("application_final", &addr) ) { - app_final = reinterpret_cast(addr); + app_final = reinterpret_cast(addr); + } + + std::string root_dir = it_root_dir->second; + + #ifdef WIN32 + if ('\\' == root_dir.back() ) + { + root_dir.pop_back(); + } + #endif + + // Remove back slash from root_dir + if ('/' == root_dir.back() ) + { + root_dir.pop_back(); } bool success = true; @@ -264,17 +279,21 @@ namespace HttpServer { if (app_init) { - success = app_init(); + const std::string root = root_dir; + success = app_init(root.data() ); } } - catch (...) + catch (std::exception &exc) { + std::cout << "Warning: an exception was thrown when the application '" << it_module->second << "' was initialized: " << exc.what() << std::endl; + success = false; } if (false == success) { std::cout << "Warning: error when initializing application '" << it_module->second << "';" << std::endl; + return false; } @@ -308,21 +327,6 @@ namespace HttpServer modules.emplace_back(std::move(module) ); } - std::string root_dir = it_root_dir->second; - - #ifdef WIN32 - if ('\\' == root_dir.back() ) - { - root_dir.pop_back(); - } - #endif - - // Remove back slash from root_dir - if ('/' == root_dir.back() ) - { - root_dir.pop_back(); - } - // Create application settings struct ServerApplicationSettings *settings = new ServerApplicationSettings { std::move(ports), diff --git a/src/server/protocol/ServerHttp1.cpp b/src/server/protocol/ServerHttp1.cpp index c8c24c1..290ae9b 100644 --- a/src/server/protocol/ServerHttp1.cpp +++ b/src/server/protocol/ServerHttp1.cpp @@ -54,9 +54,12 @@ namespace HttpServer long ServerHttp1::sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const { - long send_size = this->sock.nonblock_send(src, size, timeout); + const long send_size = this->sock.nonblock_send(src, size, timeout); - dt->send_total += send_size; + if (send_size > 0) + { + dt->send_total += send_size; + } return send_size; } From e284a0687019ff04a30edfeb78d35c5d146cf169 Mon Sep 17 00:00:00 2001 From: awwit Date: Sun, 7 May 2017 16:11:33 +0300 Subject: [PATCH 34/50] Added build variant using Makefile --- Makefile | 34 ++++++++++++++++++++++++++++++++++ README.md | 8 ++++++++ 2 files changed, 42 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5ff0f59 --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +RM = rm -rf +MKDIR = mkdir -p + +#CXX = g++ +CXXFLAGS += -std=c++14 -c -Wall -O2 +LDFLAGS = -ldl -lpthread -lrt -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)/httpserver + +.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 75bcf02..0546a29 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,14 @@ Windows: `ws2_32.lib`, `libgnutls.dll.a` Linux: +```sh +git clone https://github.com/awwit/httpserver.git +cd httpserver +make +``` + +or + ```sh git clone https://github.com/awwit/httpserver.git cd httpserver From d424a62d5d3ec5b426324e5043c23825d324ec58 Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Wed, 10 May 2017 00:11:31 +0300 Subject: [PATCH 35/50] Fixed signal processing (and termination) for Windows --- src/SignalHandlers.cpp | 19 ++++++++----------- src/server/Server.cpp | 30 ++++++++++++++++++++++++++++++ src/server/Server.h | 4 ++++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/SignalHandlers.cpp b/src/SignalHandlers.cpp index 96f2c6c..a3af7eb 100644 --- a/src/SignalHandlers.cpp +++ b/src/SignalHandlers.cpp @@ -21,7 +21,7 @@ static void handlerSigTerm(const int) noexcept { if (globalServerPtr) { - globalServerPtr->controls.stopProcess(); + globalServerPtr->stop(); } } @@ -32,7 +32,7 @@ static void handlerSigInt(const int) noexcept { if (globalServerPtr) { - globalServerPtr->controls.stopProcess(); + globalServerPtr->stop(); } } @@ -43,8 +43,7 @@ static void handlerSigUsr1(const int) noexcept { if (globalServerPtr) { - globalServerPtr->controls.setRestart(); - globalServerPtr->controls.stopProcess(); + globalServerPtr->restart(); } } @@ -55,9 +54,7 @@ static void handlerSigUsr2(const int) noexcept { if (globalServerPtr) { - globalServerPtr->controls.setUpdateModule(); - globalServerPtr->controls.setProcess(false); - globalServerPtr->controls.setProcessQueue(); + globalServerPtr->update(); } } @@ -108,7 +105,7 @@ static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const case WM_ENDSESSION: { - ::HANDLE hThread = ::OpenThread(SYNCHRONIZE, false, gMainThreadId); + const ::HANDLE hThread = ::OpenThread(SYNCHRONIZE, false, gMainThreadId); ::WaitForSingleObject(hThread, INFINITE); ::CloseHandle(hThread); break; @@ -158,7 +155,7 @@ static ::BOOL consoleSignalHandler(const ::DWORD ctrlType) noexcept case CTRL_SHUTDOWN_EVENT: { handlerSigTerm(ctrlType); - ::HANDLE hThread = ::OpenThread(SYNCHRONIZE, false, gMainThreadId); + const ::HANDLE hThread = ::OpenThread(SYNCHRONIZE, false, gMainThreadId); ::WaitForSingleObject(hThread, INFINITE); ::CloseHandle(hThread); return true; @@ -190,7 +187,7 @@ bool bindSignalHandlers(HttpServer::Server *server) noexcept const ::HINSTANCE hInstance = ::GetModuleHandle(nullptr); - ::WNDCLASSEX wcex = {}; + ::WNDCLASSEX wcex {}; wcex.cbSize = sizeof(::WNDCLASSEX); wcex.lpfnWndProc = WndProc; @@ -211,7 +208,7 @@ bool bindSignalHandlers(HttpServer::Server *server) noexcept #elif POSIX - struct ::sigaction act = {}; + struct ::sigaction act {}; act.sa_handler = handlerSigInt; ::sigaction(SIGINT, &act, nullptr); diff --git a/src/server/Server.cpp b/src/server/Server.cpp index 114c045..30846c5 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -1009,6 +1009,36 @@ namespace HttpServer return code; } + static void close_liseners(std::vector &liseners) + { + for (auto &sock : liseners) + { + sock.close(); + } + } + + void Server::stop() + { + this->controls.stopProcess(); + + close_liseners(this->liseners); + } + + void Server::restart() + { + this->controls.setRestart(); + this->controls.stopProcess(); + + close_liseners(this->liseners); + } + + void Server::update() + { + this->controls.setUpdateModule(); + this->controls.setProcess(false); + this->controls.setProcessQueue(); + } + System::native_processid_type Server::getServerProcessId(const std::string &serverName) { System::native_processid_type pid = 0; diff --git a/src/server/Server.h b/src/server/Server.h index 4218ad8..e09984a 100644 --- a/src/server/Server.h +++ b/src/server/Server.h @@ -53,6 +53,10 @@ namespace HttpServer public: Server() = default; + void stop(); + void restart(); + void update(); + int command_help(const int argc, const char *argv[]) const; int command_start(const int argc, const char *argv[]); int command_restart(const int argc, const char *argv[]) const; From f5f0cb9e97e8cb9cd520fae40e97182945dcecf6 Mon Sep 17 00:00:00 2001 From: awwit Date: Wed, 2 Aug 2017 15:36:52 +0300 Subject: [PATCH 36/50] Fixed bug in function Utils::explode --- src/utils/Utils.cpp | 6 +++--- src/utils/Utils.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) 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 528961805fe8e71d3c5d9269467dfbb61300091f Mon Sep 17 00:00:00 2001 From: awwit Date: Sat, 11 Nov 2017 19:29:09 +0300 Subject: [PATCH 37/50] Fixed bug in HTTPS: interrupt receiving data. Code styling --- src/SignalHandlers.cpp | 60 +++----- src/socket/Adapter.cpp | 14 +- src/socket/Adapter.h | 2 +- src/socket/AdapterDefault.cpp | 25 ++-- src/socket/AdapterDefault.h | 2 +- src/socket/AdapterTls.cpp | 54 +++---- src/socket/AdapterTls.h | 2 +- src/socket/Socket.cpp | 118 +++++---------- 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 +- 25 files changed, 319 insertions(+), 648 deletions(-) diff --git a/src/SignalHandlers.cpp b/src/SignalHandlers.cpp index a3af7eb..80bbc7d 100644 --- a/src/SignalHandlers.cpp +++ b/src/SignalHandlers.cpp @@ -17,10 +17,8 @@ static HttpServer::Server *globalServerPtr = nullptr; /** * Terminate signal */ -static void handlerSigTerm(const int) noexcept -{ - if (globalServerPtr) - { +static void handlerSigTerm(const int) noexcept { + if (globalServerPtr) { globalServerPtr->stop(); } } @@ -28,10 +26,8 @@ static void handlerSigTerm(const int) noexcept /** * Interrupt signal */ -static void handlerSigInt(const int) noexcept -{ - if (globalServerPtr) - { +static void handlerSigInt(const int) noexcept { + if (globalServerPtr) { globalServerPtr->stop(); } } @@ -39,10 +35,8 @@ static void handlerSigInt(const int) noexcept /** * Signal to restart */ -static void handlerSigUsr1(const int) noexcept -{ - if (globalServerPtr) - { +static void handlerSigUsr1(const int) noexcept { + if (globalServerPtr) { globalServerPtr->restart(); } } @@ -50,10 +44,8 @@ static void handlerSigUsr1(const int) noexcept /** * Signal to update modules */ -static void handlerSigUsr2(const int) noexcept -{ - if (globalServerPtr) - { +static void handlerSigUsr2(const int) noexcept { + if (globalServerPtr) { globalServerPtr->update(); } } @@ -68,51 +60,44 @@ static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const { switch (message) { - case SIGTERM: - { + case SIGTERM: { handlerSigTerm(message); ::PostMessage(hWnd, WM_QUIT, 0, 0); // Fuck ::PostQuitMessage(0); break; } - case SIGINT: - { + case SIGINT: { handlerSigInt(message); ::PostMessage(hWnd, WM_QUIT, 0, 0); // Fuck ::PostQuitMessage(0); break; } - case SIGUSR1: - { + case SIGUSR1: { handlerSigUsr1(message); break; } - case SIGUSR2: - { + case SIGUSR2: { handlerSigUsr2(message); break; } // Cases WM_QUERYENDSESSION and WM_ENDSESSION run before shutting down the system (or ending user session) - case WM_QUERYENDSESSION: - { + case WM_QUERYENDSESSION: { handlerSigTerm(message); break; } - case WM_ENDSESSION: - { + case WM_ENDSESSION: { const ::HANDLE hThread = ::OpenThread(SYNCHRONIZE, false, gMainThreadId); ::WaitForSingleObject(hThread, INFINITE); ::CloseHandle(hThread); break; } - default: - { + default: { return ::DefWindowProc(hWnd, message, wParam, lParam); } } @@ -126,15 +111,13 @@ static ::WPARAM mainMessageLoop(const ::HINSTANCE hInstance, Utils::Event * cons eventWindowCreation->notify(); // After this action, eventWindowCreation will be destroyed (in the other thread) - if (0 == hWnd) - { + if (0 == hWnd) { return 0; } ::MSG msg; - while (::GetMessage(&msg, hWnd, 0, 0) ) - { + while (::GetMessage(&msg, hWnd, 0, 0) ) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } @@ -152,8 +135,7 @@ static ::BOOL consoleSignalHandler(const ::DWORD ctrlType) noexcept // @see my function WndProc -> cases WM_QUERYENDSESSION and WM_ENDSESSION. Only they happen in this program, because the library user32.dll is connected. // @prooflink: https://msdn.microsoft.com/library/windows/desktop/ms686016(v=vs.85).aspx case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - { + case CTRL_SHUTDOWN_EVENT: { handlerSigTerm(ctrlType); const ::HANDLE hThread = ::OpenThread(SYNCHRONIZE, false, gMainThreadId); ::WaitForSingleObject(hThread, INFINITE); @@ -161,9 +143,10 @@ static ::BOOL consoleSignalHandler(const ::DWORD ctrlType) noexcept return true; } - case CTRL_C_EVENT: + case CTRL_C_EVENT: { handlerSigInt(ctrlType); return true; + } default: return false; @@ -194,8 +177,7 @@ bool bindSignalHandlers(HttpServer::Server *server) noexcept wcex.hInstance = hInstance; wcex.lpszClassName = myWndClassName; - if (0 == ::RegisterClassEx(&wcex) ) - { + if (::RegisterClassEx(&wcex) == 0) { return false; } 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..afd4ca2 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); } @@ -125,18 +112,23 @@ 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 - { + 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 +140,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..f787e31 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 @@ -319,7 +294,7 @@ namespace Socket #ifdef WIN32 WSAPOLLFD event = { this->socket_handle, - POLLRDNORM | POLLRDBAND, + POLLIN, 0 }; @@ -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); } @@ -373,25 +344,20 @@ 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) - { + 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 (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); } @@ -443,7 +402,7 @@ namespace Socket #ifdef WIN32 WSAPOLLFD event = { this->socket_handle, - POLLWRNORM, + POLLOUT, 0 }; @@ -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..35771ba 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 (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 77c54db0adbe8d70210cc7c0b10f551d52b14252 Mon Sep 17 00:00:00 2001 From: awwit Date: Mon, 13 Nov 2017 02:25:48 +0300 Subject: [PATCH 38/50] Fixed stuck threads and interruption of data reception over HTTPS --- src/server/Server.cpp | 313 +++++++++------------------- src/server/protocol/ServerHttp2.cpp | 137 ++++-------- src/server/protocol/ServerHttp2.h | 2 +- src/socket/AdapterTls.cpp | 7 +- src/socket/List.cpp | 89 +++----- src/socket/List.h | 2 +- src/socket/Socket.cpp | 6 +- src/socket/Socket.h | 2 +- src/utils/Event.cpp | 6 +- 9 files changed, 187 insertions(+), 377 deletions(-) diff --git a/src/server/Server.cpp b/src/server/Server.cpp index 30846c5..3f87c92 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -38,10 +38,8 @@ namespace HttpServer std::unique_ptr prot; // If request is HTTP/2 Stream - if (stream) - { + if (stream) { prot.reset(new ServerHttp2Stream(sock, settings, controls, stream) ); - return prot; } @@ -53,12 +51,10 @@ namespace HttpServer { const std::string protocol(reinterpret_cast(datum.data), datum.size); - if ("h2" == protocol) - { + if ("h2" == protocol) { prot.reset(new ServerHttp2(sock, settings, controls, sockets) ); } - else if ("http/1.1" == protocol) - { + else if ("http/1.1" == protocol) { prot.reset(new ServerHttp1(sock, settings, controls) ); } } @@ -78,15 +74,12 @@ namespace HttpServer { std::unique_ptr prot = getProtocolVariant(sock, this->settings, this->controls, sockets, stream); - if (prot) - { + if (prot) { // Check if switching protocol - for (ServerProtocol *ret = nullptr; ; ) - { + for (ServerProtocol *ret = nullptr; ; ) { ret = prot->process(); - if (prot.get() == ret) - { + if (prot.get() == ret) { break; } @@ -110,15 +103,13 @@ namespace HttpServer eventThreadCycle.wait(); - if (false == this->controls.process_flag) - { + if (this->controls.process_flag == false) { break; } sockets.lock(); - if (sockets.size() ) - { + if (sockets.size() ) { std::tie(sock, stream) = sockets.front(); /* sockaddr_in addr {}; @@ -128,10 +119,8 @@ namespace HttpServer sockets.pop(); } - if (sockets.empty() ) - { + if (sockets.empty() ) { eventThreadCycle.reset(); - this->controls.eventNotFullQueue->notify(); } @@ -168,8 +157,7 @@ namespace HttpServer std::get(data) ); - if (socket_adapter.handshake() ) - { + if (socket_adapter.handshake() ) { this->threadRequestProc(socket_adapter, sockets, nullptr); } } @@ -195,19 +183,15 @@ namespace HttpServer size_t threads_max_count = 0; - if (this->settings.global.cend() != it_option) - { + if (this->settings.global.cend() != it_option) { const std::string &option = it_option->second; - threads_max_count = std::strtoull(option.c_str(), nullptr, 10); } - if (0 == threads_max_count) - { + if (0 == threads_max_count) { threads_max_count = std::thread::hardware_concurrency(); - if (0 == threads_max_count) - { + if (0 == threads_max_count) { threads_max_count = 1; } @@ -225,16 +209,13 @@ namespace HttpServer active_threads.reserve(threads_max_count); // For update applications modules - do - { - if (this->controls.eventUpdateModule->notifed() ) - { + do { + if (this->controls.eventUpdateModule->notifed() ) { updateModules(); } // Cycle creation threads applications requests - do - { + do { while (this->threads_working_count == active_threads.size() && active_threads.size() < threads_max_count && sockets.empty() == false) { active_threads.emplace_back(serverThreadRequestCycle, this, std::ref(sockets), std::ref(eventThreadCycle) ); @@ -242,8 +223,7 @@ namespace HttpServer size_t notify_count = active_threads.size() - this->threads_working_count; - if (notify_count > sockets.size() ) - { + if (notify_count > sockets.size() ) { notify_count = sockets.size(); } @@ -257,11 +237,9 @@ namespace HttpServer eventThreadCycle.notify(); - if (false == active_threads.empty() ) - { + if (active_threads.empty() == false) { // Join threads (wait completion) - for (auto &th : active_threads) - { + for (auto &th : active_threads) { th.join(); } @@ -285,16 +263,13 @@ namespace HttpServer { same.emplace(app); - try - { - if (app->application_final) - { + try { + if (app->application_final) { const std::string root = app->root_dir; app->application_final(root.data() ); } } - catch (std::exception &exc) - { + catch (std::exception &exc) { std::cout << "Warning: an exception was thrown when the application '" << app->server_module << "' was finishes: " << exc.what() << std::endl; } @@ -314,16 +289,14 @@ namespace HttpServer #ifdef WIN32 std::ifstream src(app->server_module_update, std::ifstream::binary); - if ( ! src) - { + if ( ! src) { std::cout << "Error: file '" << app->server_module_update << "' cannot be open;" << std::endl; return false; } std::ofstream dst(module_name, std::ofstream::binary | std::ofstream::trunc); - if ( ! dst) - { + if ( ! dst) { std::cout << "Error: file '" << module_name << "' cannot be open;" << std::endl; return false; } @@ -345,27 +318,22 @@ namespace HttpServer std::string module_name_temp; - if (std::string::npos != ext_pos && (std::string::npos == dir_pos || dir_pos < ext_pos) ) - { + if (std::string::npos != ext_pos && (std::string::npos == dir_pos || dir_pos < ext_pos) ) { module_name_temp = module_name.substr(0, ext_pos) + '-' + Utils::getUniqueName() + module_name.substr(ext_pos); - } - else - { + } else { module_name_temp = module_name + '-' + Utils::getUniqueName(); } std::ifstream src(app->server_module_update, std::ifstream::binary); - if ( ! src) - { + if ( ! src) { std::cout << "Error: file '" << app->server_module_update << "' cannot be open;" << std::endl; return false; } std::ofstream dst(module_name_temp, std::ofstream::binary | std::ofstream::trunc); - if ( ! dst) - { + if ( ! dst) { std::cout << "Error: file '" << module_name << "' cannot be open;" << std::endl; return false; } @@ -379,14 +347,12 @@ namespace HttpServer // Open updated module module.open(module_name_temp); - if (0 != std::remove(module_name.c_str() ) ) - { + if (0 != std::remove(module_name.c_str() ) ) { std::cout << "Error: file '" << module_name << "' could not be removed;" << std::endl; return false; } - if (0 != std::rename(module_name_temp.c_str(), module_name.c_str() ) ) - { + if (0 != std::rename(module_name_temp.c_str(), module_name.c_str() ) ) { std::cout << "Error: file '" << module_name_temp << "' could not be renamed;" << std::endl; return false; } @@ -394,30 +360,26 @@ namespace HttpServer #error "Undefined platform" #endif - if (false == module.is_open() ) - { + if (module.is_open() == false) { std::cout << "Error: the application module '" << module_name << "' can not be opened;" << std::endl; return false; } void *(*addr)(void *) = nullptr; - if (false == module.find("application_call", &addr) ) - { + if (module.find("application_call", &addr) == false) { std::cout << "Error: function 'application_call' was not found in the module '" << module_name << "';" << std::endl; return false; } std::function app_call = reinterpret_cast(addr); - if ( ! app_call) - { + if ( ! app_call) { std::cout << "Error: invalid function 'application_call' is in the module '" << module_name << "';" << std::endl; return false; } - if (false == module.find("application_clear", &addr) ) - { + if (module.find("application_clear", &addr) == false) { std::cout << "Error: function 'application_clear' was not found in the module '" << module_name << "';" << std::endl; return false; } @@ -426,15 +388,13 @@ namespace HttpServer std::function app_init = std::function(); - if (module.find("application_init", &addr) ) - { + if (module.find("application_init", &addr) ) { app_init = reinterpret_cast(addr); } std::function app_final = std::function(); - if (module.find("application_final", &addr) ) - { + if (module.find("application_final", &addr) ) { app_final = reinterpret_cast(addr); } @@ -445,16 +405,13 @@ namespace HttpServer app->application_init = app_init; app->application_final = app_final; - try - { - if (app->application_init) - { + try { + if (app->application_init) { const std::string root = app->root_dir; app->application_init(root.data() ); } } - catch (std::exception &exc) - { + catch (std::exception &exc) { std::cout << "Warning: an exception was thrown when the application '" << module_name << "' was initialized: " << exc.what() << std::endl; } } @@ -478,7 +435,7 @@ namespace HttpServer // If module is not updated (not checked) if (updated.cend() == updated.find(module_index) ) { - if (false == app->server_module_update.empty() && app->server_module_update != app->server_module) + if (app->server_module_update.empty() == false && app->server_module_update != app->server_module) { size_t module_size_new = 0; time_t module_time_new = 0; @@ -490,10 +447,8 @@ namespace HttpServer System::Module &module = this->modules[module_index]; - if (System::getFileSizeAndTimeGmt(app->server_module, &module_size_cur, &module_time_cur) ) - { - if (module_size_cur != module_size_new || module_time_cur < module_time_new) - { + if (System::getFileSizeAndTimeGmt(app->server_module, &module_size_cur, &module_time_cur) ) { + if (module_size_cur != module_size_new || module_time_cur < module_time_new) { this->updateModule(module, applications, module_index); } } @@ -532,10 +487,8 @@ namespace HttpServer { this->controls.clear(); - if (false == this->tls_data.empty() ) - { - for (auto &pair : this->tls_data) - { + if (this->tls_data.empty() == false) { + for (auto &pair : this->tls_data) { std::tuple &data = pair.second; ::gnutls_certificate_free_credentials(std::get(data) ); @@ -545,10 +498,8 @@ namespace HttpServer this->settings.clear(); - if (false == this->modules.empty() ) - { - for (auto &module : this->modules) - { + if (this->modules.empty() == false) { + for (auto &module : this->modules) { module.close(); } @@ -566,48 +517,41 @@ namespace HttpServer int ret = ::gnutls_certificate_allocate_credentials(&x509_cred); - if (ret < 0) - { + if (ret < 0) { std::cout << "Error [tls]: certificate credentials has not been allocated;" << std::endl; - return false; } - if (false == app.chain_file.empty() ) + if (app.chain_file.empty() == false) { ret = ::gnutls_certificate_set_x509_trust_file(x509_cred, app.chain_file.c_str(), GNUTLS_X509_FMT_PEM); - if (ret < 0) - { + if (ret < 0) { std::cout << "Warning [tls]: (CA) chain file has not been accepted;" << std::endl; } } - if (false == app.crl_file.empty() ) + if (app.crl_file.empty() == false) { ret = ::gnutls_certificate_set_x509_crl_file(x509_cred, app.crl_file.c_str(), GNUTLS_X509_FMT_PEM); - if (ret < 0) - { + if (ret < 0) { std::cout << "Warning [tls]: (CLR) clr file has not been accepted;" << std::endl; } } ret = ::gnutls_certificate_set_x509_key_file(x509_cred, app.cert_file.c_str(), app.key_file.c_str(), GNUTLS_X509_FMT_PEM); - if (ret < 0) - { + if (ret < 0) { std::cout << "Error [tls]: (CERT) cert file or/and (KEY) key file has not been accepted;" << std::endl; - return false; } - if (false == app.stapling_file.empty() ) + if (app.stapling_file.empty() == false) { ret = ::gnutls_certificate_set_ocsp_status_request_file(x509_cred, app.stapling_file.c_str(), 0); - if (ret < 0) - { + if (ret < 0) { std::cout << "Warning [tls]: (OCSP) stapling file has not been accepted;" << std::endl; } } @@ -651,12 +595,9 @@ namespace HttpServer dh_file.close(); } - if (ret < 0) - { + if (ret < 0) { ::gnutls_certificate_free_credentials(x509_cred); - std::cout << "Error [tls]: DH params were not loaded;" << std::endl; - return false; } @@ -666,12 +607,9 @@ namespace HttpServer ret = ::gnutls_priority_init(&priority_cache, "NORMAL", nullptr); - if (ret < 0) - { + if (ret < 0) { ::gnutls_certificate_free_credentials(x509_cred); - std::cout << "Error [tls]: priority cache cannot be init;" << std::endl; - return false; } @@ -683,27 +621,23 @@ namespace HttpServer bool Server::tryBindPort(const int port, std::unordered_set &ports) { // Only unique ports - if (ports.cend() != ports.find(port) ) - { + if (ports.cend() != ports.find(port) ) { return false; } Socket::Socket sock; - if (false == sock.open() ) - { + if (sock.open() == false) { std::cout << "Error: socket cannot be open; errno " << Socket::Socket::getLastError() << ";" << std::endl; return false; } - if (false == sock.bind(port) ) - { + if (sock.bind(port) == false) { std::cout << "Error: port " << port << " cannot be bind; errno " << Socket::Socket::getLastError() << ";" << std::endl; return false; } - if (false == sock.listen() ) - { + if (sock.listen() == false) { std::cout << "Error: socket " << port << " cannot be listen; errno " << Socket::Socket::getLastError() << ";" << std::endl; return false; } @@ -732,16 +666,12 @@ namespace HttpServer { const std::unordered_set &tls = app->tls_ports; - if (false == tls.empty() ) - { + if (tls.empty() == false) { std::tuple data; - if (tlsInit(*app, data) ) - { - for (const int port : tls) - { - if (this->tryBindPort(port, ports) ) - { + if (tlsInit(*app, data) ) { + for (const int port : tls) { + if (this->tryBindPort(port, ports) ) { this->tls_data.emplace(port, data); } } @@ -750,8 +680,7 @@ namespace HttpServer const std::unordered_set &list = app->ports; - for (const int port : list) - { + for (const int port : list) { this->tryBindPort(port, ports); } } @@ -759,15 +688,13 @@ namespace HttpServer int Server::run() { - if (false == this->init() ) - { + if (this->init() == false) { return 0x10; } this->initAppsPorts(); - if (this->liseners.empty() ) - { + if (this->liseners.empty() ) { std::cout << "Error: any socket was not open;" << std::endl; this->clear(); return 0x20; @@ -777,8 +704,7 @@ namespace HttpServer sockets_list.create(this->liseners.size() ); - for (auto const &sock : this->liseners) - { + for (auto const &sock : this->liseners) { sockets_list.addSocket(sock); } @@ -799,8 +725,7 @@ namespace HttpServer std::vector accept_sockets; // Cycle for receiving new connections - do - { + do { if (sockets_list.accept(accept_sockets) ) { sockets.lock(); @@ -827,8 +752,7 @@ namespace HttpServer this->controls.eventProcessQueue->notify(); - if (sockets.size() >= queue_max_length) - { + if (sockets.size() >= queue_max_length) { this->controls.eventNotFullQueue->reset(); } @@ -845,10 +769,8 @@ namespace HttpServer sockets_list.destroy(); - if (false == this->liseners.empty() ) - { - for (Socket::Socket &sock : this->liseners) - { + if (this->liseners.empty() == false) { + for (Socket::Socket &sock : this->liseners) { sock.close(); } @@ -866,32 +788,26 @@ namespace HttpServer { for (int i = 1; i < argc; ++i) { - if (0 == ::strcmp(argv[i], "--start") ) - { + if (0 == ::strcmp(argv[i], "--start") ) { } - else if (0 == ::strcmp(argv[i], "--force") ) - { + else if (0 == ::strcmp(argv[i], "--force") ) { st->force = true; } - else if (argv[i] == ::strstr(argv[i], "--config-path=") ) - { + else if (argv[i] == ::strstr(argv[i], "--config-path=") ) { st->config_path = std::string(argv[i] + sizeof("--config-path=") - 1); } - else if (argv[i] == ::strstr(argv[i], "--server-name=") ) - { + else if (argv[i] == ::strstr(argv[i], "--server-name=") ) { st->server_name = std::string(argv[i] + sizeof("--server-name=") - 1); } else { std::cout << "Argument '" << argv[i] << "' can't be applied with --start;" << std::endl; - return false; } } - if (st->server_name.empty() ) - { + if (st->server_name.empty() ) { st->server_name = argv[0]; } @@ -904,23 +820,18 @@ namespace HttpServer { struct server_start_args st = {}; - if (false == Server::get_start_args(argc, argv, &st) ) - { + if (Server::get_start_args(argc, argv, &st) == false) { return 0x1; } - if (false == st.config_path.empty() ) - { - if (false == System::changeCurrentDirectory(st.config_path) ) - { + if (st.config_path.empty() == false) { + if (System::changeCurrentDirectory(st.config_path) == false) { std::cout << "Configuration path '" << st.config_path << "' has not been found;" << std::endl; - return 0x2; } } - if (st.force) - { + if (st.force) { System::SharedMemory::destroy(st.server_name); System::GlobalMutex::destory(st.server_name); } @@ -930,16 +841,13 @@ namespace HttpServer bool is_exists = false; - if (glob_mtx.open(st.server_name) ) - { + if (glob_mtx.open(st.server_name) ) { glob_mtx.lock(); - if (glob_mem.open(st.server_name) ) - { + if (glob_mem.open(st.server_name) ) { System::native_processid_type pid = 0; - if (glob_mem.read(&pid, sizeof(pid) ) ) - { + if (glob_mem.read(&pid, sizeof(pid) ) ) { is_exists = System::isProcessExists(pid); } } @@ -947,46 +855,34 @@ namespace HttpServer glob_mtx.unlock(); } - if (is_exists) - { + if (is_exists) { std::cout << "Server instance with the name '" << st.server_name << "' is already running;" << std::endl; - return 0x3; } - if (false == glob_mtx.open(st.server_name) ) - { - if (false == glob_mtx.create(st.server_name) ) - { + if (glob_mtx.open(st.server_name) == false) { + if (glob_mtx.create(st.server_name) == false) { std::cout << "Global mutex could not been created;" << std::endl; - return 0x4; } } glob_mtx.lock(); - if (false == glob_mem.open(st.server_name) ) - { - if (false == glob_mem.create(st.server_name, sizeof(System::native_processid_type) ) ) - { + if (glob_mem.open(st.server_name) == false) { + if (glob_mem.create(st.server_name, sizeof(System::native_processid_type) ) == false) { glob_mtx.unlock(); - std::cout << "Shared memory could not been allocated;" << std::endl; - return 0x5; } } System::native_processid_type pid = System::getProcessId(); - if (false == glob_mem.write(&pid, sizeof(pid) ) ) - { + if (glob_mem.write(&pid, sizeof(pid) ) == false) { glob_mem.destroy(); glob_mtx.unlock(); - std::cout << "Writing data to shared memory has failed;" << std::endl; - return 0x6; } @@ -994,8 +890,7 @@ namespace HttpServer int code = EXIT_FAILURE; - do - { + do { this->controls.setProcess(false); this->controls.setRestart(false); @@ -1011,8 +906,7 @@ namespace HttpServer static void close_liseners(std::vector &liseners) { - for (auto &sock : liseners) - { + for (auto &sock : liseners) { sock.close(); } } @@ -1051,8 +945,7 @@ namespace HttpServer glob_mtx.lock(); - if (glob_mem.open(serverName) ) - { + if (glob_mem.open(serverName) ) { glob_mem.read(&pid, sizeof(pid) ); } @@ -1084,17 +977,14 @@ namespace HttpServer { std::string server_name; - for (int i = 1; i < argc; ++i) - { - if (argv[i] == ::strstr(argv[i], "--server-name=") ) - { + for (int i = 1; i < argc; ++i) { + if (argv[i] == ::strstr(argv[i], "--server-name=") ) { server_name = std::string(argv[i] + sizeof("--server-name=") - 1); break; } } - if (server_name.empty() ) - { + if (server_name.empty() ) { server_name = argv[0]; } @@ -1107,8 +997,7 @@ namespace HttpServer { const System::native_processid_type pid = Server::getServerProcessId(get_server_name(argc, argv) ); - if (1 < pid && System::sendSignal(pid, SIGUSR1) ) - { + if (1 < pid && System::sendSignal(pid, SIGUSR1) ) { return EXIT_SUCCESS; } @@ -1119,8 +1008,7 @@ namespace HttpServer { const System::native_processid_type pid = Server::getServerProcessId(get_server_name(argc, argv) ); - if (1 < pid && System::sendSignal(pid, SIGTERM) ) - { + if (1 < pid && System::sendSignal(pid, SIGTERM) ) { return EXIT_SUCCESS; } @@ -1131,11 +1019,10 @@ namespace HttpServer { const System::native_processid_type pid = Server::getServerProcessId(get_server_name(argc, argv) ); - if (1 < pid && System::sendSignal(pid, SIGUSR2) ) - { + if (1 < pid && System::sendSignal(pid, SIGUSR2) ) { return EXIT_SUCCESS; } return EXIT_FAILURE; } -}; +} diff --git a/src/server/protocol/ServerHttp2.cpp b/src/server/protocol/ServerHttp2.cpp index 5b1e56d..5ef4991 100644 --- a/src/server/protocol/ServerHttp2.cpp +++ b/src/server/protocol/ServerHttp2.cpp @@ -13,8 +13,7 @@ namespace HttpServer } - void ServerHttp2::close() - { + void ServerHttp2::close() { this->sock.close(); } @@ -32,8 +31,7 @@ namespace HttpServer { auto it = streams.find(streamId); - if (streams.end() != it) - { + if (streams.end() != it) { return it->second; } @@ -56,18 +54,15 @@ namespace HttpServer static Http2::ErrorCode parseHttp2Data(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) { - if (0 == meta.stream_id) - { + if (0 == meta.stream_id) { return Http2::ErrorCode::PROTOCOL_ERROR; } - if (Http2::StreamState::OPEN != stream.state) - { + if (Http2::StreamState::OPEN != stream.state) { return Http2::ErrorCode::STREAM_CLOSED; } - if (stream.window_size_inc <= 0) - { + if (stream.window_size_inc <= 0) { return Http2::ErrorCode::FLOW_CONTROL_ERROR; } @@ -77,8 +72,7 @@ namespace HttpServer { padding = *src; - if (padding >= meta.length) - { + if (padding >= meta.length) { return Http2::ErrorCode::PROTOCOL_ERROR; } @@ -134,8 +128,7 @@ namespace HttpServer { padding = *src; - if (padding >= meta.length) - { + if (padding >= meta.length) { return Http2::ErrorCode::PROTOCOL_ERROR; } @@ -155,8 +148,7 @@ namespace HttpServer src += sizeof(uint8_t); } - if (false == HPack::unpack(src, end - src - padding, stream) ) - { + if (HPack::unpack(src, end - src - padding, stream) == false) { return Http2::ErrorCode::COMPRESSION_ERROR; } @@ -165,27 +157,23 @@ namespace HttpServer static Http2::ErrorCode parseHttp2rstStream(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) { - if (Http2::StreamState::IDLE == stream.state) - { + if (Http2::StreamState::IDLE == stream.state) { return Http2::ErrorCode::PROTOCOL_ERROR; } stream.state = Http2::StreamState::CLOSED; - if (0 == meta.stream_id) - { + if (0 == meta.stream_id) { return Http2::ErrorCode::PROTOCOL_ERROR; } - if (sizeof(uint32_t) != meta.length) - { + if (sizeof(uint32_t) != meta.length) { return Http2::ErrorCode::FRAME_SIZE_ERROR; } const Http2::ErrorCode error_code = static_cast(::ntohl(*reinterpret_cast(src) ) ); - if (Http2::ErrorCode::NO_ERROR != error_code) - { + if (Http2::ErrorCode::NO_ERROR != error_code) { // DEBUG } @@ -194,18 +182,15 @@ namespace HttpServer static Http2::ErrorCode parseHttp2Settings(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) { - if (0 != meta.stream_id) - { + if (0 != meta.stream_id) { return Http2::ErrorCode::PROTOCOL_ERROR; } - if (meta.length % (sizeof(uint16_t) + sizeof(uint32_t) ) ) - { + if (meta.length % (sizeof(uint16_t) + sizeof(uint32_t) ) ) { return Http2::ErrorCode::FRAME_SIZE_ERROR; } - if (Http2::StreamState::OPEN != stream.state) - { + if (Http2::StreamState::OPEN != stream.state) { stream.state = Http2::StreamState::OPEN; } @@ -229,8 +214,7 @@ namespace HttpServer case Http2::ConnectionSetting::SETTINGS_ENABLE_PUSH: { - if (value > 1) - { + if (value > 1) { return Http2::ErrorCode::PROTOCOL_ERROR; } @@ -245,8 +229,7 @@ namespace HttpServer case Http2::ConnectionSetting::SETTINGS_INITIAL_WINDOW_SIZE: { - if (value >= uint32_t(1 << 31) ) - { + if (value >= uint32_t(1 << 31) ) { return Http2::ErrorCode::FLOW_CONTROL_ERROR; } @@ -257,8 +240,7 @@ namespace HttpServer case Http2::ConnectionSetting::SETTINGS_MAX_FRAME_SIZE: { - if (value < (1 << 14) || value >= (1 << 24) ) - { + if (value < (1 << 14) || value >= (1 << 24) ) { return Http2::ErrorCode::PROTOCOL_ERROR; } @@ -281,8 +263,7 @@ namespace HttpServer static Http2::ErrorCode parseHttp2GoAway(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) { - if (0 != meta.stream_id) - { + if (0 != meta.stream_id) { return Http2::ErrorCode::PROTOCOL_ERROR; } @@ -290,8 +271,7 @@ namespace HttpServer const uint32_t last_stream_id = ::ntohl(*reinterpret_cast(src) ); - if (last_stream_id > 0) - { + if (last_stream_id > 0) { } @@ -299,8 +279,7 @@ namespace HttpServer const Http2::ErrorCode error_code = static_cast(::ntohl(*reinterpret_cast(src) ) ); - if (Http2::ErrorCode::NO_ERROR != error_code) - { + if (Http2::ErrorCode::NO_ERROR != error_code) { } @@ -327,13 +306,11 @@ namespace HttpServer static Http2::ErrorCode parseHttp2Ping(Http2::FrameMeta &meta) { - if (0 != meta.stream_id) - { + if (0 != meta.stream_id) { return Http2::ErrorCode::PROTOCOL_ERROR; } - if (sizeof(uint64_t) != meta.length) - { + if (sizeof(uint64_t) != meta.length) { return Http2::ErrorCode::FRAME_SIZE_ERROR; } @@ -342,38 +319,30 @@ namespace HttpServer static Http2::ErrorCode parseHttp2WindowUpdate(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) { - if (Http2::StreamState::RESERVED == stream.state) - { + if (Http2::StreamState::RESERVED == stream.state) { return Http2::ErrorCode::PROTOCOL_ERROR; } - else if (Http2::StreamState::OPEN != stream.state) - { + else if (Http2::StreamState::OPEN != stream.state) { return Http2::ErrorCode::NO_ERROR; } - if (sizeof(uint32_t) != meta.length) - { + if (sizeof(uint32_t) != meta.length) { return Http2::ErrorCode::FRAME_SIZE_ERROR; } const uint32_t window_size_increment = ::ntohl(*reinterpret_cast(src) ); - if (0 == window_size_increment) - { + if (0 == window_size_increment) { return Http2::ErrorCode::PROTOCOL_ERROR; } - else if (window_size_increment >= uint32_t(1 << 31) ) - { + else if (window_size_increment >= uint32_t(1 << 31) ) { return Http2::ErrorCode::FLOW_CONTROL_ERROR; } - if (0 == meta.stream_id) - { + if (0 == meta.stream_id) { // TODO: update all streams stream.window_size_out += window_size_increment; - } - else - { + } else { stream.window_size_out += window_size_increment; } @@ -439,8 +408,7 @@ namespace HttpServer const long read_size = sock.nonblock_recv(buf.data(), buf.size(), timeout); - if (read_size != buf.size() ) - { + if (read_size != buf.size() ) { return false; } @@ -478,15 +446,13 @@ namespace HttpServer { if (read_size <= static_cast(meta.length + Http2::FRAME_HEADER_SIZE) ) { - if (read_size == static_cast(meta.length + Http2::FRAME_HEADER_SIZE) ) - { + if (read_size == static_cast(meta.length + Http2::FRAME_HEADER_SIZE) ) { read_size = 0; } read_size = sock.nonblock_recv(buf.data() + read_size, buf.size() - read_size, timeout); - if (read_size < static_cast(Http2::FRAME_HEADER_SIZE) ) - { + if (read_size < static_cast(Http2::FRAME_HEADER_SIZE) ) { return false; } } @@ -517,12 +483,9 @@ namespace HttpServer sendEmptySettings(this->sock, req.timeout, conn, Http2::FrameFlag::EMPTY); - if (false == getClientPreface(this->sock, req.timeout) ) - { + if (getClientPreface(this->sock, req.timeout) == false) { constexpr uint32_t last_stream_id = 0; - goAway(this->sock, req.timeout, conn, last_stream_id, Http2::ErrorCode::PROTOCOL_ERROR); - return this; } @@ -544,32 +507,26 @@ namespace HttpServer Http2::FrameMeta meta {}; long read_size = 0; - do - { - if (false == getNextHttp2FrameMeta(this->sock, req.timeout, buf, meta, read_size) ) - { + do { + if (getNextHttp2FrameMeta(this->sock, req.timeout, buf, meta, read_size) == false) { break; } const uint8_t *addr = reinterpret_cast(buf.data() ) + Http2::FRAME_HEADER_SIZE; const uint8_t *end = addr + meta.length; - if (meta.stream_id > last_stream_id) - { + if (meta.stream_id > last_stream_id) { last_stream_id = meta.stream_id; } Http2::IncStream &stream = getStreamData(streams, meta.stream_id, conn); - if (Http2::StreamState::CLOSED == stream.state) - { + if (Http2::StreamState::CLOSED == stream.state) { rstStream(this->sock, req.timeout, stream, Http2::ErrorCode::STREAM_CLOSED); - continue; } - if (meta.type != Http2::FrameType::CONTINUATION) - { + if (meta.type != Http2::FrameType::CONTINUATION) { stream.frame_type = meta.type; } @@ -591,8 +548,7 @@ namespace HttpServer { size_t update_size = conn.server_settings.initial_window_size + (dr->full_size - dr->recv_total) - stream.window_size_inc; - if (update_size > Http2::MAX_WINDOW_UPDATE) - { + if (update_size > Http2::MAX_WINDOW_UPDATE) { update_size = Http2::MAX_WINDOW_UPDATE; } @@ -616,10 +572,8 @@ namespace HttpServer stream.reserved = createDataReceiver(rd, this->settings.variants); - if (stream.reserved) - { + if (stream.reserved) { DataVariant::DataReceiver *dr = reinterpret_cast(stream.reserved); - dr->reserved = new std::string(); } } @@ -661,7 +615,6 @@ namespace HttpServer if (Http2::ErrorCode::NO_ERROR == result && false == (meta.flags & Http2::FrameFlag::ACK) ) { const uint64_t ping_data = *reinterpret_cast(addr); - ping(this->sock, req.timeout, conn, ping_data); } @@ -711,18 +664,16 @@ namespace HttpServer } while (Http2::StreamState::CLOSED != primary.state); - while (conn.sync.completed.load() < streams_process_count) - { + while (conn.sync.completed.load() < streams_process_count) { conn.sync.event.wait(); } goAway(this->sock, req.timeout, conn, last_stream_id, Http2::ErrorCode::NO_ERROR); - for (auto &pair : streams) - { + for (auto &pair : streams) { destroyDataReceiver(pair.second.reserved); } return this; } -}; +} diff --git a/src/server/protocol/ServerHttp2.h b/src/server/protocol/ServerHttp2.h index 54658d4..6910788 100644 --- a/src/server/protocol/ServerHttp2.h +++ b/src/server/protocol/ServerHttp2.h @@ -18,4 +18,4 @@ namespace HttpServer virtual ServerProtocol *process() override; virtual void close() override; }; -}; +} 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 8df0b9a..1746a79 100644 --- a/src/socket/List.cpp +++ b/src/socket/List.cpp @@ -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..19f83b0 100644 --- a/src/socket/List.h +++ b/src/socket/List.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/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 35771ba..d768a8e 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) { @@ -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) { @@ -55,7 +55,7 @@ namespace Utils break; } } - while (false == this->signaled.load() ); + while (this->signaled.load() == false); } if (false == this->manually) { From b9c1a2801013652cabf734928e0b18624f5941a0 Mon Sep 17 00:00:00 2001 From: awwit Date: Mon, 13 Nov 2017 03:19:20 +0300 Subject: [PATCH 39/50] Trying fix intrrution of data reception. Again --- src/socket/AdapterTls.cpp | 11 +++++------ src/socket/Socket.cpp | 6 +++--- src/socket/Socket.h | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/socket/AdapterTls.cpp b/src/socket/AdapterTls.cpp index b725d37..f284bb7 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,18 @@ 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) { + 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 b0f7775f58f4ca05d38c1b4b5e6040ee754f3b81 Mon Sep 17 00:00:00 2001 From: awwit Date: Mon, 13 Nov 2017 03:41:31 +0300 Subject: [PATCH 40/50] Set result to failed when timeout --- src/socket/AdapterTls.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/socket/AdapterTls.cpp b/src/socket/AdapterTls.cpp index f284bb7..b63bf73 100644 --- a/src/socket/AdapterTls.cpp +++ b/src/socket/AdapterTls.cpp @@ -114,12 +114,14 @@ namespace Socket do { if (sock.nonblock_recv_sync(timeout) == false) { + // Timeout + result = -1; break; } result = ::gnutls_record_recv(this->session, buf, length); } - while (GNUTLS_E_AGAIN == result ||GNUTLS_E_INTERRUPTED == result); + while (GNUTLS_E_AGAIN == result || GNUTLS_E_INTERRUPTED == result); return result; } From 9b10936f8c5affbce4a04f536e8b00d30575d9da Mon Sep 17 00:00:00 2001 From: wuyougongzi <1211385701@qq.com> Date: Thu, 23 Nov 2017 22:39:44 +0800 Subject: [PATCH 41/50] fix make error in ubuntu system --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5ff0f59..c0e28ab 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 5e7425317384cc01c47f9d416a5f325b916e29b0 Mon Sep 17 00:00:00 2001 From: wuyougongzi <1211385701@qq.com> Date: Sun, 3 Dec 2017 22:20:39 +0800 Subject: [PATCH 42/50] use a state machine to parse 'mimes.conf' function --- src/server/config/ConfigParser.cpp | 98 ++++++++++++++++++++---------- src/server/config/ConfigParser.h | 7 +++ 2 files changed, 73 insertions(+), 32 deletions(-) diff --git a/src/server/config/ConfigParser.cpp b/src/server/config/ConfigParser.cpp index 7ae4490..5bd3d4b 100644 --- a/src/server/config/ConfigParser.cpp +++ b/src/server/config/ConfigParser.cpp @@ -412,59 +412,93 @@ namespace HttpServer const std::string str_buf(buf.cbegin(), buf.cend() ); size_t cur_pos = 0; - size_t end_pos = str_buf.find('\n', cur_pos); - while (std::string::npos != end_pos) - { - cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - size_t delimiter = str_buf.find_first_of(whitespace, cur_pos); + ConfigFileDataState dataState = CONFIGFILEDATASNONE; - if (delimiter < end_pos) + while (std::string::npos != cur_pos) + { + //std::cout << "parse Mine dataState: " << dataState << std::endl; + switch(dataState) { - std::string mime_type = str_buf.substr(cur_pos, delimiter - cur_pos); - - if ('#' != mime_type.front() ) - { - delimiter = str_buf.find_first_not_of(whitespace, delimiter); + case CONFIGFILEDATASNONE: - if (delimiter < end_pos) + case CONFIGFILEDATASNOTE: + { - std::string ext = str_buf.substr(delimiter, end_pos - delimiter); - - delimiter = ext.find_first_of(whitespace); + cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); + if (cur_pos < 0) + { + return true; + } - if (std::string::npos != delimiter) + //start from next line + if ('#' == buf[cur_pos]) { - for (size_t ext_pos = 0; std::string::npos != ext_pos; ) + //last line + cur_pos = str_buf.find_first_of("\n", cur_pos); + if (cur_pos < 0) { - std::string ext_unit = ext.substr(ext_pos, std::string::npos != delimiter ? delimiter - ext_pos : std::string::npos); - - if (false == ext_unit.empty() ) - { - mimes_types.emplace(std::move(ext_unit), mime_type); - } + return true; + } - ext_pos = ext.find_first_not_of(whitespace, delimiter); + cur_pos += 1; - delimiter = ext.find_first_of(whitespace, ext_pos); - } + dataState = CONFIGFILEDATASNOTE; + } + else if ('\n' == buf[cur_pos]) + { + cur_pos += 1; + dataState = CONFIGFILEDATASNONE; } else { - mimes_types.emplace(std::move(ext), std::move(mime_type) ); + dataState = CONFIGFILEDATASTYPE; } } - } - } + break; + case CONFIGFILEDATASTYPE: + { + size_t delimiter = str_buf.find_first_of("\n", cur_pos); + std::string strLine = str_buf.substr(cur_pos, delimiter - cur_pos); + + //get mimetypes + { + size_t ext_pos = strLine.find_first_of(whitespace, 0); + if (ext_pos < 0) + { + return false; + } + std::string strExt = strLine.substr(0, ext_pos); + size_t extUnitPos = strLine.find_first_not_of(whitespace, ext_pos); + std::string strExtUnit = strLine.substr(extUnitPos, strLine.length() - extUnitPos); - cur_pos = end_pos + 1; + mimes_types.emplace(std::move(strExt), std::move(strExtUnit)); - end_pos = str_buf.find('\n', cur_pos); - } + //std::cout << strExt << " " << strExtUnit << std::endl; + } + + //change line + cur_pos = str_buf.find_first_of("\n", cur_pos); + if (cur_pos < 0) + { + return true; + } + cur_pos += 1; + + dataState = CONFIGFILEDATASNONE; + + } + break; + default: + break; + } + } + return true; } + static size_t findBlockEnd(const std::string &str_buf, size_t str_pos) { size_t pos = str_buf.find('}', str_pos); diff --git a/src/server/config/ConfigParser.h b/src/server/config/ConfigParser.h index 5614237..c9b0e23 100644 --- a/src/server/config/ConfigParser.h +++ b/src/server/config/ConfigParser.h @@ -7,6 +7,13 @@ namespace HttpServer { + enum ConfigFileDataState + { + CONFIGFILEDATASNONE = 0, + CONFIGFILEDATASNOTE, //comment + CONFIGFILEDATASTYPE, + + }; class ConfigParser { private: From 2bda69185757358f8a41af77de1d59f7e861a88c Mon Sep 17 00:00:00 2001 From: wuyougongzi <1211385701@qq.com> Date: Tue, 12 Dec 2017 23:09:45 +0800 Subject: [PATCH 43/50] change parse 'main.conf' ways using state machine --- src/server/config/ConfigParser.cpp | 303 ++++++++++++++++++----------- src/server/config/ConfigParser.h | 10 +- 2 files changed, 201 insertions(+), 112 deletions(-) diff --git a/src/server/config/ConfigParser.cpp b/src/server/config/ConfigParser.cpp index 5bd3d4b..fee0df6 100644 --- a/src/server/config/ConfigParser.cpp +++ b/src/server/config/ConfigParser.cpp @@ -7,6 +7,8 @@ #include #include +const long FILESIZE = 1024 * 1024; + namespace HttpServer { /** @@ -14,6 +16,7 @@ namespace HttpServer */ bool ConfigParser::includeConfigFile(const std::string &fileName, std::string &strBuf, const std::size_t offset) { + std:: cout << "config file name: " << fileName << std::endl; std::ifstream file(fileName); if ( ! file) @@ -29,7 +32,7 @@ namespace HttpServer std::streamsize file_size = file.tellg(); file.seekg(0, std::ifstream::beg); - constexpr std::streamsize file_size_max = 2 * 1024 * 1024; + constexpr std::streamsize file_size_max = 2 * FILESIZE; if (file_size_max < file_size) { @@ -426,7 +429,7 @@ namespace HttpServer { cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - if (cur_pos < 0) + if (cur_pos == std::string::npos) { return true; } @@ -436,7 +439,7 @@ namespace HttpServer { //last line cur_pos = str_buf.find_first_of("\n", cur_pos); - if (cur_pos < 0) + if (cur_pos == std::string::npos) { return true; } @@ -464,7 +467,7 @@ namespace HttpServer //get mimetypes { size_t ext_pos = strLine.find_first_of(whitespace, 0); - if (ext_pos < 0) + if (ext_pos == std::string::npos) { return false; } @@ -479,7 +482,7 @@ namespace HttpServer //change line cur_pos = str_buf.find_first_of("\n", cur_pos); - if (cur_pos < 0) + if (cur_pos == std::string::npos) { return true; } @@ -534,6 +537,7 @@ namespace HttpServer */ bool ConfigParser::loadConfig(const std::string &conf_file_name, ServerSettings &settings, std::vector &modules) { + //std::cout << "enter loadCofig" << std::endl; std::string str_buf; if (false == includeConfigFile(conf_file_name, str_buf) ) @@ -550,163 +554,238 @@ namespace HttpServer const std::string whitespace(" \t\n\v\f\r"); size_t cur_pos = 0; - size_t end_pos = str_buf.find(';', cur_pos); - size_t block_pos = 0; - while (std::string::npos != end_pos) - { - block_pos = str_buf.find('{', cur_pos); + ConfigFileDataState dataState = CONFIGFILEDATASNONE; + InBlockDataState inBlockState = INBLOCKNONE; + + std::unordered_multimap app; - if (end_pos < block_pos) + int iStatus = 0; + while (std::string::npos != cur_pos) + { + //std::cout << "parse Mine dataState: " << dataState << std::endl; + if (iStatus == 1 || iStatus == 2) { - cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - size_t delimiter = str_buf.find_first_of(whitespace, cur_pos); + break; + } - if (delimiter < end_pos) - { - std::string param_name = str_buf.substr(cur_pos, delimiter - cur_pos); + switch (dataState) + { + case CONFIGFILEDATASNONE: - if ('#' != param_name.front() ) + case CONFIGFILEDATASNOTE: { - cur_pos = str_buf.find_first_not_of(whitespace, delimiter + 1); - delimiter = str_buf.find_last_not_of(whitespace, end_pos); + cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); + if (cur_pos == std::string::npos) + { + iStatus = 1; + } - std::string param_value = str_buf.substr(cur_pos, delimiter - cur_pos); + //start from next line + if ('#' == str_buf[cur_pos]) + { + //last line + cur_pos = str_buf.find_first_of("\n", cur_pos); + if (cur_pos == std::string::npos) + { + iStatus = 1; + } + + cur_pos += 1; - if ("include" == param_name) + dataState = CONFIGFILEDATASNOTE; + } + else if ('\n' == str_buf[cur_pos]) { - this->includeConfigFile(param_value, str_buf, end_pos + 1); + cur_pos += 1; + dataState = CONFIGFILEDATASNONE; } else { - global.emplace(std::move(param_name), std::move(param_value) ); + dataState = CONFIGFILEDATASTYPE; } } - else // if comment line + break; + case CONFIGFILEDATASTYPE: { - end_pos = str_buf.find_first_of("\r\n", cur_pos); - } - } - - cur_pos = end_pos; - - if (std::string::npos != cur_pos) - { - ++cur_pos; - } - } - else if (std::string::npos != block_pos) - { - cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - size_t delimiter = str_buf.find_first_of(whitespace, cur_pos); + //in app and main config file "; and \n " has different meaning + size_t delimiter = str_buf.find_first_of("\n", cur_pos); + //std:: cout << "str_buf.length()" << str_buf.length() << " delimiter " << delimiter + // << " cur_pos " << cur_pos << std::endl; + //std::cout << "npos: " << std::string::npos << std::endl; + if (delimiter == std::string::npos) + { + iStatus = 1; + } - const std::string block_type_name = str_buf.substr(cur_pos, delimiter - cur_pos); + std::string strLine = str_buf.substr(cur_pos, delimiter - cur_pos); + //std::cout << "strLine: " << strLine << std::endl; + do { + size_t ext_pos = strLine.find_first_of(whitespace, 0); + if (ext_pos == std::string::npos) + { + iStatus = 2; + } + std::string param_name = strLine.substr(0, ext_pos); + size_t extUnitPos = strLine.find_first_not_of(whitespace, ext_pos); - if ('#' != block_type_name.front() ) - { - delimiter = str_buf.find_first_not_of(whitespace, delimiter); + //mines the last ";" + std::string param_value; + if (strLine[strLine.length() - 1] == ';') + { + param_value = strLine.substr(extUnitPos, strLine.length() - extUnitPos - 1); + } + else + { + param_value = strLine.substr(extUnitPos, strLine.length() - extUnitPos); + } - cur_pos = block_pos + 1; - size_t block_end = findBlockEnd(str_buf, cur_pos); + //std::cout << param_name << " " << param_value << std::endl; + if (param_name == "server" && param_value == "{") + { + dataState = CONFIGFILEDATAINBLOCK; + inBlockState = INBLOCKNONE; + } + else if(param_name == "include") + { + this->loadConfig(param_value, settings, modules); + dataState = CONFIGFILEDATASNONE; + } + else + { + global.emplace(std::move(param_name), std::move(param_value) ); + dataState = CONFIGFILEDATASNONE; + } + break; + } while (1); - if (std::string::npos == block_end) - { - std::cout << "Error: symbol '}' after '" << block_type_name << "' has not been found;" << std::endl - << "Parsing config aborted;" << std::endl; + //change line + cur_pos = str_buf.find_first_of("\n", cur_pos); + if (cur_pos == std::string::npos) + { + iStatus = 1; + } - return false; + cur_pos += 1; } - else if (delimiter == block_pos) + break; + case CONFIGFILEDATAINBLOCK: { - if ("server" == block_type_name) + switch(inBlockState) { - std::unordered_multimap app; - - end_pos = str_buf.find(';', cur_pos); - - while (block_end > end_pos) - { - cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - delimiter = str_buf.find_first_of(whitespace, cur_pos); - - if (delimiter < end_pos) + case INBLOCKNONE: + case INBLOCKNOTE: { - std::string param_name = str_buf.substr(cur_pos, delimiter - cur_pos); + cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); + if (cur_pos == std::string::npos) + { + iStatus = 1; + } - if ('#' != param_name.front() ) + //start from next line + if ('#' == str_buf[cur_pos]) { - cur_pos = str_buf.find_first_not_of(whitespace, delimiter + 1); - delimiter = str_buf.find_last_not_of(whitespace, end_pos); + //last line + cur_pos = str_buf.find_first_of("\n", cur_pos); + if (cur_pos == std::string::npos) + { + iStatus = 1; + } - std::string param_value = str_buf.substr(cur_pos, delimiter - cur_pos); + cur_pos += 1; - if ("include" == param_name) + inBlockState = INBLOCKNOTE; + } + else if ('\n' == str_buf[cur_pos]) + { + cur_pos += 1; + inBlockState = INBLOCKNONE; + } + else + { + inBlockState = INBLOCKTPYE; + } + } + break; + case INBLOCKTPYE: + { + size_t delimiter = str_buf.find_first_of("\n", cur_pos); + std::string strLine = str_buf.substr(cur_pos, delimiter - cur_pos); + + //std::cout << "inblockLineStr: " << strLine << std::endl; + + do { + if ("}" == strLine) { - cur_pos = end_pos + 1; - this->includeConfigFile(param_value, str_buf, cur_pos); - block_end = findBlockEnd(str_buf, cur_pos); + dataState = CONFIGFILEDATASNOTE; + applications.push_back(app); + app.clear(); + break; } - else + + size_t ext_pos = strLine.find_first_of(whitespace, 0); + if (ext_pos == std::string::npos) { - app.emplace(std::move(param_name), std::move(param_value) ); + iStatus = 2; } - } - else // if comment line + std::string strExt = strLine.substr(0, ext_pos); + size_t extUnitPos = strLine.find_first_not_of(whitespace, ext_pos); + std::string strExtUnit = strLine.substr(extUnitPos, strLine.length() - extUnitPos - 1); + + //std::cout << "inblockLine " << strExt << " " << strExtUnit << std::endl; + app.emplace(std::move(strExt), std::move(strExtUnit)); + + break; + + } while(1); + + //change line + cur_pos = str_buf.find_first_of("\n", cur_pos); + if (cur_pos == std::string::npos) { - end_pos = str_buf.find_first_of("\r\n", cur_pos); + iStatus = 2; } - } - - if (std::string::npos != end_pos) - { - ++end_pos; - } - cur_pos = end_pos; + cur_pos += 1; - end_pos = str_buf.find(';', cur_pos); - } - - applications.emplace_back(std::move(app) ); - } - else - { - std::cout << "Warning: " << block_type_name << " - unknown block type;" << std::endl; + inBlockState = INBLOCKNONE; + } + break; + default: + break; } } - else - { - std::cout << "Warning: after " << block_type_name << " expected '{' ;" << std::endl; - } - - cur_pos = block_end; - - if (std::string::npos != cur_pos) - { - ++cur_pos; - } - } - else // if comment line - { - cur_pos = str_buf.find_first_of("\r\n", cur_pos); - } + break; + default: + break; } - - end_pos = str_buf.find(';', cur_pos); } + // std::cout << "app value start" << std::endl; + // for (size_t i = 0; i < applications.size(); ++i) + // { + // std::unordered_multimap sa = applications[i]; + // for (auto iter = sa.begin(); iter != sa.end(); iter++) + // { + // std::cout << iter->first << " " << iter->second << std::endl; + // } + + // } + // std::cout << "app value end" << std::endl; + auto const it_mimes = global.find("mimes"); if (global.cend() != it_mimes) { this->parseMimes(it_mimes->second, mimes_types); + //std::cout << "parse mimes end" << std::endl; } else { std::cout << "Warning: mime types file is not set in configuration;" << std::endl; } - if (false == applications.empty() ) + if (!applications.empty()) { auto const it_default_temp_dir = global.find("default_temp_dir"); @@ -724,6 +803,7 @@ namespace HttpServer for (auto const &app : applications) { this->addApplication(app, defaults, modules, apps_tree); + std::cout << "addApplication end" << std::endl; } } @@ -732,6 +812,7 @@ namespace HttpServer std::cout << "Notice: server does not contain applications;" << std::endl; } - return true; + //std::cout << "out loadCofig" << std::endl; + return iStatus == 1; } }; diff --git a/src/server/config/ConfigParser.h b/src/server/config/ConfigParser.h index c9b0e23..c501d5d 100644 --- a/src/server/config/ConfigParser.h +++ b/src/server/config/ConfigParser.h @@ -12,8 +12,16 @@ namespace HttpServer CONFIGFILEDATASNONE = 0, CONFIGFILEDATASNOTE, //comment CONFIGFILEDATASTYPE, - + //CONFIGFILEDATAGLOBAL, + CONFIGFILEDATAINBLOCK, //in block + }; + enum InBlockDataState + { + INBLOCKNONE, //in block none + INBLOCKNOTE, //in block note + INBLOCKTPYE, //in block type }; + class ConfigParser { private: From 845a585a2daf238d7ae6c90948d1eb06d0094268 Mon Sep 17 00:00:00 2001 From: awwit Date: Sat, 13 Jan 2018 18:04:55 +0300 Subject: [PATCH 44/50] Fixed bug in function `getPackNumberSize` (which caused the crash application in one case) --- Makefile | 2 +- src/utils/Utils.cpp | 29 +++++++++++++++++------------ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index c0e28ab..3e65d7d 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ $(BUILDDIR): $(MKDIR) $@ $(EXECUTABLE): $(OBJECTS) - $(CXX) $(OBJECTS) -o $@ $(LDFLAGS) + $(CXX) $(OBJECTS) -o $@ $(LDFLAGS) $(OBJECTS) : $(OBJDIR)/%.o : $(SOURCEDIR)/%.cpp @$(MKDIR) $(dir $@) 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 1796b812e837bd96cd2157bec93bd224e048d908 Mon Sep 17 00:00:00 2001 From: awwit Date: Sat, 20 Jan 2018 21:35:10 +0300 Subject: [PATCH 45/50] Fixed code of parsing configs. Started convert to state machine. Removed previous version of code. --- src/server/config/ConfigParser.cpp | 582 ++++++++++++----------------- src/server/config/ConfigParser.h | 19 +- 2 files changed, 240 insertions(+), 361 deletions(-) diff --git a/src/server/config/ConfigParser.cpp b/src/server/config/ConfigParser.cpp index fee0df6..20ed3e0 100644 --- a/src/server/config/ConfigParser.cpp +++ b/src/server/config/ConfigParser.cpp @@ -7,24 +7,31 @@ #include #include -const long FILESIZE = 1024 * 1024; - namespace HttpServer { + enum class ConfigMimeState { + NONE, + TYPE + }; + + enum class ConfigState { + NONE, + PARAM, + BLOCK + }; + + constexpr long FILESIZE = 2 * 1024 * 1024; + /** * Config - include file */ bool ConfigParser::includeConfigFile(const std::string &fileName, std::string &strBuf, const std::size_t offset) { - std:: cout << "config file name: " << fileName << std::endl; std::ifstream file(fileName); - if ( ! file) - { + if ( ! file) { file.close(); - std::cout << "Error: file " << fileName << " cannot be open;" << std::endl; - return false; } @@ -32,19 +39,15 @@ namespace HttpServer std::streamsize file_size = file.tellg(); file.seekg(0, std::ifstream::beg); - constexpr std::streamsize file_size_max = 2 * FILESIZE; + constexpr std::streamsize file_size_max = FILESIZE; - if (file_size_max < file_size) - { + if (file_size_max < file_size) { file.close(); - std::cout << "Error: file " << fileName << " is too large; max include file size = " << file_size_max << " bytes;" << std::endl; - return false; } - if (file_size) - { + if (file_size) { std::vector buf(file_size); file.read(buf.data(), file_size); @@ -68,8 +71,7 @@ namespace HttpServer { auto const it_name = app.find("server_name"); - if (app.cend() == it_name) - { + if (app.cend() == it_name) { std::cout << "Error: application parameter 'server_name' has not been specified;" << std::endl; return false; } @@ -121,14 +123,10 @@ namespace HttpServer { const int port = std::strtol(value.c_str(), nullptr, 10); - if (port) - { - if (is_tls) - { + if (port) { + if (is_tls) { tls_ports.emplace(port); - } - else - { + } else { ports.emplace(port); } } @@ -142,73 +140,61 @@ namespace HttpServer std::string stapling_file; std::string dh_file; - if (false == tls_ports.empty() ) + if (tls_ports.empty() == false) { auto const it_ca_file = app.find("tls_certificate_chain"); - if (app.cend() != it_ca_file) - { + if (app.cend() != it_ca_file) { chain_file = it_ca_file->second; } auto const it_crl_file = app.find("tls_certificate_crl"); - if (app.cend() != it_crl_file) - { + if (app.cend() != it_crl_file) { crl_file = it_crl_file->second; } auto const it_stapling_file = app.find("tls_stapling_file"); - if (app.cend() != it_stapling_file) - { + if (app.cend() != it_stapling_file) { stapling_file = it_stapling_file->second; } auto const it_dh_params_file = app.find("tls_dh_params_file"); - if (app.cend() != it_dh_params_file) - { + if (app.cend() != it_dh_params_file) { dh_file = it_dh_params_file->second; } auto const it_cert_file = app.find("tls_certificate"); - if (app.cend() == it_cert_file) - { + if (app.cend() == it_cert_file) { std::cout << "Error: tls certificate file \"CERT\" has not been specified in configuration file;" << std::endl; tls_ports.clear(); - } - else - { + } else { cert_file = it_cert_file->second; } auto const it_key_file = app.find("tls_certificate_key"); - if (app.cend() == it_key_file) - { + if (app.cend() == it_key_file) { std::cout << "Error: tls certificate key file \"KEY\" has not been specified in configuration file;" << std::endl; tls_ports.clear(); - } - else - { + } else { key_file = it_key_file->second; } } auto const it_root_dir = app.find("root_dir"); - if (app.cend() == it_root_dir || it_root_dir->second.empty() ) - { + if (app.cend() == it_root_dir || it_root_dir->second.empty() ) { std::cout << "Error: application parameter 'root_dir' has not been specified;" << std::endl; return false; } auto const it_module = app.find("server_module"); - if (app.cend() == it_module) - { + if (app.cend() == it_module) { std::cout << "Error: application parameter 'server_module' has not been specified;" << std::endl; return false; } @@ -217,30 +203,26 @@ namespace HttpServer System::Module module(it_module->second); - if (false == module.is_open() ) - { + if (module.is_open() == false) { std::cout << "Error: module '" << it_module->second << "' cannot be open;" << std::endl; return false; } void *(*addr)(void *) = nullptr; - if (false == module.find("application_call", &addr) ) - { + if (module.find("application_call", &addr) == false) { std::cout << "Error: function 'application_call' not found in module '" << it_module->second << "';" << std::endl; return false; } std::function app_call = reinterpret_cast(addr); - if ( ! app_call) - { + if ( ! app_call) { std::cout << "Error: invalid function 'application_call' in module '" << it_module->second << "';" << std::endl; return false; } - if (false == module.find("application_clear", &addr) ) - { + if (module.find("application_clear", &addr) == false) { std::cout << "Error: function 'application_clear' not found in module '" << it_module->second << "';" << std::endl; return false; } @@ -249,30 +231,26 @@ namespace HttpServer std::function app_init = std::function(); - if (module.find("application_init", &addr) ) - { + if (module.find("application_init", &addr) ) { app_init = reinterpret_cast(addr); } std::function app_final = std::function(); - if (module.find("application_final", &addr) ) - { + if (module.find("application_final", &addr) ) { app_final = reinterpret_cast(addr); } std::string root_dir = it_root_dir->second; #ifdef WIN32 - if ('\\' == root_dir.back() ) - { + if (root_dir.back() == '\\') { root_dir.pop_back(); } #endif // Remove back slash from root_dir - if ('/' == root_dir.back() ) - { + if (root_dir.back() == '/') { root_dir.pop_back(); } @@ -293,10 +271,8 @@ namespace HttpServer success = false; } - if (false == success) - { + if (false == success) { std::cout << "Warning: error when initializing application '" << it_module->second << "';" << std::endl; - return false; } @@ -324,8 +300,7 @@ namespace HttpServer } } - if (std::numeric_limits::max() == module_index) - { + if (std::numeric_limits::max() == module_index) { module_index = modules.size(); modules.emplace_back(std::move(module) ); } @@ -357,14 +332,10 @@ namespace HttpServer }; // Add application names in tree - if (names.empty() ) - { + if (names.empty() ) { apps_tree.addApplication(app_name, settings); - } - else - { - for (size_t i = 0; i < names.size(); ++i) - { + } else { + for (size_t i = 0; i < names.size(); ++i) { apps_tree.addApplication(names[i], settings); } } @@ -382,12 +353,9 @@ namespace HttpServer { std::ifstream file(fileName); - if ( ! file) - { + if ( ! file) { file.close(); - std::cout << "Error: " << fileName << " - cannot be open;" << std::endl; - return false; } @@ -395,14 +363,11 @@ namespace HttpServer std::streamsize file_size = file.tellg(); file.seekg(0, std::ifstream::beg); - const std::streamsize file_size_max = 2048 * 1024; + const std::streamsize file_size_max = FILESIZE; - if (file_size_max < file_size) - { + if (file_size_max < file_size) { file.close(); - std::cout << "Error: " << fileName << " - is too large; max file size = " << file_size_max << " bytes;" << std::endl; - return false; } @@ -414,94 +379,90 @@ namespace HttpServer const std::string str_buf(buf.cbegin(), buf.cend() ); + size_t delimiter = 0; size_t cur_pos = 0; + size_t end_pos = str_buf.find('\n', cur_pos); - ConfigFileDataState dataState = CONFIGFILEDATASNONE; + ConfigMimeState state = ConfigMimeState::NONE; - while (std::string::npos != cur_pos) + while (std::string::npos != end_pos) { - //std::cout << "parse Mine dataState: " << dataState << std::endl; - switch(dataState) + switch (state) { - case CONFIGFILEDATASNONE: + case ConfigMimeState::NONE: + { + cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); + delimiter = str_buf.find_first_of(whitespace, cur_pos); - case CONFIGFILEDATASNOTE: - - { - cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - if (cur_pos == std::string::npos) - { - return true; - } + if (delimiter >= end_pos) { + cur_pos = end_pos + 1; + end_pos = str_buf.find('\n', cur_pos); + break; + } - //start from next line - if ('#' == buf[cur_pos]) - { - //last line - cur_pos = str_buf.find_first_of("\n", cur_pos); - if (cur_pos == std::string::npos) - { - return true; - } + if ('#' != str_buf[cur_pos]) { + state = ConfigMimeState::TYPE; + } - cur_pos += 1; + break; + } - dataState = CONFIGFILEDATASNOTE; - } - else if ('\n' == buf[cur_pos]) - { - cur_pos += 1; - dataState = CONFIGFILEDATASNONE; - } - else - { - dataState = CONFIGFILEDATASTYPE; - } + case ConfigMimeState::TYPE: + { + state = ConfigMimeState::NONE; + + std::string mime_type = str_buf.substr(cur_pos, delimiter - cur_pos); + + delimiter = str_buf.find_first_not_of(whitespace, delimiter); + + if (delimiter >= end_pos) { + cur_pos = end_pos + 1; + end_pos = str_buf.find('\n', cur_pos); + break; } - break; - case CONFIGFILEDATASTYPE: + + std::string ext = str_buf.substr(delimiter, end_pos - delimiter); + + delimiter = ext.find_first_of(whitespace); + + if (std::string::npos != delimiter) { - size_t delimiter = str_buf.find_first_of("\n", cur_pos); - std::string strLine = str_buf.substr(cur_pos, delimiter - cur_pos); - - //get mimetypes + for (size_t ext_pos = 0; std::string::npos != ext_pos; ) { - size_t ext_pos = strLine.find_first_of(whitespace, 0); - if (ext_pos == std::string::npos) - { - return false; + std::string ext_unit = ext.substr(ext_pos, + std::string::npos == delimiter + ? std::string::npos + : delimiter - ext_pos + ); + + if (ext_unit.empty() == false) { + mimes_types.emplace(std::move(ext_unit), mime_type); } - std::string strExt = strLine.substr(0, ext_pos); - size_t extUnitPos = strLine.find_first_not_of(whitespace, ext_pos); - std::string strExtUnit = strLine.substr(extUnitPos, strLine.length() - extUnitPos); - mimes_types.emplace(std::move(strExt), std::move(strExtUnit)); + ext_pos = ext.find_first_not_of(whitespace, delimiter); - //std::cout << strExt << " " << strExtUnit << std::endl; - } - - //change line - cur_pos = str_buf.find_first_of("\n", cur_pos); - if (cur_pos == std::string::npos) - { - return true; + delimiter = ext.find_first_of(whitespace, ext_pos); } + } + else + { + mimes_types.emplace(std::move(ext), std::move(mime_type) ); + } - cur_pos += 1; + cur_pos = end_pos + 1; + end_pos = str_buf.find('\n', cur_pos); - dataState = CONFIGFILEDATASNONE; - - } break; + } + default: break; } } - + return true; } - static size_t findBlockEnd(const std::string &str_buf, size_t str_pos) { size_t pos = str_buf.find('}', str_pos); @@ -510,22 +471,18 @@ namespace HttpServer { size_t begin_line = str_buf.rfind('\n', pos); - if (std::string::npos == begin_line) - { + if (std::string::npos == begin_line) { begin_line = 0; } begin_line = str_buf.find_first_not_of("\r\n", begin_line); - if ('#' == str_buf[begin_line]) - { - str_pos = str_buf.find_first_of("\r\n", pos); - } - else - { + if ('#' != str_buf[begin_line]) { break; } + str_pos = str_buf.find_first_of("\r\n", pos); + pos = str_buf.find('}', str_pos); } @@ -537,11 +494,9 @@ namespace HttpServer */ bool ConfigParser::loadConfig(const std::string &conf_file_name, ServerSettings &settings, std::vector &modules) { - //std::cout << "enter loadCofig" << std::endl; std::string str_buf; - if (false == includeConfigFile(conf_file_name, str_buf) ) - { + if (includeConfigFile(conf_file_name, str_buf) == false) { return false; } @@ -554,238 +509,181 @@ namespace HttpServer const std::string whitespace(" \t\n\v\f\r"); size_t cur_pos = 0; + size_t end_pos = 0; + size_t block_pos = 0; - ConfigFileDataState dataState = CONFIGFILEDATASNONE; - InBlockDataState inBlockState = INBLOCKNONE; - - std::unordered_multimap app; + ConfigState state = ConfigState::NONE; - int iStatus = 0; - while (std::string::npos != cur_pos) + while (std::string::npos != end_pos) { - //std::cout << "parse Mine dataState: " << dataState << std::endl; - if (iStatus == 1 || iStatus == 2) + switch (state) { - break; - } + case ConfigState::NONE: + { + end_pos = str_buf.find(';', cur_pos); + block_pos = str_buf.find('{', cur_pos); - switch (dataState) - { - case CONFIGFILEDATASNONE: + if (end_pos < block_pos) { + state = ConfigState::PARAM; + } + else if (std::string::npos != block_pos) { + state = ConfigState::BLOCK; + } - case CONFIGFILEDATASNOTE: - { - cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - if (cur_pos == std::string::npos) - { - iStatus = 1; - } + break; + } - //start from next line - if ('#' == str_buf[cur_pos]) - { - //last line - cur_pos = str_buf.find_first_of("\n", cur_pos); - if (cur_pos == std::string::npos) - { - iStatus = 1; - } + case ConfigState::PARAM: + { + state = ConfigState::NONE; - cur_pos += 1; + cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); + end_pos = str_buf.find(';', cur_pos); + size_t delimiter = str_buf.find_first_of(whitespace, cur_pos); - dataState = CONFIGFILEDATASNOTE; - } - else if ('\n' == str_buf[cur_pos]) - { - cur_pos += 1; - dataState = CONFIGFILEDATASNONE; - } - else - { - dataState = CONFIGFILEDATASTYPE; - } - } - break; - case CONFIGFILEDATASTYPE: + if (delimiter < end_pos) { - //in app and main config file "; and \n " has different meaning - size_t delimiter = str_buf.find_first_of("\n", cur_pos); - //std:: cout << "str_buf.length()" << str_buf.length() << " delimiter " << delimiter - // << " cur_pos " << cur_pos << std::endl; - //std::cout << "npos: " << std::string::npos << std::endl; - if (delimiter == std::string::npos) + std::string param_name = str_buf.substr(cur_pos, delimiter - cur_pos); + + if ('#' != param_name.front() ) { - iStatus = 1; - } + cur_pos = str_buf.find_first_not_of(whitespace, delimiter + 1); + delimiter = str_buf.find_last_not_of(whitespace, end_pos); - std::string strLine = str_buf.substr(cur_pos, delimiter - cur_pos); - //std::cout << "strLine: " << strLine << std::endl; - do { - size_t ext_pos = strLine.find_first_of(whitespace, 0); - if (ext_pos == std::string::npos) - { - iStatus = 2; - } - std::string param_name = strLine.substr(0, ext_pos); - size_t extUnitPos = strLine.find_first_not_of(whitespace, ext_pos); + std::string param_value = str_buf.substr(cur_pos, delimiter - cur_pos); - //mines the last ";" - std::string param_value; - if (strLine[strLine.length() - 1] == ';') + if ("include" == param_name) { - param_value = strLine.substr(extUnitPos, strLine.length() - extUnitPos - 1); - } - else - { - param_value = strLine.substr(extUnitPos, strLine.length() - extUnitPos); - } - - //std::cout << param_name << " " << param_value << std::endl; - if (param_name == "server" && param_value == "{") - { - dataState = CONFIGFILEDATAINBLOCK; - inBlockState = INBLOCKNONE; - } - else if(param_name == "include") - { - this->loadConfig(param_value, settings, modules); - dataState = CONFIGFILEDATASNONE; + this->includeConfigFile(param_value, str_buf, end_pos + 1); } else { global.emplace(std::move(param_name), std::move(param_value) ); - dataState = CONFIGFILEDATASNONE; } - break; - } while (1); - - //change line - cur_pos = str_buf.find_first_of("\n", cur_pos); - if (cur_pos == std::string::npos) + } + else // if comment line { - iStatus = 1; + end_pos = str_buf.find_first_of("\r\n", cur_pos); } - - cur_pos += 1; } + + cur_pos = std::string::npos == end_pos + ? std::string::npos + : end_pos + 1; + break; - case CONFIGFILEDATAINBLOCK: + } + + case ConfigState::BLOCK: + { + state = ConfigState::NONE; + + cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); + end_pos = str_buf.find(';', cur_pos); + size_t delimiter = str_buf.find_first_of(whitespace, cur_pos); + + const std::string block_type_name = str_buf.substr(cur_pos, delimiter - cur_pos); + + if ('#' != block_type_name.front() ) { - switch(inBlockState) + delimiter = str_buf.find_first_not_of(whitespace, delimiter); + + cur_pos = block_pos + 1; + size_t block_end = findBlockEnd(str_buf, cur_pos); + + if (std::string::npos == block_end) + { + std::cout << "Error: symbol '}' after '" << block_type_name << "' has not been found;" << std::endl + << "Parsing config aborted;" << std::endl; + + return false; + } + else if (delimiter == block_pos) { - case INBLOCKNONE: - case INBLOCKNOTE: + if ("server" == block_type_name) + { + std::unordered_multimap app; + + end_pos = str_buf.find(';', cur_pos); + + while (block_end > end_pos) { cur_pos = str_buf.find_first_not_of(whitespace, cur_pos); - if (cur_pos == std::string::npos) - { - iStatus = 1; - } + delimiter = str_buf.find_first_of(whitespace, cur_pos); - //start from next line - if ('#' == str_buf[cur_pos]) + if (delimiter < end_pos) { - //last line - cur_pos = str_buf.find_first_of("\n", cur_pos); - if (cur_pos == std::string::npos) - { - iStatus = 1; - } - - cur_pos += 1; + std::string param_name = str_buf.substr(cur_pos, delimiter - cur_pos); - inBlockState = INBLOCKNOTE; - } - else if ('\n' == str_buf[cur_pos]) - { - cur_pos += 1; - inBlockState = INBLOCKNONE; - } - else - { - inBlockState = INBLOCKTPYE; - } - } - break; - case INBLOCKTPYE: - { - size_t delimiter = str_buf.find_first_of("\n", cur_pos); - std::string strLine = str_buf.substr(cur_pos, delimiter - cur_pos); - - //std::cout << "inblockLineStr: " << strLine << std::endl; - - do { - if ("}" == strLine) + if ('#' != param_name.front() ) { - dataState = CONFIGFILEDATASNOTE; - applications.push_back(app); - app.clear(); - break; + cur_pos = str_buf.find_first_not_of(whitespace, delimiter + 1); + delimiter = str_buf.find_last_not_of(whitespace, end_pos); + + std::string param_value = str_buf.substr(cur_pos, delimiter - cur_pos); + + if ("include" == param_name) + { + cur_pos = end_pos + 1; + this->includeConfigFile(param_value, str_buf, cur_pos); + block_end = findBlockEnd(str_buf, cur_pos); + } + else + { + app.emplace(std::move(param_name), std::move(param_value) ); + } } - - size_t ext_pos = strLine.find_first_of(whitespace, 0); - if (ext_pos == std::string::npos) + else // if comment line { - iStatus = 2; + end_pos = str_buf.find_first_of("\r\n", cur_pos); } - std::string strExt = strLine.substr(0, ext_pos); - size_t extUnitPos = strLine.find_first_not_of(whitespace, ext_pos); - std::string strExtUnit = strLine.substr(extUnitPos, strLine.length() - extUnitPos - 1); - - //std::cout << "inblockLine " << strExt << " " << strExtUnit << std::endl; - app.emplace(std::move(strExt), std::move(strExtUnit)); - - break; - - } while(1); - - //change line - cur_pos = str_buf.find_first_of("\n", cur_pos); - if (cur_pos == std::string::npos) - { - iStatus = 2; } - cur_pos += 1; + cur_pos = std::string::npos == end_pos + ? std::string::npos + : end_pos + 1; - inBlockState = INBLOCKNONE; + end_pos = str_buf.find(';', cur_pos); } - break; - default: - break; + + applications.emplace_back(std::move(app) ); + } + else + { + std::cout << "Warning: " << block_type_name << " - unknown block type;" << std::endl; + } } + else + { + std::cout << "Warning: after " << block_type_name << " expected '{' ;" << std::endl; + } + + cur_pos = std::string::npos == block_end + ? std::string::npos + : block_end + 1; + } + else // if comment line + { + cur_pos = str_buf.find_first_of("\r\n", cur_pos); } + break; + } + default: break; } } - // std::cout << "app value start" << std::endl; - // for (size_t i = 0; i < applications.size(); ++i) - // { - // std::unordered_multimap sa = applications[i]; - // for (auto iter = sa.begin(); iter != sa.end(); iter++) - // { - // std::cout << iter->first << " " << iter->second << std::endl; - // } - - // } - // std::cout << "app value end" << std::endl; - auto const it_mimes = global.find("mimes"); - if (global.cend() != it_mimes) - { + if (global.cend() != it_mimes) { this->parseMimes(it_mimes->second, mimes_types); - //std::cout << "parse mimes end" << std::endl; - } - else - { + } else { std::cout << "Warning: mime types file is not set in configuration;" << std::endl; } - if (!applications.empty()) + if (applications.empty() == false) { auto const it_default_temp_dir = global.find("default_temp_dir"); @@ -800,19 +698,15 @@ namespace HttpServer default_request_max_size }; - for (auto const &app : applications) - { + for (auto const &app : applications) { this->addApplication(app, defaults, modules, apps_tree); - std::cout << "addApplication end" << std::endl; } } - if (apps_tree.empty() ) - { + if (apps_tree.empty() ) { std::cout << "Notice: server does not contain applications;" << std::endl; } - //std::cout << "out loadCofig" << std::endl; - return iStatus == 1; + return true; } -}; +} diff --git a/src/server/config/ConfigParser.h b/src/server/config/ConfigParser.h index c501d5d..f7805dc 100644 --- a/src/server/config/ConfigParser.h +++ b/src/server/config/ConfigParser.h @@ -6,22 +6,7 @@ #include namespace HttpServer -{ - enum ConfigFileDataState - { - CONFIGFILEDATASNONE = 0, - CONFIGFILEDATASNOTE, //comment - CONFIGFILEDATASTYPE, - //CONFIGFILEDATAGLOBAL, - CONFIGFILEDATAINBLOCK, //in block - }; - enum InBlockDataState - { - INBLOCKNONE, //in block none - INBLOCKNOTE, //in block note - INBLOCKTPYE, //in block type - }; - +{ class ConfigParser { private: @@ -45,4 +30,4 @@ namespace HttpServer public: bool loadConfig(const std::string &conf, ServerSettings &settings, std::vector &modules); }; -}; +} From b04b1a7e74b0116b32112b9c8eb308973b49ae07 Mon Sep 17 00:00:00 2001 From: awwit Date: Sat, 31 Mar 2018 22:31:40 +0300 Subject: [PATCH 46/50] Fixed endless looping when TLS-handshake. Added http/1.1 as default protocol for non-ALPN tls connections. Fixed many warnings in code. Changed code style. --- projects/qt-creator/httpserver.qbs | 4 +- src/Main.cpp | 21 +- src/SignalHandlers.cpp | 30 +- src/server/Request.cpp | 2 +- src/server/Request.h | 8 +- src/server/Server.cpp | 239 +++++++---- src/server/Server.h | 34 +- src/server/ServerApplicationSettings.h | 2 +- src/server/ServerApplicationsTree.cpp | 58 +-- src/server/ServerApplicationsTree.h | 2 +- src/server/ServerControls.cpp | 39 +- src/server/ServerControls.h | 2 +- src/server/ServerSettings.cpp | 26 +- src/server/ServerSettings.h | 2 +- src/server/ServerStructuresArguments.h | 2 +- src/server/SocketsQueue.h | 2 +- src/server/config/ConfigParser.cpp | 160 ++++--- src/server/config/ConfigParser.h | 20 +- src/server/data-variant/Abstract.cpp | 16 +- src/server/data-variant/Abstract.h | 14 +- src/server/data-variant/FormUrlencoded.cpp | 57 ++- src/server/data-variant/FormUrlencoded.h | 2 +- src/server/data-variant/MultipartFormData.cpp | 194 +++++---- src/server/data-variant/MultipartFormData.h | 13 +- src/server/data-variant/TextPlain.cpp | 50 ++- src/server/data-variant/TextPlain.h | 2 +- src/server/protocol/ServerHttp1.cpp | 390 ++++++++++------- src/server/protocol/ServerHttp1.h | 53 ++- src/server/protocol/ServerHttp2.cpp | 400 ++++++++++++------ src/server/protocol/ServerHttp2.h | 7 +- src/server/protocol/ServerHttp2Protocol.cpp | 130 ++++-- src/server/protocol/ServerHttp2Protocol.h | 35 +- src/server/protocol/ServerHttp2Stream.cpp | 52 ++- src/server/protocol/ServerHttp2Stream.h | 9 +- src/server/protocol/ServerProtocol.cpp | 115 +++-- src/server/protocol/ServerProtocol.h | 48 ++- src/server/protocol/ServerWebSocket.cpp | 45 +- src/server/protocol/ServerWebSocket.h | 36 +- src/server/protocol/extensions/Sendfile.cpp | 249 +++++++---- src/server/protocol/extensions/Sendfile.h | 2 +- src/socket/Adapter.cpp | 22 +- src/socket/Adapter.h | 26 +- src/socket/AdapterDefault.cpp | 16 +- src/socket/AdapterDefault.h | 13 +- src/socket/AdapterTls.cpp | 42 +- src/socket/AdapterTls.h | 28 +- src/socket/List.cpp | 114 +++-- src/socket/List.h | 18 +- src/socket/Socket.cpp | 272 ++++++++---- src/socket/Socket.h | 43 +- src/system/GlobalMutex.cpp | 57 +-- src/system/GlobalMutex.h | 4 +- src/system/Module.cpp | 94 ++-- src/system/Module.h | 15 +- src/system/SharedMemory.cpp | 109 +++-- src/system/SharedMemory.h | 23 +- src/system/System.cpp | 53 ++- src/system/System.h | 40 +- src/transfer/AppRequest.h | 6 +- src/transfer/AppResponse.h | 3 +- src/transfer/FileIncoming.cpp | 47 +- src/transfer/FileIncoming.h | 19 +- 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 +- 71 files changed, 2803 insertions(+), 1453 deletions(-) diff --git a/projects/qt-creator/httpserver.qbs b/projects/qt-creator/httpserver.qbs index 464d956..20d1f24 100644 --- a/projects/qt-creator/httpserver.qbs +++ b/projects/qt-creator/httpserver.qbs @@ -12,12 +12,12 @@ Project { Properties { condition: qbs.targetOS.contains("linux") - cpp.platformDefines: outer.concat(["POSIX"]) + cpp.defines: outer.concat(["POSIX"]) cpp.dynamicLibraries: outer.concat(["dl", "pthread", "rt"]) } Properties { condition: qbs.targetOS.contains("windows") - cpp.platformDefines: outer.concat(["WIN32", "NOMINMAX"]) + cpp.defines: outer.concat(["WIN32", "NOMINMAX"]) } files: [ diff --git a/src/Main.cpp b/src/Main.cpp index d3d341d..8aa2a4b 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -17,32 +17,23 @@ int main(const int argc, const char *argv[]) int exitcode = EXIT_FAILURE; - if (1 < argc) - { + if (1 < argc) { auto const command = commands.find(argv[1]); - if (commands.cend() != command) - { + if (commands.cend() != command) { HttpServer::Server server; - if (bindSignalHandlers(&server) ) - { + if (bindSignalHandlers(&server) ) { exitcode = command->second(&server, argc, argv); - stopSignalHandlers(); } - } - else - { + } else { std::cout << "Unknown parameter, see --help" << std::endl; } } - else if (1 == argc) - { + else if (1 == argc) { std::cout << "Try to run with the parameter --help" << std::endl; - } - else - { + } else { std::cout << "The number of arguments cannot be equal to zero. Enter the parameter --help" << std::endl; } diff --git a/src/SignalHandlers.cpp b/src/SignalHandlers.cpp index 80bbc7d..cad0155 100644 --- a/src/SignalHandlers.cpp +++ b/src/SignalHandlers.cpp @@ -56,8 +56,12 @@ static void handlerSigUsr2(const int) noexcept { * It doesn't work in case the program was launched and was * attempted to finish under different remote sessions. */ -static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const ::WPARAM wParam, const ::LPARAM lParam) noexcept -{ +static ::LRESULT CALLBACK WndProc( + const ::HWND hWnd, + const ::UINT message, + const ::WPARAM wParam, + const ::LPARAM lParam +) noexcept { switch (message) { case SIGTERM: { @@ -105,9 +109,23 @@ static ::LRESULT CALLBACK WndProc(const ::HWND hWnd, const ::UINT message, const return 0; } -static ::WPARAM mainMessageLoop(const ::HINSTANCE hInstance, Utils::Event * const eventWindowCreation) noexcept -{ - const ::HWND hWnd = ::CreateWindow(myWndClassName, nullptr, 0, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, nullptr, nullptr, hInstance, nullptr); +static ::WPARAM mainMessageLoop( + const ::HINSTANCE hInstance, + Utils::Event * const eventWindowCreation +) noexcept { + const ::HWND hWnd = ::CreateWindow( + myWndClassName, + nullptr, + 0, + CW_USEDEFAULT, + CW_USEDEFAULT, + 0, + 0, + nullptr, + nullptr, + hInstance, + nullptr + ); eventWindowCreation->notify(); // After this action, eventWindowCreation will be destroyed (in the other thread) @@ -207,7 +225,7 @@ bool bindSignalHandlers(HttpServer::Server *server) noexcept ::signal(SIGPIPE, SIG_IGN); #else - #error "Undefine platform" + #error "Undefined platform" #endif return true; diff --git a/src/server/Request.cpp b/src/server/Request.cpp index f8bfcea..17ca269 100644 --- a/src/server/Request.cpp +++ b/src/server/Request.cpp @@ -17,4 +17,4 @@ namespace HttpServer // timeout = std::chrono::milliseconds::zero(); } -}; +} diff --git a/src/server/Request.h b/src/server/Request.h index dd2b5d5..abc8de0 100644 --- a/src/server/Request.h +++ b/src/server/Request.h @@ -8,8 +8,7 @@ namespace HttpServer { - enum ConnectionParams - { + enum ConnectionParams { CONNECTION_CLOSE = 0, CONNECTION_REUSE = 1, CONNECTION_LEAVE_OPEN = 2 @@ -36,9 +35,8 @@ namespace HttpServer void clear() noexcept; }; - struct DataTransfer - { + struct DataTransfer { size_t full_size; size_t send_total; }; -}; +} diff --git a/src/server/Server.cpp b/src/server/Server.cpp index 3f87c92..df464eb 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -33,8 +33,7 @@ namespace HttpServer ServerControls &controls, SocketsQueue &sockets, Http2::IncStream *stream - ) - { + ) { std::unique_ptr prot; // If request is HTTP/2 Stream @@ -43,11 +42,13 @@ namespace HttpServer return prot; } - if (sock.get_tls_session() ) + if (sock.get_tls_session() != nullptr) { ::gnutls_datum_t datum; - if (0 == ::gnutls_alpn_get_selected_protocol(sock.get_tls_session(), &datum) ) + const int ret = ::gnutls_alpn_get_selected_protocol(sock.get_tls_session(), &datum); + + if (GNUTLS_E_SUCCESS == ret) { const std::string protocol(reinterpret_cast(datum.data), datum.size); @@ -58,6 +59,9 @@ namespace HttpServer prot.reset(new ServerHttp1(sock, settings, controls) ); } } + else if (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE == ret) { + prot.reset(new ServerHttp1(sock, settings, controls) ); + } return prot; } @@ -70,9 +74,18 @@ namespace HttpServer /** * Метод для обработки запроса */ - void Server::threadRequestProc(Socket::Adapter &sock, SocketsQueue &sockets, Http2::IncStream *stream) const - { - std::unique_ptr prot = getProtocolVariant(sock, this->settings, this->controls, sockets, stream); + void Server::threadRequestProc( + Socket::Adapter &sock, + SocketsQueue &sockets, + Http2::IncStream *stream + ) const { + std::unique_ptr prot = getProtocolVariant( + sock, + this->settings, + this->controls, + sockets, + stream + ); if (prot) { // Check if switching protocol @@ -94,8 +107,10 @@ namespace HttpServer * Метод для обработки запросов (запускается в отдельном потоке) * извлекает сокет клиенты из очереди и передаёт его на обслуживание */ - void Server::threadRequestCycle(SocketsQueue &sockets, Utils::Event &eventThreadCycle) const - { + void Server::threadRequestCycle( + SocketsQueue &sockets, + Utils::Event &eventThreadCycle + ) const { while (true) { Socket::Socket sock; @@ -114,7 +129,11 @@ namespace HttpServer /* sockaddr_in addr {}; socklen_t addr_size = sizeof(sockaddr_in); - ::getpeername(sock.get_handle(), reinterpret_cast(&addr), &addr_size); + ::getpeername( + sock.get_handle(), + reinterpret_cast(&addr), + &addr_size + ); */ sockets.pop(); } @@ -133,7 +152,11 @@ namespace HttpServer ::sockaddr_in sock_addr {}; ::socklen_t sock_addr_len = sizeof(sock_addr); - ::getsockname(sock.get_handle(), reinterpret_cast(&sock_addr), &sock_addr_len); + ::getsockname( + sock.get_handle(), + reinterpret_cast(&sock_addr), + &sock_addr_len + ); const int port = ntohs(sock_addr.sin_port); @@ -141,14 +164,17 @@ namespace HttpServer if (this->tls_data.cend() != it) // if TLS connection { - if (stream) - { - Socket::AdapterTls socket_adapter(reinterpret_cast(stream->reserved) ); + if (stream) { + Socket::AdapterTls socket_adapter( + reinterpret_cast(stream->reserved) + ); - this->threadRequestProc(socket_adapter, sockets, stream); - } - else - { + this->threadRequestProc( + socket_adapter, + sockets, + stream + ); + } else { const std::tuple &data = it->second; Socket::AdapterTls socket_adapter( @@ -158,15 +184,21 @@ namespace HttpServer ); if (socket_adapter.handshake() ) { - this->threadRequestProc(socket_adapter, sockets, nullptr); + this->threadRequestProc( + socket_adapter, + sockets, + nullptr + ); } } - } - else - { + } else { Socket::AdapterDefault socket_adapter(sock); - this->threadRequestProc(socket_adapter, sockets, stream); + this->threadRequestProc( + socket_adapter, + sockets, + stream + ); } --this->threads_working_count; @@ -202,8 +234,9 @@ namespace HttpServer Utils::Event eventThreadCycle(false, true); - std::function serverThreadRequestCycle - = std::mem_fn(&Server::threadRequestCycle); + std::function serverThreadRequestCycle = std::mem_fn(&Server::threadRequestCycle); std::vector active_threads; active_threads.reserve(threads_max_count); @@ -216,9 +249,17 @@ namespace HttpServer // Cycle creation threads applications requests do { - while (this->threads_working_count == active_threads.size() && active_threads.size() < threads_max_count && sockets.empty() == false) - { - active_threads.emplace_back(serverThreadRequestCycle, this, std::ref(sockets), std::ref(eventThreadCycle) ); + while ( + this->threads_working_count == active_threads.size() && + active_threads.size() < threads_max_count && + sockets.empty() == false + ) { + active_threads.emplace_back( + serverThreadRequestCycle, + this, + std::ref(sockets), + std::ref(eventThreadCycle) + ); } size_t notify_count = active_threads.size() - this->threads_working_count; @@ -253,8 +294,11 @@ namespace HttpServer return 0; } - bool Server::updateModule(System::Module &module, std::unordered_set &applications, const size_t moduleIndex) - { + bool Server::updateModule( + System::Module &module, + std::unordered_set &applications, + const size_t moduleIndex + ) { std::unordered_set same; for (auto &app : applications) @@ -270,7 +314,8 @@ namespace HttpServer } } catch (std::exception &exc) { - std::cout << "Warning: an exception was thrown when the application '" << app->server_module << "' was finishes: " << exc.what() << std::endl; + std::cout << "Warning: an exception was thrown when the application '" + << app->server_module << "' was finishes: " << exc.what() << std::endl; } app->application_call = std::function(); @@ -347,12 +392,12 @@ namespace HttpServer // Open updated module module.open(module_name_temp); - if (0 != std::remove(module_name.c_str() ) ) { + if (std::remove(module_name.c_str() ) != 0) { std::cout << "Error: file '" << module_name << "' could not be removed;" << std::endl; return false; } - if (0 != std::rename(module_name_temp.c_str(), module_name.c_str() ) ) { + if (std::rename(module_name_temp.c_str(), module_name.c_str() ) != 0) { std::cout << "Error: file '" << module_name_temp << "' could not be renamed;" << std::endl; return false; } @@ -372,7 +417,11 @@ namespace HttpServer return false; } - std::function app_call = reinterpret_cast(addr); + std::function app_call = reinterpret_cast(addr); if ( ! app_call) { std::cout << "Error: invalid function 'application_call' is in the module '" << module_name << "';" << std::endl; @@ -511,48 +560,67 @@ namespace HttpServer Socket::Socket::Cleanup(); } - static bool tlsInit(const ServerApplicationSettings &app, std::tuple &data) - { + static bool tlsInit( + const ServerApplicationSettings &app, + std::tuple &data + ) { ::gnutls_certificate_credentials_t x509_cred; int ret = ::gnutls_certificate_allocate_credentials(&x509_cred); if (ret < 0) { - std::cout << "Error [tls]: certificate credentials has not been allocated;" << std::endl; + std::cout << "Error [tls]: certificate credentials has not been allocated; code: " << ret << std::endl; return false; } if (app.chain_file.empty() == false) { - ret = ::gnutls_certificate_set_x509_trust_file(x509_cred, app.chain_file.c_str(), GNUTLS_X509_FMT_PEM); + ret = ::gnutls_certificate_set_x509_trust_file( + x509_cred, + app.chain_file.c_str(), + GNUTLS_X509_FMT_PEM + ); if (ret < 0) { - std::cout << "Warning [tls]: (CA) chain file has not been accepted;" << std::endl; + std::cout << "Warning [tls]: (CA) chain file has not been accepted; code: " << ret << std::endl; } } if (app.crl_file.empty() == false) { - ret = ::gnutls_certificate_set_x509_crl_file(x509_cred, app.crl_file.c_str(), GNUTLS_X509_FMT_PEM); + ret = ::gnutls_certificate_set_x509_crl_file( + x509_cred, + app.crl_file.c_str(), + GNUTLS_X509_FMT_PEM + ); if (ret < 0) { - std::cout << "Warning [tls]: (CLR) clr file has not been accepted;" << std::endl; + std::cout << "Warning [tls]: (CLR) clr file has not been accepted; code: " << ret << std::endl; } } - ret = ::gnutls_certificate_set_x509_key_file(x509_cred, app.cert_file.c_str(), app.key_file.c_str(), GNUTLS_X509_FMT_PEM); + ret = ::gnutls_certificate_set_x509_key_file( + x509_cred, + app.cert_file.c_str(), + app.key_file.c_str(), + GNUTLS_X509_FMT_PEM + ); if (ret < 0) { - std::cout << "Error [tls]: (CERT) cert file or/and (KEY) key file has not been accepted;" << std::endl; + std::cout << "Error [tls]: (CERT) cert file or/and (KEY) key file has not been accepted; code: " << ret << std::endl; return false; } if (app.stapling_file.empty() == false) { - ret = ::gnutls_certificate_set_ocsp_status_request_file(x509_cred, app.stapling_file.c_str(), 0); + ret = ::gnutls_certificate_set_ocsp_status_request_file( + x509_cred, + app.stapling_file.c_str(), + 0 + ); if (ret < 0) { - std::cout << "Warning [tls]: (OCSP) stapling file has not been accepted;" << std::endl; + std::cout << "Warning [tls]: (OCSP) stapling file has not been accepted; code: " << ret << std::endl; } } @@ -560,35 +628,40 @@ namespace HttpServer ::gnutls_dh_params_init(&dh_params); - if (app.dh_file.empty() ) - { - const unsigned int bits = ::gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_HIGH); + if (app.dh_file.empty() ) { + const unsigned int bits = ::gnutls_sec_param_to_pk_bits( + GNUTLS_PK_DH, GNUTLS_SEC_PARAM_HIGH + ); - ret = ::gnutls_dh_params_generate2(dh_params, bits); - } - else - { + ret = ::gnutls_dh_params_generate2( + dh_params, + bits + ); + } else { std::ifstream dh_file(app.dh_file); - if (dh_file) - { + if (dh_file) { const size_t max_file_size = 1024 * 1024; std::vector buf(max_file_size); - dh_file.read(buf.data(), buf.size() ); + dh_file.read( + buf.data(), + std::streamsize(buf.size()) + ); gnutls_datum_t datum { reinterpret_cast(buf.data() ), static_cast(dh_file.gcount() ) }; - ret = ::gnutls_dh_params_import_pkcs3(dh_params, &datum, GNUTLS_X509_FMT_PEM); - } - else - { + ret = ::gnutls_dh_params_import_pkcs3( + dh_params, + &datum, + GNUTLS_X509_FMT_PEM + ); + } else { ret = -1; - std::cout << "Error [tls]: DH params file has not been opened;" << std::endl;; } @@ -597,7 +670,7 @@ namespace HttpServer if (ret < 0) { ::gnutls_certificate_free_credentials(x509_cred); - std::cout << "Error [tls]: DH params were not loaded;" << std::endl; + std::cout << "Error [tls]: DH params were not loaded; code: " << ret << std::endl; return false; } @@ -609,17 +682,22 @@ namespace HttpServer if (ret < 0) { ::gnutls_certificate_free_credentials(x509_cred); - std::cout << "Error [tls]: priority cache cannot be init;" << std::endl; + std::cout << "Error [tls]: priority cache cannot be init; code: " << ret << std::endl; return false; } - data = std::tuple { x509_cred, priority_cache }; + data = std::tuple { + x509_cred, + priority_cache + }; return true; } - bool Server::tryBindPort(const int port, std::unordered_set &ports) - { + bool Server::tryBindPort( + const int port, + std::unordered_set &ports + ) { // Only unique ports if (ports.cend() != ports.find(port) ) { return false; @@ -726,16 +804,13 @@ namespace HttpServer // Cycle for receiving new connections do { - if (sockets_list.accept(accept_sockets) ) - { + if (sockets_list.accept(accept_sockets) ) { sockets.lock(); - for (size_t i = 0; i < accept_sockets.size(); ++i) - { + for (size_t i = 0; i < accept_sockets.size(); ++i) { const Socket::Socket &sock = accept_sockets[i]; - if (sock.is_open() ) - { + if (sock.is_open() ) { sock.nonblock(true); sock.tcp_nodelay(true); @@ -784,8 +859,11 @@ namespace HttpServer return EXIT_SUCCESS; } - bool Server::get_start_args(const int argc, const char *argv[], struct server_start_args *st) - { + bool Server::get_start_args( + const int argc, + const char *argv[], + struct server_start_args *st + ) { for (int i = 1; i < argc; ++i) { if (0 == ::strcmp(argv[i], "--start") ) { @@ -904,30 +982,26 @@ namespace HttpServer return code; } - static void close_liseners(std::vector &liseners) - { + static void close_liseners(std::vector &liseners) { for (auto &sock : liseners) { sock.close(); } } - void Server::stop() - { + void Server::stop() { this->controls.stopProcess(); close_liseners(this->liseners); } - void Server::restart() - { + void Server::restart() { this->controls.setRestart(); this->controls.stopProcess(); close_liseners(this->liseners); } - void Server::update() - { + void Server::update() { this->controls.setUpdateModule(); this->controls.setProcess(false); this->controls.setProcessQueue(); @@ -939,8 +1013,7 @@ namespace HttpServer System::GlobalMutex glob_mtx; - if (glob_mtx.open(serverName) ) - { + if (glob_mtx.open(serverName) ) { System::SharedMemory glob_mem; glob_mtx.lock(); diff --git a/src/server/Server.h b/src/server/Server.h index e09984a..f8ca243 100644 --- a/src/server/Server.h +++ b/src/server/Server.h @@ -31,11 +31,22 @@ namespace HttpServer protected: int cycleQueue(SocketsQueue &sockets); - void threadRequestProc(Socket::Adapter &sock, SocketsQueue &sockets, Http2::IncStream *stream) const; + void threadRequestProc( + Socket::Adapter &sock, + SocketsQueue &sockets, + Http2::IncStream *stream + ) const; + + void threadRequestCycle( + SocketsQueue &sockets, + Utils::Event &eventThreadCycle + ) const; + + bool tryBindPort( + const int port, + std::unordered_set &ports + ); - void threadRequestCycle(SocketsQueue &sockets, Utils::Event &eventThreadCycle) const; - - bool tryBindPort(const int port, std::unordered_set &ports); void initAppsPorts(); bool init(); @@ -45,10 +56,19 @@ namespace HttpServer static System::native_processid_type getServerProcessId(const std::string &serverName); void updateModules(); - bool updateModule(System::Module &module, std::unordered_set &applications, const size_t moduleIndex); + + bool updateModule( + System::Module &module, + std::unordered_set &applications, + const size_t moduleIndex + ); private: - static bool get_start_args(const int argc, const char *argv[], struct server_start_args *st); + static bool get_start_args( + const int argc, + const char *argv[], + struct server_start_args *st + ); public: Server() = default; @@ -63,4 +83,4 @@ namespace HttpServer int command_terminate(const int argc, const char *argv[]) const; int command_update_module(const int argc, const char *argv[]) const; }; -}; +} diff --git a/src/server/ServerApplicationSettings.h b/src/server/ServerApplicationSettings.h index b1bd9d6..ca70896 100644 --- a/src/server/ServerApplicationSettings.h +++ b/src/server/ServerApplicationSettings.h @@ -34,4 +34,4 @@ namespace HttpServer std::function application_init; std::function application_final; }; -}; +} diff --git a/src/server/ServerApplicationsTree.cpp b/src/server/ServerApplicationsTree.cpp index 250e432..3e73586 100644 --- a/src/server/ServerApplicationsTree.cpp +++ b/src/server/ServerApplicationsTree.cpp @@ -8,13 +8,11 @@ namespace HttpServer } - ServerApplicationsTree::~ServerApplicationsTree() noexcept - { + ServerApplicationsTree::~ServerApplicationsTree() noexcept { this->clear(); } - bool ServerApplicationsTree::empty() const noexcept - { + bool ServerApplicationsTree::empty() const noexcept { return this->list.empty(); } @@ -32,8 +30,7 @@ namespace HttpServer { std::string part = name.substr(cur_pos, delimiter - cur_pos); - if ("" == part) - { + if (part.empty() ) { part = "*"; } @@ -45,9 +42,7 @@ namespace HttpServer // Emplace last part std::string part = name.substr(cur_pos); name_parts.emplace_back(std::move(part) ); - } - else - { + } else { name_parts.emplace_back(name); } @@ -56,24 +51,18 @@ namespace HttpServer void ServerApplicationsTree::addApplication(std::vector &nameParts, ServerApplicationSettings *sets) { - if (nameParts.empty() ) - { + if (nameParts.empty() ) { this->app_sets = sets; - } - else - { + } else { std::string &part = nameParts.back(); auto it = this->list.find(part); ServerApplicationsTree *sub; - if (this->list.cend() != it) - { + if (this->list.cend() != it) { sub = it->second; - } - else - { + } else { sub = new ServerApplicationsTree(); this->list.emplace(std::move(part), sub); } @@ -104,9 +93,7 @@ namespace HttpServer std::string part = name.substr(cur_pos); name_parts.emplace_back(std::move(part) ); - } - else - { + } else { name_parts.emplace_back(name); } @@ -115,29 +102,22 @@ namespace HttpServer const ServerApplicationSettings *ServerApplicationsTree::find(std::vector &nameParts) const { - if (nameParts.empty() ) - { + if (nameParts.empty() ) { return this->app_sets; - } - else - { + } else { const std::string part = std::move(nameParts.back() ); nameParts.pop_back(); auto it = this->list.find(part); - if (this->list.cend() == it) - { + if (this->list.cend() == it) { it = this->list.find("*"); - if (this->list.end() != it) - { + if (this->list.end() != it) { return this->app_sets; } - } - else - { + } else { return it->second->find(nameParts); } @@ -151,8 +131,7 @@ namespace HttpServer { const ServerApplicationsTree *tree = node.second; - if (nullptr != tree->app_sets) - { + if (nullptr != tree->app_sets) { set.emplace(tree->app_sets); } @@ -162,14 +141,13 @@ namespace HttpServer void ServerApplicationsTree::clear() noexcept { - if (false == this->list.empty() ) + if (this->list.empty() == false) { - for (auto &it : this->list) - { + for (auto &it : this->list) { delete it.second; } this->list.clear(); } } -}; +} diff --git a/src/server/ServerApplicationsTree.h b/src/server/ServerApplicationsTree.h index 6fe2b24..6f4b54f 100644 --- a/src/server/ServerApplicationsTree.h +++ b/src/server/ServerApplicationsTree.h @@ -31,4 +31,4 @@ namespace HttpServer void clear() noexcept; }; -}; +} diff --git a/src/server/ServerControls.cpp b/src/server/ServerControls.cpp index 6bc57ed..23fd576 100644 --- a/src/server/ServerControls.cpp +++ b/src/server/ServerControls.cpp @@ -4,39 +4,36 @@ namespace HttpServer { ServerControls::ServerControls() - : eventProcessQueue(nullptr), eventNotFullQueue(nullptr), eventUpdateModule(nullptr) + : eventProcessQueue(nullptr), + eventNotFullQueue(nullptr), + eventUpdateModule(nullptr) { } - ServerControls::~ServerControls() - { + ServerControls::~ServerControls() { this->clear(); } void ServerControls::clear() { - if (this->eventNotFullQueue) - { + if (this->eventNotFullQueue) { delete this->eventNotFullQueue; this->eventNotFullQueue = nullptr; } - if (this->eventProcessQueue) - { + if (this->eventProcessQueue) { delete this->eventProcessQueue; this->eventProcessQueue = nullptr; } - if (this->eventUpdateModule) - { + if (this->eventUpdateModule) { delete this->eventUpdateModule; this->eventUpdateModule = nullptr; } } - void ServerControls::setProcess(const bool flag) - { + void ServerControls::setProcess(const bool flag) { this->process_flag = flag; } @@ -44,32 +41,26 @@ namespace HttpServer { this->process_flag = false; - if (this->eventNotFullQueue) - { + if (this->eventNotFullQueue) { this->eventNotFullQueue->notify(); } this->setProcessQueue(); } - void ServerControls::setRestart(const bool flag) - { + void ServerControls::setRestart(const bool flag) { this->restart_flag = flag; } - void ServerControls::setUpdateModule() - { - if (this->eventUpdateModule) - { + void ServerControls::setUpdateModule() { + if (this->eventUpdateModule) { this->eventUpdateModule->notify(); } } - void ServerControls::setProcessQueue() - { - if (this->eventProcessQueue) - { + void ServerControls::setProcessQueue() { + if (this->eventProcessQueue) { this->eventProcessQueue->notify(); } } -}; +} diff --git a/src/server/ServerControls.h b/src/server/ServerControls.h index ab811f0..b438111 100644 --- a/src/server/ServerControls.h +++ b/src/server/ServerControls.h @@ -34,4 +34,4 @@ namespace HttpServer void setUpdateModule(); void setProcessQueue(); }; -}; +} diff --git a/src/server/ServerSettings.cpp b/src/server/ServerSettings.cpp index 166f2dc..3677a62 100644 --- a/src/server/ServerSettings.cpp +++ b/src/server/ServerSettings.cpp @@ -5,29 +5,29 @@ namespace HttpServer { - ServerSettings::~ServerSettings() - { + ServerSettings::~ServerSettings() { this->clear(); } - void ServerSettings::addDataVariant(DataVariant::Abstract *dataVariant) - { - this->variants.emplace(dataVariant->getName(), dataVariant); + void ServerSettings::addDataVariant(DataVariant::Abstract *dataVariant) { + this->variants.emplace( + dataVariant->getName(), + dataVariant + ); } void ServerSettings::clear() { - if (false == this->variants.empty() ) + if (this->variants.empty() == false) { - for (auto &variant : this->variants) - { + for (auto &variant : this->variants) { delete variant.second; } this->variants.clear(); } - if (false == this->apps_tree.empty() ) + if (this->apps_tree.empty() == false) { std::unordered_set applications; this->apps_tree.collectApplicationSettings(applications); @@ -36,8 +36,7 @@ namespace HttpServer { try { - if (app->application_final) - { + if (app->application_final) { const std::string root = app->root_dir; app->application_final(root.data() ); } @@ -54,9 +53,8 @@ namespace HttpServer this->apps_tree.clear(); } - if (false == this->global.empty() ) - { + if (this->global.empty() == false) { this->global.clear(); } } -}; +} diff --git a/src/server/ServerSettings.h b/src/server/ServerSettings.h index 2ef64a2..221a466 100644 --- a/src/server/ServerSettings.h +++ b/src/server/ServerSettings.h @@ -22,4 +22,4 @@ namespace HttpServer void clear(); }; -}; +} diff --git a/src/server/ServerStructuresArguments.h b/src/server/ServerStructuresArguments.h index 0e10b8b..d00e8be 100644 --- a/src/server/ServerStructuresArguments.h +++ b/src/server/ServerStructuresArguments.h @@ -10,4 +10,4 @@ namespace HttpServer std::string config_path; bool force; }; -}; +} diff --git a/src/server/SocketsQueue.h b/src/server/SocketsQueue.h index ff6ec83..2473ee4 100644 --- a/src/server/SocketsQueue.h +++ b/src/server/SocketsQueue.h @@ -17,4 +17,4 @@ namespace HttpServer { }; -}; +} diff --git a/src/server/config/ConfigParser.cpp b/src/server/config/ConfigParser.cpp index 20ed3e0..1bbb42a 100644 --- a/src/server/config/ConfigParser.cpp +++ b/src/server/config/ConfigParser.cpp @@ -25,8 +25,11 @@ namespace HttpServer /** * Config - include file */ - bool ConfigParser::includeConfigFile(const std::string &fileName, std::string &strBuf, const std::size_t offset) - { + bool ConfigParser::includeConfigFile( + const std::string &fileName, + std::string &strBuf, + const std::size_t offset + ) { std::ifstream file(fileName); if ( ! file) { @@ -51,7 +54,11 @@ namespace HttpServer std::vector buf(file_size); file.read(buf.data(), file_size); - strBuf.insert(strBuf.begin() + offset, buf.cbegin(), buf.cend() ); + strBuf.insert( + strBuf.begin() + long(offset), + buf.cbegin(), + buf.cend() + ); } file.close(); @@ -63,12 +70,11 @@ namespace HttpServer * Config - add application */ bool ConfigParser::addApplication( - const std::unordered_multimap &app, - const ServerApplicationDefaultSettings &defaults, - std::vector &modules, - ServerApplicationsTree &apps_tree - ) - { + const std::unordered_multimap &app, + const ServerApplicationDefaultSettings &defaults, + std::vector &modules, + ServerApplicationsTree &apps_tree + ) { auto const it_name = app.find("server_name"); if (app.cend() == it_name) { @@ -84,16 +90,26 @@ namespace HttpServer size_t delimiter = app_name.find_first_of(whitespace); - if (delimiter) - { + if (delimiter) { size_t cur_pos = 0; - while (std::string::npos != delimiter) - { - std::string name = app_name.substr(cur_pos, delimiter - cur_pos); + while (std::string::npos != delimiter) { + std::string name = app_name.substr( + cur_pos, + delimiter - cur_pos + ); + names.emplace_back(std::move(name) ); - cur_pos = app_name.find_first_not_of(whitespace, delimiter + 1); - delimiter = app_name.find_first_of(whitespace, cur_pos); + + cur_pos = app_name.find_first_not_of( + whitespace, + delimiter + 1 + ); + + delimiter = app_name.find_first_of( + whitespace, + cur_pos + ); } std::string name = app_name.substr(cur_pos); @@ -102,8 +118,7 @@ namespace HttpServer auto const range_port = app.equal_range("listen"); - if (range_port.first == range_port.second) - { + if (range_port.first == range_port.second) { std::cout << "Error: application port is not set;" << std::endl; return false; } @@ -121,7 +136,7 @@ namespace HttpServer for (auto const &value : list) { - const int port = std::strtol(value.c_str(), nullptr, 10); + const int port = std::atoi(value.c_str()); if (port) { if (is_tls) { @@ -215,7 +230,13 @@ namespace HttpServer return false; } - std::function app_call = reinterpret_cast(addr); + std::function app_call = reinterpret_cast(addr); if ( ! app_call) { std::cout << "Error: invalid function 'application_call' in module '" << it_module->second << "';" << std::endl; @@ -256,18 +277,14 @@ namespace HttpServer bool success = true; - try - { - if (app_init) - { + try { + if (app_init) { const std::string root = root_dir; success = app_init(root.data() ); } } - catch (std::exception &exc) - { + catch (std::exception &exc) { std::cout << "Warning: an exception was thrown when the application '" << it_module->second << "' was initialized: " << exc.what() << std::endl; - success = false; } @@ -278,23 +295,27 @@ namespace HttpServer auto const it_temp_dir = app.find("temp_dir"); - std::string temp_dir = app.cend() != it_temp_dir ? it_temp_dir->second : defaults.temp_dir; + std::string temp_dir = app.cend() != it_temp_dir + ? it_temp_dir->second + : defaults.temp_dir; auto const it_request_max_size = app.find("request_max_size"); - const size_t request_max_size = app.cend() != it_request_max_size ? std::strtoull(it_request_max_size->second.c_str(), nullptr, 10) : defaults.request_max_size; + const size_t request_max_size = app.cend() != it_request_max_size + ? std::strtoull(it_request_max_size->second.c_str(), nullptr, 10) + : defaults.request_max_size; auto const it_module_update = app.find("server_module_update"); - std::string module_update = app.cend() != it_module_update ? it_module_update->second : ""; + std::string module_update = app.cend() != it_module_update + ? it_module_update->second + : std::string(); // Calculate module index size_t module_index = std::numeric_limits::max(); - for (size_t i = 0; i < modules.size(); ++i) - { - if (modules[i] == module) - { + for (size_t i = 0; i < modules.size(); ++i) { + if (modules[i] == module) { module_index = i; break; } @@ -349,8 +370,10 @@ namespace HttpServer * @param mimes_types * @return bool */ - bool ConfigParser::parseMimes(const std::string &fileName, std::unordered_map &mimes_types) - { + bool ConfigParser::parseMimes( + const std::string &fileName, + std::unordered_map &mimes_types + ) { std::ifstream file(fileName); if ( ! file) { @@ -436,7 +459,10 @@ namespace HttpServer ); if (ext_unit.empty() == false) { - mimes_types.emplace(std::move(ext_unit), mime_type); + mimes_types.emplace( + std::move(ext_unit), + mime_type + ); } ext_pos = ext.find_first_not_of(whitespace, delimiter); @@ -446,7 +472,10 @@ namespace HttpServer } else { - mimes_types.emplace(std::move(ext), std::move(mime_type) ); + mimes_types.emplace( + std::move(ext), + std::move(mime_type) + ); } cur_pos = end_pos + 1; @@ -492,8 +521,11 @@ namespace HttpServer /** * Config - parse */ - bool ConfigParser::loadConfig(const std::string &conf_file_name, ServerSettings &settings, std::vector &modules) - { + bool ConfigParser::loadConfig( + const std::string &conf_file_name, + ServerSettings &settings, + std::vector &modules + ) { std::string str_buf; if (includeConfigFile(conf_file_name, str_buf) == false) { @@ -552,17 +584,20 @@ namespace HttpServer std::string param_value = str_buf.substr(cur_pos, delimiter - cur_pos); - if ("include" == param_name) - { - this->includeConfigFile(param_value, str_buf, end_pos + 1); - } - else - { - global.emplace(std::move(param_name), std::move(param_value) ); + if ("include" == param_name) { + this->includeConfigFile( + param_value, + str_buf, + end_pos + 1 + ); + } else { + global.emplace( + std::move(param_name), + std::move(param_value) + ); } - } - else // if comment line - { + } else { + // if comment line end_pos = str_buf.find_first_of("\r\n", cur_pos); } } @@ -622,19 +657,18 @@ namespace HttpServer std::string param_value = str_buf.substr(cur_pos, delimiter - cur_pos); - if ("include" == param_name) - { + if ("include" == param_name) { cur_pos = end_pos + 1; this->includeConfigFile(param_value, str_buf, cur_pos); block_end = findBlockEnd(str_buf, cur_pos); + } else { + app.emplace( + std::move(param_name), + std::move(param_value) + ); } - else - { - app.emplace(std::move(param_name), std::move(param_value) ); - } - } - else // if comment line - { + } else { + // if comment line end_pos = str_buf.find_first_of("\r\n", cur_pos); } } @@ -687,11 +721,15 @@ namespace HttpServer { auto const it_default_temp_dir = global.find("default_temp_dir"); - const std::string default_temp_dir = global.cend() != it_default_temp_dir ? it_default_temp_dir->second : System::getTempDir(); + const std::string default_temp_dir = global.cend() != it_default_temp_dir + ? it_default_temp_dir->second + : System::getTempDir(); auto const it_default_request_max_size = global.find("request_max_size"); - const size_t default_request_max_size = global.cend() != it_default_request_max_size ? std::strtoull(it_default_request_max_size->second.c_str(), nullptr, 10) : 0; + const size_t default_request_max_size = global.cend() != it_default_request_max_size + ? std::strtoull(it_default_request_max_size->second.c_str(), nullptr, 10) + : 0; ServerApplicationDefaultSettings defaults { default_temp_dir, diff --git a/src/server/config/ConfigParser.h b/src/server/config/ConfigParser.h index f7805dc..f994a00 100644 --- a/src/server/config/ConfigParser.h +++ b/src/server/config/ConfigParser.h @@ -10,13 +10,16 @@ namespace HttpServer class ConfigParser { private: - struct ServerApplicationDefaultSettings - { + struct ServerApplicationDefaultSettings { std::string temp_dir; size_t request_max_size; }; - static bool includeConfigFile(const std::string &fileName, std::string &strBuf, const size_t offset = 0); + static bool includeConfigFile( + const std::string &fileName, + std::string &strBuf, + const size_t offset = 0 + ); static bool addApplication( const std::unordered_multimap &app, @@ -25,9 +28,16 @@ namespace HttpServer ServerApplicationsTree &apps_tree ); - static bool parseMimes(const std::string &fileName, std::unordered_map &mimes_types); + static bool parseMimes( + const std::string &fileName, + std::unordered_map &mimes_types + ); public: - bool loadConfig(const std::string &conf, ServerSettings &settings, std::vector &modules); + bool loadConfig( + const std::string &conf, + ServerSettings &settings, + std::vector &modules + ); }; } diff --git a/src/server/data-variant/Abstract.cpp b/src/server/data-variant/Abstract.cpp index 5a13e4a..37d9744 100644 --- a/src/server/data-variant/Abstract.cpp +++ b/src/server/data-variant/Abstract.cpp @@ -3,18 +3,16 @@ namespace DataVariant { - const std::string &Abstract::getName() const noexcept - { + const std::string &Abstract::getName() const noexcept { return this->data_variant_name; } - void *Abstract::createStateStruct(const Transfer::request_data *rd, const std::unordered_map &contentParams) const - { + void *Abstract::createStateStruct( + const Transfer::request_data *rd, + const std::unordered_map &contentParams + ) const { return nullptr; } - void Abstract::destroyStateStruct(void *st) const noexcept - { - - } -}; + void Abstract::destroyStateStruct(void *st) const noexcept {} +} diff --git a/src/server/data-variant/Abstract.h b/src/server/data-variant/Abstract.h index 0ec2e0a..f9f239c 100644 --- a/src/server/data-variant/Abstract.h +++ b/src/server/data-variant/Abstract.h @@ -17,13 +17,19 @@ namespace DataVariant public: /** - * virtual destructor + * Virtual destructor */ virtual ~Abstract() noexcept = default; - virtual void *createStateStruct(const Transfer::request_data *rd, const std::unordered_map &contentParams) const; + virtual void *createStateStruct( + const Transfer::request_data *rd, + const std::unordered_map &contentParams + ) const; - virtual bool parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const = 0; + virtual bool parse( + const std::string &buf, + Transfer::request_data *rd, DataReceiver *dr + ) const = 0; virtual void destroyStateStruct(void *st) const noexcept; }; @@ -37,4 +43,4 @@ namespace DataVariant size_t left; void *reserved; }; -}; +} diff --git a/src/server/data-variant/FormUrlencoded.cpp b/src/server/data-variant/FormUrlencoded.cpp index 5535b14..08f8180 100644 --- a/src/server/data-variant/FormUrlencoded.cpp +++ b/src/server/data-variant/FormUrlencoded.cpp @@ -5,29 +5,27 @@ namespace DataVariant { - FormUrlencoded::FormUrlencoded() noexcept - { + FormUrlencoded::FormUrlencoded() noexcept { this->data_variant_name = "application/x-www-form-urlencoded"; } bool FormUrlencoded::parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const { - if (buf.empty() ) - { + if (buf.empty() ) { return 0 == dr->full_size || dr->full_size != dr->recv_total; } - for (size_t var_pos = 0, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) - { + for ( + size_t var_pos = 0, var_end = 0; + std::string::npos != var_end; + var_pos = var_end + 1 + ) { // Поиск следующего параметра var_end = buf.find('&', var_pos); - if (std::string::npos == var_end) - { - if (dr->full_size != dr->recv_total) - { + if (std::string::npos == var_end) { + if (dr->full_size != dr->recv_total) { dr->left = buf.size() - var_pos; - return true; } } @@ -38,26 +36,51 @@ namespace DataVariant if (delimiter >= var_end) { // Получить имя параметра - std::string var_name = Utils::urlDecode(buf.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos) ); + std::string var_name = Utils::urlDecode( + buf.substr( + var_pos, + std::string::npos != var_end + ? var_end - var_pos + : std::string::npos + ) + ); // Сохранить параметр с пустым значением - rd->incoming_data.emplace(std::move(var_name), std::string() ); + rd->incoming_data.emplace( + std::move(var_name), + std::string() + ); } else { // Получить имя параметра - std::string var_name = Utils::urlDecode(buf.substr(var_pos, delimiter - var_pos) ); + std::string var_name = Utils::urlDecode( + buf.substr( + var_pos, + delimiter - var_pos + ) + ); ++delimiter; // Получить значение параметра - std::string var_value = Utils::urlDecode(buf.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos) ); + std::string var_value = Utils::urlDecode( + buf.substr( + delimiter, + std::string::npos != var_end + ? var_end - delimiter + : std::string::npos + ) + ); // Сохранить параметр и значение - rd->incoming_data.emplace(std::move(var_name), std::move(var_value) ); + rd->incoming_data.emplace( + std::move(var_name), + std::move(var_value) + ); } } return true; } -}; +} diff --git a/src/server/data-variant/FormUrlencoded.h b/src/server/data-variant/FormUrlencoded.h index c52b575..141c525 100644 --- a/src/server/data-variant/FormUrlencoded.h +++ b/src/server/data-variant/FormUrlencoded.h @@ -12,4 +12,4 @@ namespace DataVariant public: virtual bool parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const override; }; -}; +} diff --git a/src/server/data-variant/MultipartFormData.cpp b/src/server/data-variant/MultipartFormData.cpp index 2c24504..56ec8cc 100644 --- a/src/server/data-variant/MultipartFormData.cpp +++ b/src/server/data-variant/MultipartFormData.cpp @@ -6,13 +6,11 @@ namespace DataVariant { - MultipartFormData::MultipartFormData() noexcept - { + MultipartFormData::MultipartFormData() noexcept { this->data_variant_name = "multipart/form-data"; } - enum class ParsingState : uint8_t - { + enum class ParsingState : uint8_t { INITIALIZATION = 0, FIND_DATA_BLOCK, GET_DATA_BLOCK_TYPE, @@ -20,15 +18,13 @@ namespace DataVariant SAVE_DATA_BLOCK, }; - enum class BlockType : uint8_t - { + enum class BlockType : uint8_t { UNKNOWN = 0, DATA, FILE, }; - struct StateMultipartFormData - { + struct StateMultipartFormData { std::string block_name; std::string block_value; std::string file_tmp_name; @@ -40,14 +36,15 @@ namespace DataVariant BlockType block_type; }; - void *MultipartFormData::createStateStruct(const Transfer::request_data *rd, const std::unordered_map &contentParams) const - { + void *MultipartFormData::createStateStruct( + const Transfer::request_data *rd, + const std::unordered_map &contentParams + ) const { std::string boundary; auto const it = contentParams.find("boundary"); - if (contentParams.cend() != it) - { + if (contentParams.cend() != it) { boundary = it->second; } @@ -57,8 +54,7 @@ namespace DataVariant }; } - void MultipartFormData::destroyStateStruct(void *st) const noexcept - { + void MultipartFormData::destroyStateStruct(void *st) const noexcept { delete reinterpret_cast(st); } @@ -68,8 +64,11 @@ namespace DataVariant std::unordered_map headers; - for (size_t line_end = buf.find(nl.data(), cur); cur < end; line_end = buf.find(nl.data(), cur) ) - { + for ( + size_t line_end = buf.find(nl.data(), cur); + cur < end; + line_end = buf.find(nl.data(), cur) + ) { size_t delimiter = buf.find(':', cur); if (std::string::npos == delimiter || delimiter > line_end) @@ -77,10 +76,12 @@ namespace DataVariant std::string header_name = buf.substr(cur, line_end - cur); Utils::trim(header_name); Utils::toLower(header_name); - headers.emplace(std::move(header_name), std::string() ); - } - else - { + + headers.emplace( + std::move(header_name), + std::string() + ); + } else { std::string header_name = buf.substr(cur, delimiter - cur); Utils::trim(header_name); Utils::toLower(header_name); @@ -90,7 +91,10 @@ namespace DataVariant std::string header_value = buf.substr(delimiter, line_end - delimiter); Utils::trim(header_value); - headers.emplace(std::move(header_name), std::move(header_value) ); + headers.emplace( + std::move(header_name), + std::move(header_value) + ); } // Перейти к следующему заголовку @@ -107,8 +111,7 @@ namespace DataVariant size_t delimiter = header.find(';'); - if (std::string::npos == delimiter) - { + if (std::string::npos == delimiter) { return header_params; } @@ -116,8 +119,7 @@ namespace DataVariant Utils::trim(content_disposition); // Проверить соответствие указанного формата - if ("form-data" != content_disposition) - { + if ("form-data" != content_disposition) { return header_params; } @@ -129,13 +131,21 @@ namespace DataVariant if (std::string::npos == delimiter || delimiter > end) { - std::string param_name = header.substr(cur, (std::string::npos != end) ? end - cur: std::string::npos); + std::string param_name = header.substr( + cur, + std::string::npos != end + ? end - cur + : std::string::npos + ); + Utils::trim(param_name); Utils::toLower(param_name); - header_params.emplace(std::move(param_name), std::string() ); - } - else - { + + header_params.emplace( + std::move(param_name), + std::string() + ); + } else { std::string param_name = header.substr(cur, delimiter - cur); Utils::trim(param_name); Utils::toLower(param_name); @@ -148,26 +158,40 @@ namespace DataVariant { end = header.find(';', cur); - std::string param_value = header.substr(delimiter, (std::string::npos != end) ? end - delimiter : std::string::npos); + std::string param_value = header.substr( + delimiter, + std::string::npos != end + ? end - delimiter + : std::string::npos + ); + Utils::trim(param_value); - header_params.emplace(std::move(param_name), std::move(param_value) ); - } - else - { + header_params.emplace( + std::move(param_name), + std::move(param_value) + ); + } else { ++delimiter; cur = header.find('"', delimiter); end = header.find(';', cur); - std::string param_value = header.substr(delimiter, (std::string::npos != cur) ? cur - delimiter : std::string::npos); - - header_params.emplace(std::move(param_name), std::move(param_value) ); + std::string param_value = header.substr( + delimiter, + std::string::npos != cur + ? cur - delimiter + : std::string::npos + ); + + header_params.emplace( + std::move(param_name), + std::move(param_value) + ); } } - if (std::string::npos != end) - { + if (std::string::npos != end) { ++end; } } @@ -175,8 +199,11 @@ namespace DataVariant return header_params; } - bool MultipartFormData::parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const - { + bool MultipartFormData::parse( + const std::string &buf, + Transfer::request_data *rd, + DataReceiver *dr + ) const { StateMultipartFormData *ss = reinterpret_cast(dr->ss); size_t cur = 0; @@ -187,22 +214,18 @@ namespace DataVariant { case ParsingState::INITIALIZATION: { - if (ss->boundary.empty() ) - { + if (ss->boundary.empty() ) { return false; } const std::string data_end("--" + ss->boundary + "--\r\n"); - if (buf.size() < data_end.length() ) - { + if (buf.size() < data_end.length() ) { dr->left = buf.size(); - return dr->full_size != dr->recv_total; } - if (0 == buf.find(data_end) ) - { + if (0 == buf.find(data_end) ) { return dr->full_size == data_end.length() && dr->full_size == dr->recv_total; } @@ -210,8 +233,7 @@ namespace DataVariant cur = buf.find(first_block); - if (0 != cur) - { + if (0 != cur) { return false; } @@ -228,17 +250,14 @@ namespace DataVariant const std::string data_end("\r\n--" + ss->boundary + "--\r\n"); - if (data_end.length() > dr->left) - { + if (data_end.length() > dr->left) { return dr->full_size != dr->recv_total; } const size_t end = buf.find(data_end, cur); - if (end == cur) - { + if (end == cur) { dr->left -= data_end.length(); - return dr->full_size == dr->recv_total; } @@ -246,8 +265,7 @@ namespace DataVariant cur = buf.find(block_delimiter, cur); - if (std::string::npos == cur) - { + if (std::string::npos == cur) { return dr->full_size != dr->recv_total; } @@ -262,10 +280,8 @@ namespace DataVariant { const size_t end = buf.find("\r\n\r\n", cur); - if (std::string::npos == end) - { + if (std::string::npos == end) { dr->left = buf.size() - cur; - return dr->full_size != dr->recv_total; } @@ -276,8 +292,7 @@ namespace DataVariant auto const it = headers.find("content-disposition"); // Если заголовок не определён - if (headers.cend() == it) - { + if (headers.cend() == it) { return false; } @@ -286,8 +301,7 @@ namespace DataVariant // Поиск имени блока данных auto const it_name = header_params.find("name"); - if (header_params.cend() == it_name) - { + if (header_params.cend() == it_name) { return false; } @@ -304,8 +318,7 @@ namespace DataVariant // Найти тип файла auto const it_filetype = headers.find("content-type"); - if (headers.cend() != it_filetype) - { + if (headers.cend() != it_filetype) { ss->file_type = it_filetype->second; } @@ -315,8 +328,7 @@ namespace DataVariant // Создать файл ss->file.open(ss->file_tmp_name, std::ofstream::trunc | std::ofstream::binary); - if (false == ss->file.is_open() ) - { + if (ss->file.is_open() == false) { return false; } } @@ -340,16 +352,20 @@ namespace DataVariant switch (ss->block_type) { - case BlockType::DATA: - { - ss->block_value.append(buf.cbegin() + cur, buf.cbegin() + end); + case BlockType::DATA: { + ss->block_value.append( + buf.cbegin() + long(cur), + buf.cbegin() + long(end) + ); break; } - case BlockType::FILE: - { - ss->file.write(&buf[cur], end - cur); + case BlockType::FILE: { + ss->file.write( + &buf[cur], + std::streamsize(end - cur) + ); break; } @@ -358,10 +374,8 @@ namespace DataVariant return false; } - if (std::string::npos == block_end) - { + if (std::string::npos == block_end) { dr->left = buf.size() - end; - return dr->full_size != dr->recv_total; } @@ -376,19 +390,27 @@ namespace DataVariant { switch (ss->block_type) { - case BlockType::DATA: - { - rd->incoming_data.emplace(std::move(ss->block_name), std::move(ss->block_value) ); + case BlockType::DATA: { + rd->incoming_data.emplace( + std::move(ss->block_name), + std::move(ss->block_value) + ); break; } - case BlockType::FILE: - { - rd->incoming_files.emplace(std::move(ss->block_name), Transfer::FileIncoming(std::move(ss->file_tmp_name), std::move(ss->file_name), std::move(ss->file_type), ss->file.tellp() ) ); + case BlockType::FILE: { + rd->incoming_files.emplace( + std::move(ss->block_name), + Transfer::FileIncoming( + std::move(ss->file_tmp_name), + std::move(ss->file_name), + std::move(ss->file_type), + size_t(ss->file.tellp()) + ) + ); ss->file.close(); - break; } @@ -408,4 +430,4 @@ namespace DataVariant return dr->full_size != dr->recv_total; } -}; +} diff --git a/src/server/data-variant/MultipartFormData.h b/src/server/data-variant/MultipartFormData.h index 65e9071..1a45fc0 100644 --- a/src/server/data-variant/MultipartFormData.h +++ b/src/server/data-variant/MultipartFormData.h @@ -10,10 +10,17 @@ namespace DataVariant MultipartFormData() noexcept; public: - virtual void *createStateStruct(const Transfer::request_data *rd, const std::unordered_map &contentParams) const override; + virtual void *createStateStruct( + const Transfer::request_data *rd, + const std::unordered_map &contentParams + ) const override; - virtual bool parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const override; + virtual bool parse( + const std::string &buf, + Transfer::request_data *rd, + DataReceiver *dr + ) const override; virtual void destroyStateStruct(void *st) const noexcept override; }; -}; +} diff --git a/src/server/data-variant/TextPlain.cpp b/src/server/data-variant/TextPlain.cpp index 1f4333c..ecb5efa 100644 --- a/src/server/data-variant/TextPlain.cpp +++ b/src/server/data-variant/TextPlain.cpp @@ -3,29 +3,27 @@ namespace DataVariant { - TextPlain::TextPlain() noexcept - { + TextPlain::TextPlain() noexcept { this->data_variant_name = "text/plain"; } bool TextPlain::parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const { - if (buf.empty() ) - { + if (buf.empty() ) { return 0 == dr->full_size || dr->full_size != dr->recv_total; } - for (size_t var_pos = 0, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1) - { + for ( + size_t var_pos = 0, var_end = 0; + std::string::npos != var_end; + var_pos = var_end + 1 + ) { // Поиск следующего параметра var_end = buf.find('&', var_pos); - if (std::string::npos == var_end) - { - if (dr->full_size != dr->recv_total) - { + if (std::string::npos == var_end) { + if (dr->full_size != dr->recv_total) { dr->left = buf.size() - var_pos; - return true; } } @@ -36,26 +34,40 @@ namespace DataVariant if (delimiter >= var_end) { // Получить имя параметра - std::string var_name = buf.substr(var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos); + std::string var_name = buf.substr( + var_pos, + std::string::npos != var_end + ? var_end - var_pos + : std::string::npos + ); // Сохранить параметр с пустым значением - rd->incoming_data.emplace(std::move(var_name), std::string() ); - } - else - { + rd->incoming_data.emplace( + std::move(var_name), + std::string() + ); + } else { // Получить имя параметра std::string var_name = buf.substr(var_pos, delimiter - var_pos); ++delimiter; // Получить значение параметра - std::string var_value = buf.substr(delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos); + std::string var_value = buf.substr( + delimiter, + std::string::npos != var_end + ? var_end - delimiter + : std::string::npos + ); // Сохранить параметр и значение - rd->incoming_data.emplace(std::move(var_name), std::move(var_value) ); + rd->incoming_data.emplace( + std::move(var_name), + std::move(var_value) + ); } } return true; } -}; +} diff --git a/src/server/data-variant/TextPlain.h b/src/server/data-variant/TextPlain.h index 8d98766..d6ba101 100644 --- a/src/server/data-variant/TextPlain.h +++ b/src/server/data-variant/TextPlain.h @@ -12,4 +12,4 @@ namespace DataVariant public: virtual bool parse(const std::string &buf, Transfer::request_data *rd, DataReceiver *dr) const override; }; -}; +} diff --git a/src/server/protocol/ServerHttp1.cpp b/src/server/protocol/ServerHttp1.cpp index 290ae9b..8bb5f17 100644 --- a/src/server/protocol/ServerHttp1.cpp +++ b/src/server/protocol/ServerHttp1.cpp @@ -10,14 +10,22 @@ namespace HttpServer { - ServerHttp1::ServerHttp1(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls) noexcept + ServerHttp1::ServerHttp1( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls + ) noexcept : ServerProtocol(sock, settings, controls) { } - bool ServerHttp1::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 { static const std::unordered_map status_list { { 200, "OK" }, { 206, "Partial Content" }, @@ -33,17 +41,14 @@ namespace HttpServer auto const it = status_list.find(static_cast(status) ); - if (status_list.cend() != it) - { + if (status_list.cend() != it) { const std::string &status = it->second; - str += ' ' + status; } str += "\r\n"; - for (auto const &header : headers) - { + for (auto const &header : headers) { str += header.first + ": " + header.second + "\r\n"; } @@ -52,25 +57,34 @@ namespace HttpServer return this->sock.nonblock_send(str, timeout) > 0; // >= 0 } - long ServerHttp1::sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const - { - const long send_size = this->sock.nonblock_send(src, size, timeout); + long ServerHttp1::sendData( + const void *src, + size_t size, + const std::chrono::milliseconds &timeout, + DataTransfer *dt + ) const { + const long send_size = this->sock.nonblock_send( + src, + size, + timeout + ); - if (send_size > 0) - { - dt->send_total += send_size; + if (send_size > 0) { + dt->send_total += static_cast(send_size); } return send_size; } - void ServerHttp1::close() - { + void ServerHttp1::close() { this->sock.close(); } - bool ServerHttp1::packRequestParameters(std::vector &buf, const struct Request &req, const std::string &rootDir) const - { + bool ServerHttp1::packRequestParameters( + std::vector &buf, + const struct Request &req, + const std::string &rootDir + ) const { Utils::packNumber(buf, static_cast(Transfer::ProtocolVariant::HTTP_1) ); Utils::packString(buf, rootDir); Utils::packString(buf, req.host); @@ -83,34 +97,48 @@ namespace HttpServer return true; } - void ServerHttp1::unpackResponseParameters(struct Request &req, const void *src) const - { - Utils::unpackContainer(req.outgoing_headers, reinterpret_cast(src) ); + void ServerHttp1::unpackResponseParameters( + struct Request &req, + const void *src + ) const { + Utils::unpackContainer( + req.outgoing_headers, + reinterpret_cast(src) + ); } - static bool getRequest(const Socket::Adapter &sock, struct Request &req, std::vector &buf, std::string &str_buf) - { + static bool getRequest( + const Socket::Adapter &sock, + struct Request &req, + std::vector &buf, + std::string &str_buf + ) { // Получить данные запроса от клиента - const long recv_size = sock.nonblock_recv(buf, req.timeout); + const long recv_size = sock.nonblock_recv( + buf, + req.timeout + ); - if (recv_size < 0 && str_buf.empty() ) - { + if (recv_size < 0 && str_buf.empty() ) { return false; } - if (recv_size > 0) // Если данные были получены - { - str_buf.append(buf.cbegin(), buf.cbegin() + recv_size); + if (recv_size > 0) { // Если данные были получены + str_buf.append( + buf.cbegin(), + buf.cbegin() + recv_size + ); } return true; } - static Http::StatusCode getRequestHeaders(struct Request &req, std::string &str_buf) - { + static Http::StatusCode getRequestHeaders( + struct Request &req, + std::string &str_buf + ) { // Если запрос пустой - if (str_buf.empty() ) - { + if (str_buf.empty() ) { return Http::StatusCode::BAD_REQUEST; } @@ -118,8 +146,7 @@ namespace HttpServer size_t headers_end = str_buf.find("\r\n\r\n"); // Если найден конец заголовков - if (std::string::npos == headers_end) - { + if (std::string::npos == headers_end) { return Http::StatusCode::BAD_REQUEST; } @@ -130,8 +157,7 @@ namespace HttpServer size_t str_end = str_buf.find("\r\n"); // Если не найден конец заголовка - if (std::string::npos == str_end) - { + if (std::string::npos == str_end) { return Http::StatusCode::BAD_REQUEST; } @@ -142,7 +168,11 @@ namespace HttpServer size_t delimiter = str_buf.find(' ', str_cur); // Получить метод запроса (GET, POST, PUT, DELETE, ...) - req.method = str_buf.substr(str_cur, delimiter - str_cur); + req.method = str_buf.substr( + str_cur, + delimiter - str_cur + ); + Utils::toLower(req.method); // Сохранить метод и параметры запроса @@ -153,19 +183,16 @@ namespace HttpServer size_t uri_end = str_buf.find(' ', delimiter); // Если окончание не найдено - if (std::string::npos == uri_end) - { + if (std::string::npos == uri_end) { uri_end = str_end; // то версия протокола HTTP - 0.9 // const std::string version = "0.9"; - } - else // Если окончание найдено - { + } else { + // Если окончание найдено str_buf[uri_end] = '\0'; const size_t ver_beg = uri_end + 6; // Пропустить "HTTP/" - if (ver_beg < str_end) - { + if (ver_beg < str_end) { // Получить версию протокола HTTP // const std::string version = str_buf.substr(ver_beg, str_end - ver_beg); } @@ -182,36 +209,53 @@ namespace HttpServer str_buf[str_end] = '\0'; // Цикл извлечения заголовков запроса - for (; str_cur != headers_end; str_end = str_buf.find("\r\n", str_cur), str_buf[str_end] = '\0') - { + for ( + ; + str_cur != headers_end; + str_end = str_buf.find("\r\n", str_cur), str_buf[str_end] = '\0' + ) { // Поиск разделителя названия заголовка и его значения delimiter = str_buf.find(':', str_cur); // Если разделитель найден в текущей строке if (delimiter < str_end) { - std::string header_name = str_buf.substr(str_cur, delimiter - str_cur); + std::string header_name = str_buf.substr( + str_cur, + delimiter - str_cur + ); + Utils::toLower(header_name); - std::string header_value = str_buf.substr(delimiter + 1, str_end - delimiter - 1); + std::string header_value = str_buf.substr( + delimiter + 1, + str_end - delimiter - 1 + ); + // Удалить лишние пробелы в начале и в конце строки Utils::trim(header_value); // Сохранить заголовок и его значение - req.incoming_headers.emplace(std::move(header_name), std::move(header_value) ); + req.incoming_headers.emplace( + std::move(header_name), + std::move(header_value) + ); } // Перейти к следующей строке str_cur = str_end + 2; } - str_buf.erase(str_buf.begin(), str_buf.begin() + headers_end + 2); + str_buf.erase(0, headers_end + 2); return Http::StatusCode::EMPTY; } - const ServerApplicationSettings *ServerHttp1::getApplicationSettings(struct Request &req, const bool isSecureConnection) const - { + const ServerApplicationSettings * + ServerHttp1::getApplicationSettings( + struct Request &req, + const bool isSecureConnection + ) const { // Получить доменное имя (или адрес) назначения запроса auto const it_host = req.incoming_headers.find("host"); @@ -229,14 +273,19 @@ namespace HttpServer const int default_port = isSecureConnection ? 443 : 80; // Получить номер порта - const int port = (std::string::npos != delimiter) ? std::strtol(host_header.substr(delimiter + 1).c_str(), nullptr, 10) : default_port; + const int port = (std::string::npos != delimiter) + ? std::atoi(host_header.substr(delimiter + 1).c_str()) + : default_port; // Поиск настроек приложения по имени const ServerApplicationSettings *app_sets = this->settings.apps_tree.find(req.host); // Если приложение найдено - if (app_sets && (app_sets->ports.cend() != app_sets->ports.find(port) || app_sets->tls_ports.cend() != app_sets->tls_ports.find(port) ) ) - { + if (app_sets && ( + app_sets->ports.cend() != app_sets->ports.find(port) || + app_sets->tls_ports.cend() != app_sets->tls_ports.find(port) + ) + ) { return app_sets; } } @@ -244,13 +293,15 @@ namespace HttpServer return nullptr; } - Http::StatusCode ServerHttp1::getRequestData(struct Request &req, std::string &str_buf, const ServerApplicationSettings &appSets) const - { + Http::StatusCode ServerHttp1::getRequestData( + struct Request &req, + std::string &str_buf, + const ServerApplicationSettings &appSets + ) const { // Определить вариант данных запроса (заодно проверить, есть ли данные) auto const it = req.incoming_headers.find("content-type"); - if (req.incoming_headers.cend() == it) - { + if (req.incoming_headers.cend() == it) { return Http::StatusCode::EMPTY; } @@ -270,33 +321,57 @@ namespace HttpServer data_variant_name = header_value.substr(0, delimiter); Utils::trim(data_variant_name); - for (size_t str_param_cur = delimiter + 1, str_param_end = 0; std::string::npos != str_param_end; str_param_cur = str_param_end + 1) - { + for ( + size_t str_param_cur = delimiter + 1, str_param_end = 0; + std::string::npos != str_param_end; + str_param_cur = str_param_end + 1 + ) { str_param_end = header_value.find(';', str_param_cur); delimiter = header_value.find('=', str_param_cur); if (delimiter >= str_param_end) { - std::string param_name = header_value.substr(str_param_cur, std::string::npos != str_param_end ? str_param_end - str_param_cur : std::string::npos); + std::string param_name = header_value.substr( + str_param_cur, + std::string::npos != str_param_end + ? str_param_end - str_param_cur + : std::string::npos + ); + Utils::trim(param_name); - content_params.emplace(std::move(param_name), std::string() ); + + content_params.emplace( + std::move(param_name), + std::string() + ); } else { - std::string param_name = header_value.substr(str_param_cur, delimiter - str_param_cur); + std::string param_name = header_value.substr( + str_param_cur, + delimiter - str_param_cur + ); + Utils::trim(param_name); ++delimiter; - std::string param_value = header_value.substr(delimiter, std::string::npos != str_param_end ? str_param_end - delimiter : std::string::npos); + std::string param_value = header_value.substr( + delimiter, + std::string::npos != str_param_end + ? str_param_end - delimiter + : std::string::npos + ); + Utils::trim(param_value); - content_params.emplace(std::move(param_name), std::move(param_value) ); + content_params.emplace( + std::move(param_name), + std::move(param_value) + ); } } - } - else - { + } else { data_variant_name = header_value; } @@ -304,8 +379,7 @@ namespace HttpServer auto const variant = this->settings.variants.find(data_variant_name); // Если сервер не поддерживает формат полученных данных - if (this->settings.variants.cend() == variant) - { + if (this->settings.variants.cend() == variant) { return Http::StatusCode::BAD_REQUEST; } @@ -316,14 +390,16 @@ namespace HttpServer auto const it_len = req.incoming_headers.find("content-length"); - if (req.incoming_headers.cend() != it_len) - { - data_length = std::strtoull(it_len->second.c_str(), nullptr, 10); + if (req.incoming_headers.cend() != it_len) { + data_length = std::strtoull( + it_len->second.c_str(), + nullptr, + 10 + ); } // Если размер запроса превышает лимит (если лимит был установлен) - if (data_length > appSets.request_max_size && 0 != appSets.request_max_size) - { + if (data_length > appSets.request_max_size && 0 != appSets.request_max_size) { return Http::StatusCode::REQUEST_ENTITY_TOO_LARGE; } @@ -338,16 +414,15 @@ namespace HttpServer std::string data_buf; - if (data_length >= str_buf.length() ) - { + if (str_buf.length() <= data_length) { dr.recv_total = str_buf.length(); - data_buf.swap(str_buf); - } - else - { - data_buf.assign(str_buf.cbegin(), str_buf.cbegin() + data_length); - str_buf.erase(str_buf.begin(), str_buf.begin() + data_length); + } else { + data_buf.assign( + str_buf, 0, data_length + ); + + str_buf.erase(0, data_length); dr.recv_total = data_buf.size(); } @@ -356,21 +431,33 @@ namespace HttpServer while (result && dr.full_size > dr.recv_total) { - std::vector buf(dr.full_size - dr.recv_total >= 512 * 1024 ? 512 * 1024 : dr.full_size - dr.recv_total); + std::vector buf( + dr.full_size - dr.recv_total >= 512 * 1024 + ? 512 * 1024 + : dr.full_size - dr.recv_total + ); - long recv_size = this->sock.nonblock_recv(buf.data(), buf.size(), req.timeout); + long recv_size = this->sock.nonblock_recv( + buf.data(), + buf.size(), + req.timeout + ); - if (recv_size <= 0) - { + if (recv_size <= 0) { result = false; - break; } - dr.recv_total += recv_size; + dr.recv_total += static_cast(recv_size); - data_buf.erase(data_buf.begin(), data_buf.end() - dr.left); - data_buf.append(buf.cbegin(), buf.cbegin() + recv_size); + data_buf.erase( + 0, data_buf.length() - dr.left + ); + + data_buf.append( + buf.data(), + 0, static_cast(recv_size) + ); dr.left = 0; @@ -379,27 +466,30 @@ namespace HttpServer data_variant->destroyStateStruct(dr.ss); - // Разобрать данные на составляющие - if (false == result) - { - for (auto const &it : req.incoming_files) - { + if (false == result) { + for (auto const &it : req.incoming_files) { std::remove(it.second.getTmpName().c_str() ); } return Http::StatusCode::BAD_REQUEST; } - if (dr.left) - { - str_buf.assign(data_buf.cend() - dr.left, data_buf.cend() ); + if (dr.left) { + str_buf.assign( + data_buf, + data_buf.length() - dr.left, + data_buf.length() + ); } return Http::StatusCode::EMPTY; } - static void sendStatus(const Socket::Adapter &sock, const struct Request &req, const Http::StatusCode statusCode) - { + static void sendStatus( + const Socket::Adapter &sock, + const struct Request &req, + const Http::StatusCode statusCode + ) { static const std::unordered_map status_list { { 400, "Bad Request" }, { 404, "Not Found" }, @@ -408,8 +498,7 @@ namespace HttpServer auto const it = status_list.find(static_cast(statusCode) ); - if (status_list.cend() != it) - { + if (status_list.cend() != it) { const std::string &status = it->second; std::string headers("HTTP/1.1 " + std::to_string(static_cast(statusCode) ) + ' ' + status + "\r\n\r\n"); @@ -418,19 +507,27 @@ namespace HttpServer } } - static void getConnectionParams(struct Request &req, const bool isSecureConnection) - { + static void getConnectionParams( + struct Request &req, + const bool isSecureConnection + ) { auto const it_in_connection = req.incoming_headers.find("connection"); auto const it_out_connection = req.outgoing_headers.find("connection"); - if (req.incoming_headers.cend() != it_in_connection && req.outgoing_headers.cend() != it_out_connection) - { + if ( + req.incoming_headers.cend() != it_in_connection && + req.outgoing_headers.cend() != it_out_connection + ) { const std::string connection_in = Utils::getLowerString(it_in_connection->second); const std::string connection_out = Utils::getLowerString(it_out_connection->second); auto const incoming_params = Utils::explode(connection_in, ','); - auto const it = std::find(incoming_params.cbegin(), incoming_params.cend(), connection_out); + auto const it = std::find( + incoming_params.cbegin(), + incoming_params.cend(), + connection_out + ); if (incoming_params.cend() != it) { @@ -440,8 +537,7 @@ namespace HttpServer { --req.keep_alive_count; - if (0 < req.keep_alive_count) - { + if (0 < req.keep_alive_count) { req.connection_params |= ConnectionParams::CONNECTION_REUSE; } } @@ -453,24 +549,19 @@ namespace HttpServer { const std::string upgrade = Utils::getLowerString(it_out_upgrade->second); - if ("h2" == upgrade) - { - if (isSecureConnection) - { + if ("h2" == upgrade) { + if (isSecureConnection) { req.protocol_variant = Transfer::ProtocolVariant::HTTP_2; req.connection_params |= ConnectionParams::CONNECTION_REUSE; } } - else if ("h2c" == upgrade) - { - if (false == isSecureConnection) - { + else if ("h2c" == upgrade) { + if (false == isSecureConnection) { req.protocol_variant = Transfer::ProtocolVariant::HTTP_2; req.connection_params |= ConnectionParams::CONNECTION_REUSE; } } - else if ("websocket" == upgrade) - { + else if ("websocket" == upgrade) { req.connection_params |= ConnectionParams::CONNECTION_LEAVE_OPEN; } } @@ -479,58 +570,61 @@ namespace HttpServer } } - void ServerHttp1::useHttp1Protocol(struct Request &req, std::vector &buf, std::string &str_buf) const - { - if (false == getRequest(this->sock, req, buf, str_buf) ) - { + void ServerHttp1::useHttp1Protocol( + struct Request &req, + std::vector &buf, + std::string &str_buf + ) const { + if (getRequest(this->sock, req, buf, str_buf) == false) { return; } Http::StatusCode error_code = getRequestHeaders(req, str_buf); - if (error_code != Http::StatusCode::EMPTY) - { + if (error_code != Http::StatusCode::EMPTY) { sendStatus(this->sock, req, error_code); - return; } - const ServerApplicationSettings *app_sets = this->getApplicationSettings(req, this->sock.get_tls_session() != 0); + const ServerApplicationSettings *app_sets = this->getApplicationSettings( + req, + this->sock.get_tls_session() != nullptr + ); // Если приложение не найдено - if (nullptr == app_sets) - { + if (nullptr == app_sets) { sendStatus(this->sock, req, Http::StatusCode::NOT_FOUND); - return; } error_code = this->getRequestData(req, str_buf, *app_sets); - if (error_code != Http::StatusCode::EMPTY) - { + if (error_code != Http::StatusCode::EMPTY) { sendStatus(this->sock, req, error_code); - return; } this->runApplication(req, *app_sets); - for (auto const &it : req.incoming_files) - { + for (auto const &it : req.incoming_files) { std::remove(it.second.getTmpName().c_str() ); } - if (EXIT_SUCCESS == req.app_exit_code) - { - getConnectionParams(req, this->sock.get_tls_session() != 0); + if (EXIT_SUCCESS == req.app_exit_code) { + getConnectionParams( + req, + this->sock.get_tls_session() != nullptr + ); - Sendfile::xSendfile(std::ref(*this), req, this->settings.mimes_types); + Sendfile::xSendfile( + std::ref(*this), + req, + this->settings.mimes_types + ); } } - static bool isConnectionLeaveOpen(const struct Request &req) - { + static bool isConnectionLeaveOpen(const struct Request &req) { return (req.connection_params & ConnectionParams::CONNECTION_LEAVE_OPEN) == ConnectionParams::CONNECTION_LEAVE_OPEN; } @@ -544,8 +638,7 @@ namespace HttpServer std::vector buf(4096); std::string str_buf; - do - { + do { // Подготовить параметры для получения данных req.connection_params = ConnectionParams::CONNECTION_CLOSE; req.app_exit_code = EXIT_FAILURE; @@ -556,11 +649,10 @@ namespace HttpServer } while (Sendfile::isConnectionReuse(req) ); - if (isConnectionLeaveOpen(req) ) - { + if (isConnectionLeaveOpen(req) ) { return new ServerWebSocket(*this); } return this; } -}; +} diff --git a/src/server/protocol/ServerHttp1.h b/src/server/protocol/ServerHttp1.h index cc7f2c3..258e2c8 100644 --- a/src/server/protocol/ServerHttp1.h +++ b/src/server/protocol/ServerHttp1.h @@ -8,22 +8,57 @@ namespace HttpServer class ServerHttp1 : public ServerProtocol { private: - const ServerApplicationSettings *getApplicationSettings(struct Request &rp, const bool isSecureConnection) const; - Http::StatusCode getRequestData(struct Request &rp, std::string &str_buf, const ServerApplicationSettings &appSets) const; + const ServerApplicationSettings *getApplicationSettings( + struct Request &rp, + const bool isSecureConnection + ) const; + + Http::StatusCode getRequestData( + struct Request &rp, + std::string &str_buf, + const ServerApplicationSettings &appSets + ) const; protected: - void useHttp1Protocol(struct Request &rp, std::vector &buf, std::string &str_buf) const; + void useHttp1Protocol( + struct Request &rp, + std::vector &buf, + std::string &str_buf + ) const; public: - ServerHttp1(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls) noexcept; + ServerHttp1( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls + ) noexcept; + + virtual bool sendHeaders( + const Http::StatusCode status, + std::vector > &headers, + const std::chrono::milliseconds &timeout, + const bool endStream + ) const override; + + virtual long sendData( + const void *src, + size_t size, + const std::chrono::milliseconds &timeout, + DataTransfer *dt + ) const override; - virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const override; - virtual long sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const override; + virtual bool packRequestParameters( + std::vector &buf, + const struct Request &rp, + const std::string &rootDir + ) const override; - virtual bool packRequestParameters(std::vector &buf, const struct Request &rp, const std::string &rootDir) const override; - virtual void unpackResponseParameters(struct Request &req, const void *src) const override; + virtual void unpackResponseParameters( + struct Request &req, + const void *src + ) const override; virtual ServerProtocol *process() override; virtual void close() override; }; -}; +} diff --git a/src/server/protocol/ServerHttp2.cpp b/src/server/protocol/ServerHttp2.cpp index 5ef4991..12ae2be 100644 --- a/src/server/protocol/ServerHttp2.cpp +++ b/src/server/protocol/ServerHttp2.cpp @@ -7,7 +7,12 @@ namespace HttpServer { - ServerHttp2::ServerHttp2(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, SocketsQueue &sockets) noexcept + ServerHttp2::ServerHttp2( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls, + SocketsQueue &sockets + ) noexcept : ServerHttp2Protocol(sock, settings, controls, nullptr), sockets(sockets) { @@ -17,8 +22,13 @@ namespace HttpServer this->sock.close(); } - static uint8_t *setHttp2FrameHeader(uint8_t *addr, const uint32_t frameSize, const Http2::FrameType frameType, const Http2::FrameFlag frameFlags, const uint32_t streamId) noexcept - { + static uint8_t *setHttp2FrameHeader( + uint8_t *addr, + const uint32_t frameSize, + const Http2::FrameType frameType, + const Http2::FrameFlag frameFlags, + const uint32_t streamId + ) noexcept { Utils::hton24(addr, frameSize); *(addr + 3) = static_cast(frameType); *(addr + 4) = static_cast(frameFlags); @@ -27,8 +37,11 @@ namespace HttpServer return (addr + Http2::FRAME_HEADER_SIZE); } - static Http2::IncStream &getStreamData(std::unordered_map &streams, const uint32_t streamId, Http2::ConnectionData &conn) noexcept - { + static Http2::IncStream &getStreamData( + std::unordered_map &streams, + const uint32_t streamId, + Http2::ConnectionData &conn + ) noexcept { auto it = streams.find(streamId); if (streams.end() != it) { @@ -38,12 +51,22 @@ namespace HttpServer return streams.emplace(streamId, Http2::IncStream(streamId, conn) ).first->second; } - static void sendWindowUpdate(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, const Http2::IncStream &stream, const uint32_t size) noexcept - { + static void sendWindowUpdate( + const Socket::Adapter &sock, + const std::chrono::milliseconds &timeout, + const Http2::IncStream &stream, + const uint32_t size + ) noexcept { std::array buf; uint8_t *addr = buf.data(); - addr = setHttp2FrameHeader(addr, sizeof(uint32_t), Http2::FrameType::WINDOW_UPDATE, Http2::FrameFlag::EMPTY, stream.stream_id); + addr = setHttp2FrameHeader( + addr, + sizeof(uint32_t), + Http2::FrameType::WINDOW_UPDATE, + Http2::FrameFlag::EMPTY, + stream.stream_id + ); *reinterpret_cast(addr) = ::htonl(size); @@ -52,8 +75,12 @@ namespace HttpServer sock.nonblock_send(buf.data(), buf.size(), timeout); } - static Http2::ErrorCode parseHttp2Data(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) - { + static Http2::ErrorCode parseHttp2Data( + Http2::FrameMeta &meta, + Http2::IncStream &stream, + const uint8_t *src, + const uint8_t *end + ) { if (0 == meta.stream_id) { return Http2::ErrorCode::PROTOCOL_ERROR; } @@ -91,24 +118,20 @@ namespace HttpServer buf.append(src, end - padding); - dr->recv_total += end - padding - src; + dr->recv_total += size_t(end - src) - padding; - if (dr->data_variant->parse(buf, rd, dr) ) - { - buf.erase(buf.begin(), buf.end() - dr->left); - } - else - { + if (dr->data_variant->parse(buf, rd, dr) ) { + buf.erase( + 0, buf.length() - dr->left + ); + } else { error_code = Http2::ErrorCode::PROTOCOL_ERROR; } - } - else - { + } else { error_code = Http2::ErrorCode::PROTOCOL_ERROR; } - if (meta.flags & Http2::FrameFlag::END_STREAM) - { + if (meta.flags & Http2::FrameFlag::END_STREAM) { stream.state = Http2::StreamState::HALF_CLOSED; ServerProtocol::destroyDataReceiver(stream.reserved); @@ -118,9 +141,15 @@ namespace HttpServer return error_code; } - static Http2::ErrorCode parseHttp2Headers(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) - { - stream.state = (meta.flags & Http2::FrameFlag::END_STREAM) ? Http2::StreamState::HALF_CLOSED : Http2::StreamState::OPEN; + static Http2::ErrorCode parseHttp2Headers( + Http2::FrameMeta &meta, + Http2::IncStream &stream, + const uint8_t *src, + const uint8_t *end + ) { + stream.state = (meta.flags & Http2::FrameFlag::END_STREAM) + ? Http2::StreamState::HALF_CLOSED + : Http2::StreamState::OPEN; uint8_t padding = 0; @@ -138,7 +167,9 @@ namespace HttpServer if (meta.flags & Http2::FrameFlag::PRIORITY) { // Stream id - const uint32_t depend_stream_id = ::ntohl(*reinterpret_cast(src) ) & ~(1 << 31); + const uint32_t depend_stream_id = ::ntohl( + *reinterpret_cast(src) + ) & ~(uint32_t(1) << 31); src += sizeof(uint32_t); @@ -148,15 +179,19 @@ namespace HttpServer src += sizeof(uint8_t); } - if (HPack::unpack(src, end - src - padding, stream) == false) { + if (HPack::unpack(src, size_t(end - src) - padding, stream) == false) { return Http2::ErrorCode::COMPRESSION_ERROR; } return Http2::ErrorCode::NO_ERROR; } - static Http2::ErrorCode parseHttp2rstStream(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) - { + static Http2::ErrorCode parseHttp2rstStream( + Http2::FrameMeta &meta, + Http2::IncStream &stream, + const uint8_t *src, + const uint8_t *end + ) { if (Http2::StreamState::IDLE == stream.state) { return Http2::ErrorCode::PROTOCOL_ERROR; } @@ -171,7 +206,9 @@ namespace HttpServer return Http2::ErrorCode::FRAME_SIZE_ERROR; } - const Http2::ErrorCode error_code = static_cast(::ntohl(*reinterpret_cast(src) ) ); + const Http2::ErrorCode error_code = static_cast( + ::ntohl(*reinterpret_cast(src) ) + ); if (Http2::ErrorCode::NO_ERROR != error_code) { // DEBUG @@ -180,8 +217,12 @@ namespace HttpServer return Http2::ErrorCode::NO_ERROR; } - static Http2::ErrorCode parseHttp2Settings(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) - { + static Http2::ErrorCode parseHttp2Settings( + Http2::FrameMeta &meta, + Http2::IncStream &stream, + const uint8_t *src, + const uint8_t *end + ) { if (0 != meta.stream_id) { return Http2::ErrorCode::PROTOCOL_ERROR; } @@ -198,7 +239,9 @@ namespace HttpServer while (src != end) { - const Http2::ConnectionSetting setting = static_cast(ntohs(*reinterpret_cast(src) ) ); + const Http2::ConnectionSetting setting = static_cast( + ntohs(*reinterpret_cast(src) ) + ); src += sizeof(uint16_t); @@ -208,68 +251,74 @@ namespace HttpServer switch (setting) { - case Http2::ConnectionSetting::SETTINGS_HEADER_TABLE_SIZE: - settings.header_table_size = value; - break; - - case Http2::ConnectionSetting::SETTINGS_ENABLE_PUSH: - { - if (value > 1) { - return Http2::ErrorCode::PROTOCOL_ERROR; + case Http2::ConnectionSetting::SETTINGS_HEADER_TABLE_SIZE: { + settings.header_table_size = value; + break; } - settings.enable_push = value; + case Http2::ConnectionSetting::SETTINGS_ENABLE_PUSH: { + if (value > 1) { + return Http2::ErrorCode::PROTOCOL_ERROR; + } - break; - } + settings.enable_push = value; - case Http2::ConnectionSetting::SETTINGS_MAX_CONCURRENT_STREAMS: - settings.max_concurrent_streams = value; - break; + break; + } - case Http2::ConnectionSetting::SETTINGS_INITIAL_WINDOW_SIZE: - { - if (value >= uint32_t(1 << 31) ) { - return Http2::ErrorCode::FLOW_CONTROL_ERROR; + case Http2::ConnectionSetting::SETTINGS_MAX_CONCURRENT_STREAMS: { + settings.max_concurrent_streams = value; + break; } - settings.initial_window_size = value; + case Http2::ConnectionSetting::SETTINGS_INITIAL_WINDOW_SIZE: { + if (value >= uint32_t(1) << 31) { + return Http2::ErrorCode::FLOW_CONTROL_ERROR; + } - break; - } + settings.initial_window_size = value; - case Http2::ConnectionSetting::SETTINGS_MAX_FRAME_SIZE: - { - if (value < (1 << 14) || value >= (1 << 24) ) { - return Http2::ErrorCode::PROTOCOL_ERROR; + break; } - settings.max_frame_size = value; + case Http2::ConnectionSetting::SETTINGS_MAX_FRAME_SIZE: { + if (value < (1 << 14) || value >= (1 << 24) ) { + return Http2::ErrorCode::PROTOCOL_ERROR; + } - break; - } + settings.max_frame_size = value; - case Http2::ConnectionSetting::SETTINGS_MAX_HEADER_LIST_SIZE: - settings.max_header_list_size = value; - break; + break; + } - default: - break; + case Http2::ConnectionSetting::SETTINGS_MAX_HEADER_LIST_SIZE: { + settings.max_header_list_size = value; + break; + } + + default: + break; } } return Http2::ErrorCode::NO_ERROR; } - static Http2::ErrorCode parseHttp2GoAway(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) - { + static Http2::ErrorCode parseHttp2GoAway( + Http2::FrameMeta &meta, + Http2::IncStream &stream, + const uint8_t *src, + const uint8_t *end + ) { if (0 != meta.stream_id) { return Http2::ErrorCode::PROTOCOL_ERROR; } stream.state = Http2::StreamState::CLOSED; - const uint32_t last_stream_id = ::ntohl(*reinterpret_cast(src) ); + const uint32_t last_stream_id = ::ntohl( + *reinterpret_cast(src) + ); if (last_stream_id > 0) { @@ -277,7 +326,9 @@ namespace HttpServer src += sizeof(uint32_t); - const Http2::ErrorCode error_code = static_cast(::ntohl(*reinterpret_cast(src) ) ); + const Http2::ErrorCode error_code = static_cast( + ::ntohl(*reinterpret_cast(src) ) + ); if (Http2::ErrorCode::NO_ERROR != error_code) { @@ -286,8 +337,12 @@ namespace HttpServer return Http2::ErrorCode::NO_ERROR; } - static void ping(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, Http2::ConnectionData &conn, const uint64_t pingData) - { + static void ping( + const Socket::Adapter &sock, + const std::chrono::milliseconds &timeout, + Http2::ConnectionData &conn, + const uint64_t pingData + ) { constexpr uint32_t frame_size = sizeof(uint64_t); std::array buf; @@ -295,7 +350,13 @@ namespace HttpServer constexpr uint32_t stream_id = 0; - addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::PING, Http2::FrameFlag::ACK, stream_id); + addr = setHttp2FrameHeader( + addr, + frame_size, + Http2::FrameType::PING, + Http2::FrameFlag::ACK, + stream_id + ); *reinterpret_cast(addr) = pingData; @@ -304,8 +365,9 @@ namespace HttpServer sock.nonblock_send(buf.data(), buf.size(), timeout); } - static Http2::ErrorCode parseHttp2Ping(Http2::FrameMeta &meta) - { + static Http2::ErrorCode parseHttp2Ping( + Http2::FrameMeta &meta + ) { if (0 != meta.stream_id) { return Http2::ErrorCode::PROTOCOL_ERROR; } @@ -317,8 +379,12 @@ namespace HttpServer return Http2::ErrorCode::NO_ERROR; } - static Http2::ErrorCode parseHttp2WindowUpdate(Http2::FrameMeta &meta, Http2::IncStream &stream, const uint8_t *src, const uint8_t *end) - { + static Http2::ErrorCode parseHttp2WindowUpdate( + Http2::FrameMeta &meta, + Http2::IncStream &stream, + const uint8_t *src, + const uint8_t *end + ) { if (Http2::StreamState::RESERVED == stream.state) { return Http2::ErrorCode::PROTOCOL_ERROR; } @@ -330,12 +396,14 @@ namespace HttpServer return Http2::ErrorCode::FRAME_SIZE_ERROR; } - const uint32_t window_size_increment = ::ntohl(*reinterpret_cast(src) ); + const uint32_t window_size_increment = ::ntohl( + *reinterpret_cast(src) + ); if (0 == window_size_increment) { return Http2::ErrorCode::PROTOCOL_ERROR; } - else if (window_size_increment >= uint32_t(1 << 31) ) { + else if (window_size_increment >= uint32_t(1) << 31) { return Http2::ErrorCode::FLOW_CONTROL_ERROR; } @@ -349,25 +417,42 @@ namespace HttpServer return Http2::ErrorCode::NO_ERROR; } - static void rstStream(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, Http2::IncStream &stream, const Http2::ErrorCode errorCode) - { + static void rstStream( + const Socket::Adapter &sock, + const std::chrono::milliseconds &timeout, + Http2::IncStream &stream, + const Http2::ErrorCode errorCode + ) { constexpr uint32_t frame_size = sizeof(uint32_t); std::array buf; uint8_t *addr = buf.data(); - addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::RST_STREAM, Http2::FrameFlag::EMPTY, stream.stream_id); + addr = setHttp2FrameHeader( + addr, + frame_size, + Http2::FrameType::RST_STREAM, + Http2::FrameFlag::EMPTY, + stream.stream_id + ); - *reinterpret_cast(addr) = ::htonl(static_cast(errorCode) ); + *reinterpret_cast(addr) = ::htonl( + static_cast(errorCode) + ); const std::unique_lock lock(stream.conn.sync.mtx); sock.nonblock_send(buf.data(), buf.size(), timeout); } - static void sendSettings(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, Http2::ConnectionData &conn, const uint8_t *src, const uint8_t *end) - { - const uint32_t frame_size = end - src; + static void sendSettings( + const Socket::Adapter &sock, + const std::chrono::milliseconds &timeout, + Http2::ConnectionData &conn, + const uint8_t *src, + const uint8_t *end + ) { + const uint32_t frame_size = uint32_t(end - src); std::vector buf(Http2::FRAME_HEADER_SIZE + frame_size); @@ -375,7 +460,13 @@ namespace HttpServer constexpr uint32_t stream_id = 0; - addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::SETTINGS, Http2::FrameFlag::EMPTY, stream_id); + addr = setHttp2FrameHeader( + addr, + frame_size, + Http2::FrameType::SETTINGS, + Http2::FrameFlag::EMPTY, + stream_id + ); std::copy(src, end, addr); @@ -384,31 +475,51 @@ namespace HttpServer sock.nonblock_send(buf.data(), buf.size(), timeout); } - static void goAway(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, Http2::ConnectionData &conn, const uint32_t lastStreamId, const Http2::ErrorCode errorCode) - { + static void goAway( + const Socket::Adapter &sock, + const std::chrono::milliseconds &timeout, + Http2::ConnectionData &conn, + const uint32_t lastStreamId, + const Http2::ErrorCode errorCode + ) { constexpr uint32_t frame_size = sizeof(uint32_t) * 2; std::array buf; uint8_t *addr = buf.data(); - addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::RST_STREAM, Http2::FrameFlag::EMPTY, 0); + addr = setHttp2FrameHeader( + addr, + frame_size, + Http2::FrameType::RST_STREAM, + Http2::FrameFlag::EMPTY, + 0 + ); - *reinterpret_cast(addr) = ::htonl(static_cast(lastStreamId) ); - *reinterpret_cast(addr + sizeof(uint32_t) ) = ::htonl(static_cast(errorCode) ); + *reinterpret_cast(addr) = ::htonl(lastStreamId); + + *reinterpret_cast(addr + sizeof(uint32_t) ) = ::htonl( + static_cast(errorCode) + ); const std::unique_lock lock(conn.sync.mtx); sock.nonblock_send(buf.data(), buf.size(), timeout); } - static bool getClientPreface(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout) - { + static bool getClientPreface( + const Socket::Adapter &sock, + const std::chrono::milliseconds &timeout + ) { std::array buf; - const long read_size = sock.nonblock_recv(buf.data(), buf.size(), timeout); + const long read_size = sock.nonblock_recv( + buf.data(), + buf.size(), + timeout + ); - if (read_size != buf.size() ) { + if (buf.size() != read_size) { return false; } @@ -426,8 +537,12 @@ namespace HttpServer return 0 == compare; } - static void sendEmptySettings(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, Http2::ConnectionData &conn, const Http2::FrameFlag flags) - { + static void sendEmptySettings( + const Socket::Adapter &sock, + const std::chrono::milliseconds &timeout, + Http2::ConnectionData &conn, + const Http2::FrameFlag flags + ) { constexpr uint32_t frame_size = 0; std::array buf; @@ -435,32 +550,52 @@ namespace HttpServer constexpr uint32_t stream_id = 0; - addr = setHttp2FrameHeader(addr, frame_size, Http2::FrameType::SETTINGS, flags, stream_id); + addr = setHttp2FrameHeader( + addr, + frame_size, + Http2::FrameType::SETTINGS, + flags, + stream_id + ); const std::unique_lock lock(conn.sync.mtx); sock.nonblock_send(buf.data(), buf.size(), timeout); } - static bool getNextHttp2FrameMeta(const Socket::Adapter &sock, const std::chrono::milliseconds &timeout, std::vector &buf, Http2::FrameMeta &meta, long &read_size) - { - if (read_size <= static_cast(meta.length + Http2::FRAME_HEADER_SIZE) ) - { - if (read_size == static_cast(meta.length + Http2::FRAME_HEADER_SIZE) ) { + static bool getNextHttp2FrameMeta( + const Socket::Adapter &sock, + const std::chrono::milliseconds &timeout, + std::vector &buf, + Http2::FrameMeta &meta, + long &read_size + ) { + const long length = long( + meta.length + Http2::FRAME_HEADER_SIZE + ); + + if (read_size <= length) { + if (read_size == length) { read_size = 0; } - read_size = sock.nonblock_recv(buf.data() + read_size, buf.size() - read_size, timeout); + read_size = sock.nonblock_recv( + buf.data() + read_size, + buf.size() - size_t(read_size), + timeout + ); - if (read_size < static_cast(Http2::FRAME_HEADER_SIZE) ) { + if (read_size < long(Http2::FRAME_HEADER_SIZE) ) { return false; } - } - else - { - std::copy(buf.cbegin() + meta.length + Http2::FRAME_HEADER_SIZE, buf.cbegin() + read_size, buf.begin() ); + } else { + std::copy( + buf.cbegin() + length, + buf.cbegin() + read_size, + buf.begin() + ); - read_size -= static_cast(meta.length + Http2::FRAME_HEADER_SIZE); + read_size -= length; } const uint8_t *addr = reinterpret_cast(buf.data() ); @@ -481,11 +616,24 @@ namespace HttpServer Http2::ConnectionData conn; - sendEmptySettings(this->sock, req.timeout, conn, Http2::FrameFlag::EMPTY); + sendEmptySettings( + this->sock, + req.timeout, + conn, + Http2::FrameFlag::EMPTY + ); if (getClientPreface(this->sock, req.timeout) == false) { constexpr uint32_t last_stream_id = 0; - goAway(this->sock, req.timeout, conn, last_stream_id, Http2::ErrorCode::PROTOCOL_ERROR); + + goAway( + this->sock, + req.timeout, + conn, + last_stream_id, + Http2::ErrorCode::PROTOCOL_ERROR + ); + return this; } @@ -512,7 +660,10 @@ namespace HttpServer break; } - const uint8_t *addr = reinterpret_cast(buf.data() ) + Http2::FRAME_HEADER_SIZE; + const uint8_t *addr = reinterpret_cast( + buf.data() + ) + Http2::FRAME_HEADER_SIZE; + const uint8_t *end = addr + meta.length; if (meta.stream_id > last_stream_id) { @@ -544,16 +695,17 @@ namespace HttpServer { DataVariant::DataReceiver *dr = reinterpret_cast(stream.reserved); - if (static_cast(stream.window_size_inc - conn.server_settings.max_frame_size) <= 0) + if (stream.window_size_inc - long(conn.server_settings.max_frame_size) <= 0) { - size_t update_size = conn.server_settings.initial_window_size + (dr->full_size - dr->recv_total) - stream.window_size_inc; + size_t update_size = conn.server_settings.initial_window_size + + (dr->full_size - dr->recv_total) - size_t(stream.window_size_inc); if (update_size > Http2::MAX_WINDOW_UPDATE) { update_size = Http2::MAX_WINDOW_UPDATE; } - sendWindowUpdate(this->sock, req.timeout, stream, static_cast(update_size) ); - sendWindowUpdate(this->sock, req.timeout, primary, static_cast(update_size) ); + sendWindowUpdate(this->sock, req.timeout, stream, uint32_t(update_size) ); + sendWindowUpdate(this->sock, req.timeout, primary, uint32_t(update_size) ); stream.window_size_inc += update_size; } @@ -593,7 +745,7 @@ namespace HttpServer { result = parseHttp2Settings(meta, stream, addr, end); - if (Http2::ErrorCode::NO_ERROR == result && false == (meta.flags & Http2::FrameFlag::ACK) ) + if (Http2::ErrorCode::NO_ERROR == result && (meta.flags & Http2::FrameFlag::ACK) == false) { conn.decoding_dynamic_table.changeHeaderTableSize(conn.client_settings.header_table_size); conn.decoding_dynamic_table.changeMaxHeaderListSize(conn.client_settings.max_header_list_size); @@ -612,7 +764,7 @@ namespace HttpServer { result = parseHttp2Ping(meta); - if (Http2::ErrorCode::NO_ERROR == result && false == (meta.flags & Http2::FrameFlag::ACK) ) + if (Http2::ErrorCode::NO_ERROR == result && (meta.flags & Http2::FrameFlag::ACK) == false) { const uint64_t ping_data = *reinterpret_cast(addr); ping(this->sock, req.timeout, conn, ping_data); @@ -668,7 +820,13 @@ namespace HttpServer conn.sync.event.wait(); } - goAway(this->sock, req.timeout, conn, last_stream_id, Http2::ErrorCode::NO_ERROR); + goAway( + this->sock, + req.timeout, + conn, + last_stream_id, + Http2::ErrorCode::NO_ERROR + ); for (auto &pair : streams) { destroyDataReceiver(pair.second.reserved); diff --git a/src/server/protocol/ServerHttp2.h b/src/server/protocol/ServerHttp2.h index 6910788..7871d3e 100644 --- a/src/server/protocol/ServerHttp2.h +++ b/src/server/protocol/ServerHttp2.h @@ -13,7 +13,12 @@ namespace HttpServer SocketsQueue &sockets; public: - ServerHttp2(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, SocketsQueue &sockets) noexcept; + ServerHttp2( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls, + SocketsQueue &sockets + ) noexcept; virtual ServerProtocol *process() override; virtual void close() override; diff --git a/src/server/protocol/ServerHttp2Protocol.cpp b/src/server/protocol/ServerHttp2Protocol.cpp index df18c00..fd4ed10 100644 --- a/src/server/protocol/ServerHttp2Protocol.cpp +++ b/src/server/protocol/ServerHttp2Protocol.cpp @@ -7,7 +7,12 @@ namespace HttpServer { - ServerHttp2Protocol::ServerHttp2Protocol(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, Http2::IncStream *stream) noexcept + ServerHttp2Protocol::ServerHttp2Protocol( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls, + Http2::IncStream *stream + ) noexcept : ServerProtocol(sock, settings, controls), stream(stream) { @@ -15,26 +20,33 @@ namespace HttpServer uint8_t ServerHttp2Protocol::getPaddingSize(const size_t dataSize) { - if (0 == dataSize) - { + if (0 == dataSize) { return 0; } std::random_device rd; + std::uniform_int_distribution dist; - uint8_t padding = rd(); + uint8_t padding = dist(rd); - while (dataSize <= padding) - { + while (dataSize <= padding) { padding /= 2; } return padding; } - bool ServerHttp2Protocol::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const - { - headers.emplace(headers.begin(), ":status", std::to_string(static_cast(status) ) ); + bool ServerHttp2Protocol::sendHeaders( + const Http::StatusCode status, + std::vector > &headers, + const std::chrono::milliseconds &timeout, + const bool endStream + ) const { + headers.emplace( + headers.begin(), + ":status", + std::to_string(static_cast(status)) + ); std::vector buf; buf.reserve(4096); @@ -42,24 +54,34 @@ namespace HttpServer HPack::pack(buf, headers, this->stream->conn.encoding_dynamic_table); - const uint32_t frame_size = buf.size() - Http2::FRAME_HEADER_SIZE; + const uint32_t frame_size = uint32_t( + buf.size() - Http2::FRAME_HEADER_SIZE + ); Http2::FrameFlag flags = Http2::FrameFlag::END_HEADERS; - if (endStream) - { + if (endStream) { flags |= Http2::FrameFlag::END_STREAM; } - 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->conn.sync.mtx); - return this->sock.nonblock_send(buf.data(), buf.size(), timeout) > 0; // >= 0; + return this->sock.nonblock_send(buf.data(), buf.size(), timeout) > 0; } - long ServerHttp2Protocol::sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const - { + long ServerHttp2Protocol::sendData( + const void *src, + size_t size, + const std::chrono::milliseconds &timeout, + DataTransfer *dt + ) const { const uint8_t *data = reinterpret_cast(src); const Http2::ConnectionSettings &setting = this->stream->conn.client_settings; @@ -72,15 +94,15 @@ namespace HttpServer while (size != 0) { // TODO: test with data_size == 1 (padding length == 0) - size_t data_size = setting.max_frame_size < size ? setting.max_frame_size : size; + size_t data_size = setting.max_frame_size < size + ? setting.max_frame_size + : 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 > setting.max_frame_size) - { + if (padding_size) { + if (data_size + padding_size > setting.max_frame_size) { data_size = setting.max_frame_size - padding_size; } } @@ -93,27 +115,24 @@ namespace HttpServer { size_t update_size = (dt->full_size - dt->send_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; } - sendWindowUpdate(this->sock, rp, static_cast(update_size) ); + sendWindowUpdate(this->sock, rp, uint32_t(update_size) ); this->stream->window_size_out += update_size; }*/ Http2::FrameFlag flags = Http2::FrameFlag::EMPTY; - if (dt->send_total + data_size >= dt->full_size) - { + if (dt->send_total + data_size >= dt->full_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; @@ -121,23 +140,38 @@ namespace HttpServer ++cur; } - this->stream->setHttp2FrameHeader(buf.data(), frame_size, Http2::FrameType::DATA, flags); - - std::copy(data, data + data_size, buf.begin() + cur); - - if (padding) - { - std::fill(buf.end() - padding, buf.end(), 0); + this->stream->setHttp2FrameHeader( + buf.data(), + static_cast(frame_size), + Http2::FrameType::DATA, + flags + ); + + std::copy( + data, + data + data_size, + buf.begin() + long(cur) + ); + + if (padding) { + 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(); - if (sended <= 0) - { + if (sended <= 0) { send_size = sended; break; } @@ -153,8 +187,11 @@ namespace HttpServer return send_size; } - bool ServerHttp2Protocol::packRequestParameters(std::vector &buf, const struct Request &req, const std::string &rootDir) const - { + bool ServerHttp2Protocol::packRequestParameters( + std::vector &buf, + const struct Request &req, + const std::string &rootDir + ) const { Utils::packNumber(buf, static_cast(Transfer::ProtocolVariant::HTTP_2) ); Utils::packString(buf, rootDir); Utils::packString(buf, req.host); @@ -177,8 +214,13 @@ namespace HttpServer return true; } - void ServerHttp2Protocol::unpackResponseParameters(struct Request &req, const void *src) const - { - Utils::unpackContainer(req.outgoing_headers, reinterpret_cast(src) ); + void ServerHttp2Protocol::unpackResponseParameters( + struct Request &req, + const void *src + ) const { + Utils::unpackContainer( + req.outgoing_headers, + reinterpret_cast(src) + ); } -}; +} diff --git a/src/server/protocol/ServerHttp2Protocol.h b/src/server/protocol/ServerHttp2Protocol.h index 7c84ba4..99adc42 100644 --- a/src/server/protocol/ServerHttp2Protocol.h +++ b/src/server/protocol/ServerHttp2Protocol.h @@ -14,12 +14,35 @@ namespace HttpServer static uint8_t getPaddingSize(const size_t dataSize); public: - ServerHttp2Protocol(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, Http2::IncStream *stream) noexcept; + ServerHttp2Protocol( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls, Http2::IncStream *stream + ) noexcept; - virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const override; - virtual long sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const override; + virtual bool sendHeaders( + const Http::StatusCode status, + std::vector > &headers, + const std::chrono::milliseconds &timeout, + const bool endStream + ) const override; - virtual bool packRequestParameters(std::vector &buf, const struct Request &rp, const std::string &rootDir) const override; - virtual void unpackResponseParameters(struct Request &rp, const void *src) const override; + virtual long sendData( + const void *src, + size_t size, + const std::chrono::milliseconds &timeout, + DataTransfer *dt + ) const override; + + virtual bool packRequestParameters( + std::vector &buf, + const struct Request &rp, + const std::string &rootDir + ) const override; + + virtual void unpackResponseParameters( + struct Request &rp, + const void *src + ) const override; }; -}; +} diff --git a/src/server/protocol/ServerHttp2Stream.cpp b/src/server/protocol/ServerHttp2Stream.cpp index 8a20c8a..346e0f1 100644 --- a/src/server/protocol/ServerHttp2Stream.cpp +++ b/src/server/protocol/ServerHttp2Stream.cpp @@ -5,14 +5,18 @@ namespace HttpServer { - ServerHttp2Stream::ServerHttp2Stream(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, Http2::IncStream *stream) noexcept + ServerHttp2Stream::ServerHttp2Stream( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls, + Http2::IncStream *stream + ) noexcept : ServerHttp2Protocol(sock, settings, controls, stream) { } - void ServerHttp2Stream::close() - { + void ServerHttp2Stream::close() { this->stream->close(); } @@ -31,19 +35,20 @@ namespace HttpServer auto const it_scheme = headers.find(":scheme"); - if (headers.cend() == it_scheme) - { + if (headers.cend() == it_scheme) { return this; } const std::string &scheme = it_scheme->second; - const int default_port = (scheme == "https") ? 443 : (scheme == "http") ? 80 : 0; + const int default_port = (scheme == "https") + ? 443 + : (scheme == "http") + ? 80 : 0; auto const it_host = headers.find(":authority"); - if (headers.cend() == it_host) - { + if (headers.cend() == it_host) { return this; } @@ -56,20 +61,24 @@ namespace HttpServer req.host = host_header.substr(0, delimiter); // Получить номер порта - const int port = (std::string::npos != delimiter) ? std::strtol(host_header.substr(delimiter + 1).c_str(), nullptr, 10) : default_port; + const int port = std::string::npos != delimiter + ? std::atoi(host_header.substr(delimiter + 1).c_str()) + : default_port; const ServerApplicationSettings *app_sets = this->settings.apps_tree.find(req.host); // Если приложение найдено - if (nullptr == app_sets || (app_sets->ports.cend() == app_sets->ports.find(port) && app_sets->tls_ports.cend() == app_sets->tls_ports.find(port) ) ) - { + if (nullptr == app_sets || ( + app_sets->ports.cend() == app_sets->ports.find(port) && + app_sets->tls_ports.cend() == app_sets->tls_ports.find(port) + ) + ) { return this; } auto const it_method = headers.find(":method"); - if (headers.cend() == it_method) - { + if (headers.cend() == it_method) { return this; } @@ -77,8 +86,7 @@ namespace HttpServer auto const it_path = headers.find(":path"); - if (headers.cend() == it_path) - { + if (headers.cend() == it_path) { return this; } @@ -88,23 +96,25 @@ namespace HttpServer this->runApplication(req, *app_sets); - for (auto const &it : req.incoming_files) - { + for (auto const &it : req.incoming_files) { std::remove(it.second.getTmpName().c_str() ); } - if (EXIT_SUCCESS == req.app_exit_code) - { + if (EXIT_SUCCESS == req.app_exit_code) { // Http2::OutStream out(*stream); // auto tmp = req.protocol_data; // req.protocol_data = &out; - Sendfile::xSendfile(std::ref(*this), req, this->settings.mimes_types); + Sendfile::xSendfile( + std::ref(*this), + req, + this->settings.mimes_types + ); // req.protocol_data = tmp; } return this; } -}; +} diff --git a/src/server/protocol/ServerHttp2Stream.h b/src/server/protocol/ServerHttp2Stream.h index a4c18c1..1181983 100644 --- a/src/server/protocol/ServerHttp2Stream.h +++ b/src/server/protocol/ServerHttp2Stream.h @@ -8,9 +8,14 @@ namespace HttpServer class ServerHttp2Stream : public ServerHttp2Protocol { public: - ServerHttp2Stream(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls, Http2::IncStream *stream) noexcept; + ServerHttp2Stream( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls, + Http2::IncStream *stream + ) noexcept; virtual ServerProtocol *process() override; virtual void close() override; }; -}; +} diff --git a/src/server/protocol/ServerProtocol.cpp b/src/server/protocol/ServerProtocol.cpp index 9adc151..42628eb 100644 --- a/src/server/protocol/ServerProtocol.cpp +++ b/src/server/protocol/ServerProtocol.cpp @@ -4,7 +4,11 @@ namespace HttpServer { - ServerProtocol::ServerProtocol(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls) noexcept + ServerProtocol::ServerProtocol( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls + ) noexcept : sock(sock), settings(settings), controls(controls) { @@ -16,12 +20,15 @@ namespace HttpServer } - DataVariant::DataReceiver *ServerProtocol::createDataReceiver(const Transfer::request_data *rd, const std::unordered_map &variants) - { + DataVariant::DataReceiver * + ServerProtocol::createDataReceiver( + const Transfer::request_data *rd, + const std::unordered_map &variants + ) { auto const it = rd->incoming_headers.find("content-type"); - if (rd->incoming_headers.cend() == it) - { + if (rd->incoming_headers.cend() == it) { return nullptr; } @@ -36,45 +43,64 @@ namespace HttpServer size_t delimiter = header_value.find(';'); // Если есть дополнительные параметры - извлекаем их - if (std::string::npos != delimiter) - { + if (std::string::npos != delimiter) { data_variant_name = header_value.substr(0, delimiter); Utils::trim(data_variant_name); - for (size_t str_param_cur = delimiter + 1, str_param_end = 0; std::string::npos != str_param_end; str_param_cur = str_param_end + 1) - { + for ( + size_t str_param_cur = delimiter + 1, str_param_end = 0; + std::string::npos != str_param_end; + str_param_cur = str_param_end + 1 + ) { str_param_end = header_value.find(';', str_param_cur); delimiter = header_value.find('=', str_param_cur); - if (delimiter >= str_param_end) - { - std::string param_name = header_value.substr(str_param_cur, std::string::npos != str_param_end ? str_param_end - str_param_cur : std::string::npos); + if (delimiter >= str_param_end) { + std::string param_name = header_value.substr( + str_param_cur, + std::string::npos != str_param_end + ? str_param_end - str_param_cur + : std::string::npos + ); + Utils::trim(param_name); - content_params.emplace(std::move(param_name), std::string() ); - } - else - { - std::string param_name = header_value.substr(str_param_cur, delimiter - str_param_cur); + + content_params.emplace( + std::move(param_name), + std::string() + ); + } else { + std::string param_name = header_value.substr( + str_param_cur, + delimiter - str_param_cur + ); + Utils::trim(param_name); ++delimiter; - std::string param_value = header_value.substr(delimiter, std::string::npos != str_param_end ? str_param_end - delimiter : std::string::npos); + std::string param_value = header_value.substr( + delimiter, + std::string::npos != str_param_end + ? str_param_end - delimiter + : std::string::npos + ); + Utils::trim(param_value); - content_params.emplace(std::move(param_name), std::move(param_value) ); + content_params.emplace( + std::move(param_name), + std::move(param_value) + ); } } - } - else - { + } else { data_variant_name = header_value; } auto const variant = variants.find(data_variant_name); - if (variants.cend() == variant) - { + if (variants.cend() == variant) { return nullptr; } @@ -84,9 +110,12 @@ namespace HttpServer auto const it_len = rd->incoming_headers.find("content-length"); - if (rd->incoming_headers.cend() != it_len) - { - data_length = std::strtoull(it_len->second.c_str(), nullptr, 10); + if (rd->incoming_headers.cend() != it_len) { + data_length = std::strtoull( + it_len->second.c_str(), + nullptr, + 10 + ); } return new DataVariant::DataReceiver { @@ -101,12 +130,10 @@ namespace HttpServer { DataVariant::DataReceiver *dr = reinterpret_cast(src); - if (dr) - { + if (dr) { dr->data_variant->destroyStateStruct(dr->ss); - if (dr->reserved) - { + if (dr->reserved) { delete reinterpret_cast(dr->reserved); dr->reserved = nullptr; } @@ -115,13 +142,14 @@ namespace HttpServer delete dr; } - void ServerProtocol::runApplication(struct Request &req, const ServerApplicationSettings &appSets) const - { + void ServerProtocol::runApplication( + struct Request &req, + const ServerApplicationSettings &appSets + ) const { std::vector buf; buf.reserve(4096); - if (false == this->packRequestParameters(buf, req, appSets.root_dir) ) - { + if (this->packRequestParameters(buf, req, appSets.root_dir) == false) { return; } @@ -135,32 +163,27 @@ namespace HttpServer nullptr, 0 }; - try - { + try { // Launch application req.app_exit_code = appSets.application_call(&request, &response); } - catch (std::exception &exc) - { + catch (std::exception &exc) { // TODO: exception output } if (response.response_data && response.data_size) { - if (EXIT_SUCCESS == req.app_exit_code) - { + if (EXIT_SUCCESS == req.app_exit_code) { this->unpackResponseParameters(req, response.response_data); } // Clear outgoing data of application - try - { + try { appSets.application_clear(response.response_data, response.data_size); } - catch (std::exception &exc) - { + catch (std::exception &exc) { // TODO: exception output } } } -}; +} diff --git a/src/server/protocol/ServerProtocol.h b/src/server/protocol/ServerProtocol.h index 91f5b3a..e53fea6 100644 --- a/src/server/protocol/ServerProtocol.h +++ b/src/server/protocol/ServerProtocol.h @@ -16,24 +16,56 @@ namespace HttpServer ServerControls &controls; public: - ServerProtocol(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls) noexcept; + ServerProtocol( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls + ) noexcept; + ServerProtocol(const ServerProtocol &prot) noexcept; virtual ~ServerProtocol() noexcept = default; - static DataVariant::DataReceiver *createDataReceiver(const Transfer::request_data *rd, const std::unordered_map &variants); + static DataVariant::DataReceiver * + createDataReceiver( + const Transfer::request_data *rd, + const std::unordered_map &variants + ); + static void destroyDataReceiver(void *src); protected: - void runApplication(struct Request &req, const ServerApplicationSettings &appSets) const; + void runApplication( + struct Request &req, + const ServerApplicationSettings &appSets + ) const; public: - 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, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) 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, + size_t size, + const std::chrono::milliseconds &timeout, + DataTransfer *dt + ) const = 0; + + virtual bool packRequestParameters( + std::vector &buf, + const struct Request &req, + const std::string &rootDir + ) const = 0; - virtual bool packRequestParameters(std::vector &buf, const struct Request &req, const std::string &rootDir) const = 0; - virtual void unpackResponseParameters(struct Request &req, const void *src) const = 0; + virtual void unpackResponseParameters( + struct Request &req, + const void *src + ) const = 0; virtual ServerProtocol *process() = 0; virtual void close() = 0; }; -}; +} diff --git a/src/server/protocol/ServerWebSocket.cpp b/src/server/protocol/ServerWebSocket.cpp index 5c03f1a..2951e73 100644 --- a/src/server/protocol/ServerWebSocket.cpp +++ b/src/server/protocol/ServerWebSocket.cpp @@ -3,7 +3,11 @@ namespace HttpServer { - ServerWebSocket::ServerWebSocket(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls) noexcept + ServerWebSocket::ServerWebSocket( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls + ) noexcept : ServerProtocol(sock, settings, controls) { @@ -15,33 +19,42 @@ namespace HttpServer } - bool ServerWebSocket::sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const - { + bool ServerWebSocket::sendHeaders( + const Http::StatusCode status, + std::vector > &headers, + const std::chrono::milliseconds &timeout, + const bool endStream + ) const { return false; } - long ServerWebSocket::sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const - { + long ServerWebSocket::sendData( + const void *src, + size_t size, + const std::chrono::milliseconds &timeout, + DataTransfer *dt + ) const { return 0; } - bool ServerWebSocket::packRequestParameters(std::vector &buf, const struct Request &rp, const std::string &rootDir) const - { + bool ServerWebSocket::packRequestParameters( + std::vector &buf, + const struct Request &rp, + const std::string &rootDir + ) const { return false; } - void ServerWebSocket::unpackResponseParameters(struct Request &req, const void *src) const - { + void ServerWebSocket::unpackResponseParameters( + struct Request &req, + const void *src + ) const { } - ServerProtocol *ServerWebSocket::process() - { + ServerProtocol *ServerWebSocket::process() { return this; } - void ServerWebSocket::close() - { - - } -}; + void ServerWebSocket::close() {} +} diff --git a/src/server/protocol/ServerWebSocket.h b/src/server/protocol/ServerWebSocket.h index 094293f..5745f7e 100644 --- a/src/server/protocol/ServerWebSocket.h +++ b/src/server/protocol/ServerWebSocket.h @@ -7,16 +7,40 @@ namespace HttpServer class ServerWebSocket : public ServerProtocol { public: - ServerWebSocket(Socket::Adapter &sock, const ServerSettings &settings, ServerControls &controls) noexcept; + ServerWebSocket( + Socket::Adapter &sock, + const ServerSettings &settings, + ServerControls &controls + ) noexcept; + ServerWebSocket(const ServerProtocol &prot) noexcept; - virtual bool sendHeaders(const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream) const override; - virtual long sendData(const void *src, size_t size, const std::chrono::milliseconds &timeout, DataTransfer *dt) const override; + virtual bool sendHeaders( + const Http::StatusCode status, + std::vector > &headers, + const std::chrono::milliseconds &timeout, + const bool endStream + ) const override; + + virtual long sendData( + const void *src, + size_t size, + const std::chrono::milliseconds &timeout, + DataTransfer *dt + ) const override; + + virtual bool packRequestParameters( + std::vector &buf, + const struct Request &rp, + const std::string &rootDir + ) const override; - virtual bool packRequestParameters(std::vector &buf, const struct Request &rp, const std::string &rootDir) const override; - virtual void unpackResponseParameters(struct Request &req, const void *src) const override; + virtual void unpackResponseParameters( + struct Request &req, + const void *src + ) const override; virtual ServerProtocol *process() override; virtual void close() override; }; -}; +} diff --git a/src/server/protocol/extensions/Sendfile.cpp b/src/server/protocol/extensions/Sendfile.cpp index 9c557ba..1758515 100644 --- a/src/server/protocol/extensions/Sendfile.cpp +++ b/src/server/protocol/extensions/Sendfile.cpp @@ -6,15 +6,21 @@ namespace HttpServer { - static std::string getMimeTypeByFileName(const std::string &fileName, const std::unordered_map &mimesTypes) noexcept - { + static std::string getMimeTypeByFileName( + const std::string &fileName, + const std::unordered_map &mimesTypes + ) noexcept { const size_t ext_pos = fileName.rfind('.'); - const std::string file_ext = Utils::getLowerString(std::string::npos != ext_pos ? fileName.substr(ext_pos + 1) : std::string() ); + const std::string file_ext = std::string::npos != ext_pos + ? Utils::getLowerString(fileName.substr(ext_pos + 1) ) + : std::string(); auto const it_mime = mimesTypes.find(file_ext); - return mimesTypes.cend() != it_mime ? it_mime->second : std::string("application/octet-stream"); + return mimesTypes.cend() == it_mime + ? std::string("application/octet-stream") + : it_mime->second; } static std::vector > getRanges( @@ -23,15 +29,17 @@ namespace HttpServer const size_t fileSize, std::string *resultRangeHeader, size_t *contentLength - ) noexcept - { + ) noexcept { std::vector > ranges; *contentLength = 0; size_t delimiter = posSymEqual; // rangeHeader.find('='); - const std::string range_unit_name(rangeHeader.cbegin(), rangeHeader.cbegin() + delimiter); + const std::string range_unit_name( + rangeHeader.cbegin(), + rangeHeader.cbegin() + delimiter + ); static const std::unordered_map ranges_units { { "bytes", 1 } @@ -39,8 +47,7 @@ namespace HttpServer auto const it_unit = ranges_units.find(range_unit_name); - if (ranges_units.cend() == it_unit) - { + if (ranges_units.cend() == it_unit) { return ranges; } @@ -49,30 +56,41 @@ namespace HttpServer for (size_t str_pos; std::string::npos != delimiter; ) { str_pos = delimiter + 1; - delimiter = rangeHeader.find(',', str_pos); const size_t range_pos = rangeHeader.find('-', str_pos); if (range_pos < delimiter) { - const std::string range_begin_str(rangeHeader.cbegin() + str_pos, rangeHeader.cbegin() + range_pos); - const std::string range_end_str(rangeHeader.cbegin() + range_pos + 1, std::string::npos == delimiter ? rangeHeader.cend() : rangeHeader.cbegin() + delimiter); - - if (false == range_begin_str.empty() ) + const std::string range_begin_str( + rangeHeader.cbegin() + str_pos, + rangeHeader.cbegin() + range_pos + ); + + const std::string range_end_str( + rangeHeader.cbegin() + range_pos + 1, + std::string::npos == delimiter + ? rangeHeader.cend() + : rangeHeader.cbegin() + delimiter + ); + + if (range_begin_str.empty() == false) { - const size_t range_begin = std::strtoull(range_begin_str.c_str(), nullptr, 10) * range_unit; + const size_t range_begin = std::strtoull( + range_begin_str.c_str(), nullptr, 10 + ) * range_unit; if (range_begin < fileSize) { - if (false == range_end_str.empty() ) + if (range_end_str.empty() == false) { - size_t range_end = std::strtoull(range_end_str.c_str(), nullptr, 10) * range_unit; + size_t range_end = std::strtoull( + range_end_str.c_str(), nullptr, 10 + ) * range_unit; if (range_end >= range_begin) { - if (range_end > fileSize) - { + if (range_end > fileSize) { range_end = fileSize; } @@ -93,15 +111,21 @@ namespace HttpServer *resultRangeHeader += std::to_string(range_begin) + '-' + std::to_string(fileSize - 1) + ','; - ranges.emplace_back(std::tuple {range_begin, length}); + ranges.emplace_back(std::tuple { + range_begin, length + }); } } } - else if (false == range_end_str.empty() ) // if range_begin_str empty + else if (range_end_str.empty() == false) // if range_begin_str empty { - size_t range_end = std::strtoull(range_end_str.c_str(), nullptr, 10) * range_unit; + size_t range_end = std::strtoull( + range_end_str.c_str(), nullptr, 10 + ) * range_unit; - const size_t length = range_end < fileSize ? fileSize - range_end : fileSize; + const size_t length = range_end < fileSize + ? fileSize - range_end + : fileSize; const size_t range_begin = fileSize - length; @@ -111,15 +135,15 @@ namespace HttpServer *resultRangeHeader += std::to_string(range_begin) + '-' + std::to_string(range_end) + ','; - ranges.emplace_back(std::tuple {range_begin, length}); + ranges.emplace_back(std::tuple { + range_begin, length + }); } } } - if (false == ranges.empty() ) - { + if (ranges.empty() == false) { (*resultRangeHeader).back() = '/'; - *resultRangeHeader = "bytes " + *resultRangeHeader + std::to_string(fileSize); } @@ -136,13 +160,15 @@ namespace HttpServer const std::string &rangeHeader, std::vector > &additionalHeaders, const bool headersOnly - ) noexcept - { + ) noexcept { const size_t pos_sym_equal = rangeHeader.find('='); - if (std::string::npos == pos_sym_equal) - { - prot.sendHeaders(Http::StatusCode::BAD_REQUEST, additionalHeaders, req.timeout); + if (std::string::npos == pos_sym_equal) { + prot.sendHeaders( + Http::StatusCode::BAD_REQUEST, + additionalHeaders, + req.timeout + ); return 1; } @@ -151,11 +177,20 @@ namespace HttpServer size_t content_length; - const std::vector > ranges = getRanges(rangeHeader, pos_sym_equal, fileSize, &content_range_header, &content_length); - - if (0 == content_length) - { - prot.sendHeaders(Http::StatusCode::REQUESTED_RANGE_NOT_SATISFIABLE, additionalHeaders, req.timeout); + const std::vector > ranges = getRanges( + rangeHeader, + pos_sym_equal, + fileSize, + &content_range_header, + &content_length + ); + + if (0 == content_length) { + prot.sendHeaders( + Http::StatusCode::REQUESTED_RANGE_NOT_SATISFIABLE, + additionalHeaders, + req.timeout + ); return 2; } @@ -163,11 +198,14 @@ namespace HttpServer // Ranges transfer std::ifstream file(fileName, std::ifstream::binary); - if ( ! file) - { + if ( ! file) { file.close(); - prot.sendHeaders(Http::StatusCode::INTERNAL_SERVER_ERROR, additionalHeaders, req.timeout); + prot.sendHeaders( + Http::StatusCode::INTERNAL_SERVER_ERROR, + additionalHeaders, + req.timeout + ); return 3; } @@ -181,10 +219,14 @@ namespace HttpServer additionalHeaders.emplace_back("last-modified", Utils::getDatetimeAsString(fileTime, true) ); // Отправить заголовки (206 Partial Content) - if (false == prot.sendHeaders(Http::StatusCode::PARTIAL_CONTENT, additionalHeaders, req.timeout, headersOnly) ) - { + if (prot.sendHeaders( + Http::StatusCode::PARTIAL_CONTENT, + additionalHeaders, + req.timeout, + headersOnly + ) == false + ) { file.close(); - return 4; } @@ -203,7 +245,11 @@ namespace HttpServer { std::tie(position, length) = range; - buf.resize(length < 512 * 1024 ? length : 512 * 1024); + buf.resize( + length < 512 * 1024 + ? length + : 512 * 1024 + ); file.seekg(position, file.beg); @@ -211,10 +257,8 @@ namespace HttpServer long send_size; - do - { - if (send_size_left < 512 * 1024) - { + do { + if (send_size_left < 512 * 1024) { buf.resize(send_size_left); } @@ -222,7 +266,12 @@ namespace HttpServer auto const read_size = file.gcount(); - send_size = prot.sendData(buf.data(), read_size, req.timeout, &dt); + send_size = prot.sendData( + buf.data(), + read_size, + req.timeout, + &dt + ); send_size_left -= send_size; } @@ -245,8 +294,7 @@ namespace HttpServer const std::unordered_map &mimesTypes, std::vector > &additionalHeaders, const bool headersOnly - ) noexcept - { + ) noexcept { // Get current time in GMT additionalHeaders.emplace_back("date", Utils::getDatetimeAsString() ); @@ -254,9 +302,12 @@ namespace HttpServer size_t file_size; // Получить размер файла и дату последнего изменения - if (false == System::getFileSizeAndTimeGmt(fileName, &file_size, &file_time) ) - { - prot.sendHeaders(Http::StatusCode::NOT_FOUND, additionalHeaders, req.timeout); + if (System::getFileSizeAndTimeGmt(fileName, &file_size, &file_time) == false) { + prot.sendHeaders( + Http::StatusCode::NOT_FOUND, + additionalHeaders, + req.timeout + ); return 1; } @@ -265,13 +316,15 @@ namespace HttpServer auto const it_modified = req.incoming_headers.find("if-modified-since"); // Если найден заголовок проверки изменения файла (проверить, изменялся ли файл) - if (req.incoming_headers.cend() != it_modified) - { + if (req.incoming_headers.cend() != it_modified) { const time_t time_in_request = Utils::rfc822DatetimeToTimestamp(it_modified->second); - if (file_time == time_in_request) - { - prot.sendHeaders(Http::StatusCode::NOT_MODIFIED, additionalHeaders, req.timeout); + if (file_time == time_in_request) { + prot.sendHeaders( + Http::StatusCode::NOT_MODIFIED, + additionalHeaders, + req.timeout + ); return 2; } @@ -280,19 +333,31 @@ namespace HttpServer auto const it_range = req.incoming_headers.find("range"); // Range transfer - if (req.incoming_headers.cend() != it_range) - { - return transferFilePart(prot, req, fileName, mimesTypes, file_time, file_size, it_range->second, additionalHeaders, headersOnly); + if (req.incoming_headers.cend() != it_range) { + return transferFilePart( + prot, + req, + fileName, + mimesTypes, + file_time, + file_size, + it_range->second, + additionalHeaders, + headersOnly + ); } // File transfer std::ifstream file(fileName, std::ifstream::binary); - if ( ! file) - { + if ( ! file) { file.close(); - prot.sendHeaders(Http::StatusCode::INTERNAL_SERVER_ERROR, additionalHeaders, req.timeout); + prot.sendHeaders( + Http::StatusCode::INTERNAL_SERVER_ERROR, + additionalHeaders, + req.timeout + ); return 3; } @@ -305,17 +370,25 @@ namespace HttpServer additionalHeaders.emplace_back("last-modified", Utils::getDatetimeAsString(file_time, true) ); // Отправить заголовки (200 OK) - if (false == prot.sendHeaders(Http::StatusCode::OK, additionalHeaders, req.timeout, headersOnly || 0 == file_size) ) - { + if (prot.sendHeaders( + Http::StatusCode::OK, + additionalHeaders, + req.timeout, + headersOnly || 0 == file_size + ) == false + ) { file.close(); - return 4; } // Отправить файл if (false == headersOnly && file_size) { - std::vector buf(file_size < 512 * 1024 ? file_size : 512 * 1024); + std::vector buf( + file_size < 512 * 1024 + ? file_size + : 512 * 1024 + ); long send_size; @@ -324,10 +397,15 @@ namespace HttpServer 0 }; - do - { + do { file.read(buf.data(), buf.size() ); - send_size = prot.sendData(buf.data(), file.gcount(), req.timeout, &dt); + + send_size = prot.sendData( + buf.data(), + file.gcount(), + req.timeout, + &dt + ); } while (false == file.eof() && false == file.fail() && send_size > 0 && (dt.full_size - dt.send_total) ); } @@ -337,8 +415,7 @@ namespace HttpServer return 0; } - bool Sendfile::isConnectionReuse(const struct Request &req) noexcept - { + bool Sendfile::isConnectionReuse(const struct Request &req) noexcept { return (req.connection_params & ConnectionParams::CONNECTION_REUSE) == ConnectionParams::CONNECTION_REUSE; } @@ -346,30 +423,32 @@ namespace HttpServer const ServerProtocol &prot, struct Request &req, const std::unordered_map &mimesTypes - ) noexcept - { + ) noexcept { auto const it_x_sendfile = req.outgoing_headers.find("x-sendfile"); if (req.outgoing_headers.cend() != it_x_sendfile) { std::vector > additional_headers; - if (Transfer::ProtocolVariant::HTTP_1 == req.protocol_variant) - { - if (isConnectionReuse(req) ) - { + if (Transfer::ProtocolVariant::HTTP_1 == req.protocol_variant) { + if (isConnectionReuse(req) ) { additional_headers.emplace_back("connection", "keep-alive"); additional_headers.emplace_back("keep-alive", "timeout=5; max=" + std::to_string(req.keep_alive_count) ); - } - else - { + } else { additional_headers.emplace_back("connection", "close"); } } const bool headers_only = ("head" == req.method); - transferFile(prot, req, it_x_sendfile->second, mimesTypes, additional_headers, headers_only); + transferFile( + prot, + req, + it_x_sendfile->second, + mimesTypes, + additional_headers, + headers_only + ); } } -}; +} diff --git a/src/server/protocol/extensions/Sendfile.h b/src/server/protocol/extensions/Sendfile.h index eb2823b..23793d0 100644 --- a/src/server/protocol/extensions/Sendfile.h +++ b/src/server/protocol/extensions/Sendfile.h @@ -38,4 +38,4 @@ namespace HttpServer const std::unordered_map &mimesTypes ) 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..118e885 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); @@ -95,7 +104,9 @@ namespace Socket } 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..a1accbd 100644 --- a/src/socket/List.cpp +++ b/src/socket/List.cpp @@ -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,19 +247,25 @@ 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; @@ -250,7 +283,11 @@ namespace Socket ::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); + 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 +300,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 +323,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,21 +340,28 @@ 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; @@ -328,7 +381,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 +406,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..54904d3 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) ); + 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 } @@ -208,9 +237,15 @@ namespace Socket unsigned long value = isNonBlock; 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 +258,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,67 +267,106 @@ 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); + 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 @@ -300,30 +374,38 @@ namespace Socket return ::WSAPoll(&event, 1, 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 += static_cast(send_size); } return static_cast(total); @@ -337,8 +419,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 @@ -350,7 +436,12 @@ 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); + const long send_size = ::send( + socket_handle, + reinterpret_cast(data) + total, + static_cast(length - total), + 0 + ); if (send_size < 0) { return send_size; @@ -370,37 +461,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 += static_cast(send_size); } else { return -1; } } #else - #error "Undefine platform" + #error "Undefined platform" #endif return static_cast(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 +520,7 @@ namespace Socket ::WSAPoll(&event, 1, ~0); #elif POSIX - struct ::pollfd event = { + struct ::pollfd event { this->socket_handle, POLLOUT, 0 @@ -416,7 +528,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/GlobalMutex.cpp b/src/system/GlobalMutex.cpp index 2079b4e..0c72d06 100644 --- a/src/system/GlobalMutex.cpp +++ b/src/system/GlobalMutex.cpp @@ -13,7 +13,8 @@ namespace System { - GlobalMutex::GlobalMutex() noexcept : mtx_desc(nullptr) + GlobalMutex::GlobalMutex() noexcept + : mtx_desc(nullptr) { } @@ -40,22 +41,25 @@ namespace System this->mtx_desc = ::CreateMutex(nullptr, false, mutex_name.c_str() ); - if (nullptr == this->mtx_desc) - { + if (nullptr == this->mtx_desc) { return false; } #elif POSIX - ::sem_t *sem = ::sem_open(mutexName.c_str(), O_CREAT, 0666, 1); - - if (SEM_FAILED == sem) - { + ::sem_t *sem = ::sem_open( + mutexName.c_str(), + O_CREAT, + 0666, + 1 + ); + + if (SEM_FAILED == sem) { return false; } this->mtx_desc = sem; this->mtx_name = mutexName; #else - #error "Undefine platform" + #error "Undefined platform" #endif return true; @@ -79,7 +83,7 @@ namespace System #elif POSIX return 0 == ::sem_unlink(mutexName.c_str() ); #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -101,13 +105,15 @@ namespace System return ret; #elif POSIX - const int ret = ::sem_unlink(this->mtx_name.c_str() ); + const int ret = ::sem_unlink( + this->mtx_name.c_str() + ); - this->close(); + this->close(); - return 0 == ret; + return 0 == ret; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -128,21 +134,22 @@ namespace System this->mtx_desc = ::OpenMutex(SYNCHRONIZE, false, mutex_name.c_str() ); - if (nullptr == this->mtx_desc) - { + if (nullptr == this->mtx_desc) { return false; } #elif POSIX - ::sem_t *sem = ::sem_open(mutexName.c_str(), 0); + ::sem_t *sem = ::sem_open( + mutexName.c_str(), + 0 + ); - if (SEM_FAILED == sem) - { + if (SEM_FAILED == sem) { return false; } this->mtx_desc = sem; #else - #error "Undefine platform" + #error "Undefined platform" #endif this->mtx_name = mutexName; @@ -161,7 +168,7 @@ namespace System ::sem_close(this->mtx_desc); this->mtx_desc = nullptr; #else - #error "Undefine platform" + #error "Undefined platform" #endif this->mtx_name.clear(); @@ -179,7 +186,7 @@ namespace System #elif POSIX return nullptr != this->mtx_desc; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -190,7 +197,7 @@ namespace System #elif POSIX return 0 == ::sem_wait(this->mtx_desc); #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -201,7 +208,7 @@ namespace System #elif POSIX return 0 == ::sem_trywait(this->mtx_desc); #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -212,7 +219,7 @@ namespace System #elif POSIX return 0 == ::sem_post(this->mtx_desc); #else - #error "Undefine platform" + #error "Undefined platform" #endif } -}; +} diff --git a/src/system/GlobalMutex.h b/src/system/GlobalMutex.h index 5250d78..d6bc0b0 100644 --- a/src/system/GlobalMutex.h +++ b/src/system/GlobalMutex.h @@ -19,7 +19,7 @@ namespace System #elif POSIX ::sem_t *mtx_desc; #else - #error "Undefine platform" + #error "Undefined platform" #endif std::string mtx_name; @@ -42,4 +42,4 @@ namespace System bool try_lock() const noexcept; bool unlock() const noexcept; }; -}; +} diff --git a/src/system/Module.cpp b/src/system/Module.cpp index 8cbddb1..a417a59 100644 --- a/src/system/Module.cpp +++ b/src/system/Module.cpp @@ -14,36 +14,38 @@ namespace System { - Module::Module() noexcept : lib_handle(nullptr) + Module::Module() noexcept + : lib_handle(nullptr) { } - Module::Module(const std::string &libPath): lib_handle(nullptr) + Module::Module(const std::string &libPath) + : lib_handle(nullptr) { open(libPath); } - Module::Module(const Module &obj) noexcept : lib_handle(obj.lib_handle) + Module::Module(const Module &obj) noexcept + : lib_handle(obj.lib_handle) { } - Module::Module(Module &&obj) noexcept : lib_handle(obj.lib_handle) + Module::Module(Module &&obj) noexcept + : lib_handle(obj.lib_handle) { obj.lib_handle = nullptr; } - bool Module::is_open() const noexcept - { + bool Module::is_open() const noexcept { return nullptr != this->lib_handle; } bool Module::open(const std::string &libPath) { - if (is_open() ) - { - close(); + if (this->is_open() ) { + this->close(); } #ifdef WIN32 @@ -77,19 +79,18 @@ namespace System const std::string &lib_path = libPath; #endif - lib_handle = ::LoadLibraryEx(lib_path.c_str(), 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + this->lib_handle = ::LoadLibraryEx(lib_path.c_str(), 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); - if (cookie) - { + if (cookie) { ::RemoveDllDirectory(cookie); } #elif POSIX - lib_handle = ::dlopen(libPath.c_str(), RTLD_NOW | RTLD_LOCAL); + this->lib_handle = ::dlopen(libPath.c_str(), RTLD_NOW | RTLD_LOCAL); #else - #error "Undefine platform" + #error "Undefined platform" #endif - if (nullptr == lib_handle) + if (nullptr == this->lib_handle) { #ifdef POSIX std::cout << ::dlerror() << std::endl; @@ -102,85 +103,89 @@ namespace System void Module::close() noexcept { - if (lib_handle) + if (this->lib_handle) { #ifdef WIN32 - ::FreeLibrary(lib_handle); + ::FreeLibrary(this->lib_handle); #elif POSIX - ::dlclose(lib_handle); + ::dlclose(this->lib_handle); #else - #error "Undefine platform" + #error "Undefined platform" #endif - lib_handle = nullptr; + this->lib_handle = nullptr; } } - bool Module::find(const std::string &symbolName, void *(**addr)(void *) ) const noexcept - { + bool Module::find( + const std::string &symbolName, + void *(**addr)(void *) + ) const noexcept { if (lib_handle) { #ifdef WIN32 - *addr = reinterpret_cast(::GetProcAddress(lib_handle, symbolName.c_str() ) ); + *addr = reinterpret_cast(::GetProcAddress(this->lib_handle, symbolName.c_str() ) ); return nullptr != *addr; #elif POSIX char *error = ::dlerror(); - *addr = reinterpret_cast(::dlsym(lib_handle, symbolName.c_str() ) ); + *addr = reinterpret_cast( + ::dlsym(this->lib_handle, symbolName.c_str() ) + ); error = ::dlerror(); return nullptr == error; #else - #error "Undefine platform" + #error "Undefined platform" #endif } return false; } - bool Module::find(const char *symbolName, void *(**addr)(void *) ) const noexcept - { + bool Module::find( + const char *symbolName, + void *(**addr)(void *) + ) const noexcept { if (lib_handle) { #ifdef WIN32 - *addr = reinterpret_cast(::GetProcAddress(lib_handle, symbolName) ); + *addr = reinterpret_cast(::GetProcAddress(this->lib_handle, symbolName) ); return nullptr != *addr; #elif POSIX char *error = ::dlerror(); - *addr = reinterpret_cast(::dlsym(lib_handle, symbolName) ); + *addr = reinterpret_cast( + ::dlsym(this->lib_handle, symbolName) + ); error = ::dlerror(); return nullptr == error; #else - #error "Undefine platform" + #error "Undefined platform" #endif } return false; } - bool Module::operator ==(const Module &obj) const noexcept - { + bool Module::operator ==(const Module &obj) const noexcept { return this->lib_handle == obj.lib_handle; } - bool Module::operator !=(const Module &obj) const noexcept - { + bool Module::operator !=(const Module &obj) const noexcept { return this->lib_handle != obj.lib_handle; } Module &Module::operator =(const Module &obj) noexcept { - if (*this != obj) - { - close(); - - lib_handle = obj.lib_handle; + if (*this != obj) { + this->close(); + this->lib_handle = obj.lib_handle; } return *this; @@ -188,15 +193,12 @@ namespace System Module &Module::operator =(Module &&obj) noexcept { - if (*this != obj) - { - close(); - - lib_handle = obj.lib_handle; - + if (*this != obj) { + this->close(); + this->lib_handle = obj.lib_handle; obj.lib_handle = nullptr; } return *this; } -}; +} diff --git a/src/system/Module.h b/src/system/Module.h index 49e2e34..d7739ed 100644 --- a/src/system/Module.h +++ b/src/system/Module.h @@ -17,7 +17,7 @@ namespace System #elif POSIX void *lib_handle; #else - #error "Undefine platform" + #error "Undefined platform" #endif public: @@ -33,8 +33,15 @@ namespace System bool open(const std::string &libPath); void close() noexcept; - bool find(const std::string &symbolName, void *(**addr)(void *) ) const noexcept; - bool find(const char *symbolName, void *(**addr)(void *) ) const noexcept; + bool find( + const std::string &symbolName, + void *(**addr)(void *) + ) const noexcept; + + bool find( + const char *symbolName, + void *(**addr)(void *) + ) const noexcept; bool operator ==(const Module &obj) const noexcept; bool operator !=(const Module &obj) const noexcept; @@ -42,4 +49,4 @@ namespace System Module &operator =(const Module &obj) noexcept; Module &operator =(Module &&obj) noexcept; }; -}; +} diff --git a/src/system/SharedMemory.cpp b/src/system/SharedMemory.cpp index 1c0560f..3169941 100644 --- a/src/system/SharedMemory.cpp +++ b/src/system/SharedMemory.cpp @@ -24,17 +24,18 @@ namespace System #elif POSIX this->shm_desc = -1; #else - #error "Undefine platform" + #error "Undefined platform" #endif } - SharedMemory::~SharedMemory() noexcept - { + SharedMemory::~SharedMemory() noexcept { this->close(); } - bool SharedMemory::create(const std::string &memName, const size_t memSize) - { + bool SharedMemory::create( + const std::string &memName, + const size_t memSize + ) { this->close(); #ifdef WIN32 @@ -57,31 +58,31 @@ namespace System memory_name.c_str() ); - if (nullptr == this->shm_desc) - { + if (nullptr == this->shm_desc) { return false; } #elif POSIX - this->shm_desc = ::shm_open(memName.c_str(), O_CREAT | O_RDWR, 0666); + this->shm_desc = ::shm_open( + memName.c_str(), + O_CREAT | O_RDWR, + 0666 + ); - if (-1 == this->shm_desc) - { + if (-1 == this->shm_desc) { return false; } - if (-1 == ::ftruncate64(this->shm_desc, memSize) ) - { + if (::ftruncate64(this->shm_desc, long(memSize)) == -1) { this->destroy(memName); - return false; } this->shm_name = memName; #else - #error "Undefine platform" + #error "Undefined platform" #endif return true; @@ -104,8 +105,7 @@ namespace System this->shm_desc = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, false, memory_name.c_str() ); - if (nullptr == this->shm_desc) - { + if (nullptr == this->shm_desc) { return false; } @@ -113,17 +113,20 @@ namespace System #elif POSIX - this->shm_desc = ::shm_open(memName.c_str(), O_RDWR, 0666); + this->shm_desc = ::shm_open( + memName.c_str(), + O_RDWR, + 0666 + ); - if (-1 == this->shm_desc) - { + if (-1 == this->shm_desc) { return false; } this->shm_name = memName; #else - #error "Undefine platform" + #error "Undefined platform" #endif return true; @@ -136,18 +139,20 @@ namespace System #elif POSIX return -1 != this->shm_desc; #else - #error "Undefine platform" + #error "Undefined platform" #endif } - bool SharedMemory::write(const void *src, const size_t size, const size_t offset) const noexcept - { + bool SharedMemory::write( + const void *src, + const size_t size, + const size_t offset + ) const noexcept { #ifdef WIN32 void * const addr = ::MapViewOfFile(this->shm_desc, FILE_MAP_WRITE, 0, static_cast<::DWORD>(offset), size); - if (nullptr == addr) - { + if (nullptr == addr) { return false; } @@ -157,32 +162,40 @@ namespace System #elif POSIX - void * const addr = ::mmap(0, size, PROT_WRITE, MAP_SHARED, this->shm_desc, offset); + void * const addr = ::mmap( + nullptr, + size, + PROT_WRITE, + MAP_SHARED, + this->shm_desc, + long(offset) + ); - if (reinterpret_cast(-1) == addr) - { + if (reinterpret_cast(-1) == addr) { return false; } - ::memcpy(addr, src, size); + std::memcpy(addr, src, size); ::munmap(addr, size); #else - #error "Undefine platform" + #error "Undefined platform" #endif return true; } - bool SharedMemory::read(void *dest, const size_t size, const size_t offset) const noexcept - { + bool SharedMemory::read( + void *dest, + const size_t size, + const size_t offset + ) const noexcept { #ifdef WIN32 void * const addr = ::MapViewOfFile(this->shm_desc, FILE_MAP_READ, 0, static_cast<::DWORD>(offset), size); - if (nullptr == addr) - { + if (nullptr == addr) { return false; } @@ -192,19 +205,25 @@ namespace System #elif POSIX - void * const addr = ::mmap(0, size, PROT_READ, MAP_SHARED, this->shm_desc, offset); + void * const addr = ::mmap( + nullptr, + size, + PROT_READ, + MAP_SHARED, + this->shm_desc, + long(offset) + ); - if (reinterpret_cast(-1) == addr) - { + if (reinterpret_cast(-1) == addr) { return false; } - ::memcpy(dest, addr, size); + std::memcpy(dest, addr, size); ::munmap(addr, size); #else - #error "Undefine platform" + #error "Undefined platform" #endif return true; @@ -221,7 +240,7 @@ namespace System ::close(this->shm_desc); this->shm_desc = ~0; #else - #error "Undefine platform" + #error "Undefined platform" #endif this->shm_name.clear(); @@ -250,13 +269,15 @@ namespace System return ret; #elif POSIX - const int ret = ::shm_unlink(this->shm_name.c_str() ); + const int ret = ::shm_unlink( + this->shm_name.c_str() + ); this->close(); return 0 == ret; #else - #error "Undefine platform" + #error "Undefined platform" #endif } @@ -278,7 +299,7 @@ namespace System #elif POSIX return 0 == ::shm_unlink(memName.c_str() ); #else - #error "Undefine platform" + #error "Undefined platform" #endif } -}; +} diff --git a/src/system/SharedMemory.h b/src/system/SharedMemory.h index d76608f..b9a84e9 100644 --- a/src/system/SharedMemory.h +++ b/src/system/SharedMemory.h @@ -17,7 +17,7 @@ namespace System #elif POSIX int shm_desc; #else - #error "Undefine platform" + #error "Undefined platform" #endif std::string shm_name; @@ -26,17 +26,30 @@ namespace System SharedMemory() noexcept; ~SharedMemory() noexcept; - bool create(const std::string &memName, const size_t memSize); + bool create( + const std::string &memName, + const size_t memSize + ); + bool open(const std::string &memName); bool is_open() const noexcept; - bool write(const void *data, const size_t size, const size_t offset = 0) const noexcept; - bool read(void *dest, const size_t size, const size_t offset = 0) const noexcept; + bool write( + const void *data, + const size_t size, + const size_t offset = 0 + ) const noexcept; + + bool read( + void *dest, + const size_t size, + const size_t offset = 0 + ) const noexcept; bool close() noexcept; bool destroy(); static bool destroy(const std::string &memName); }; -}; +} diff --git a/src/system/System.cpp b/src/system/System.cpp index 9dcaeb7..af696d9 100644 --- a/src/system/System.cpp +++ b/src/system/System.cpp @@ -20,8 +20,7 @@ namespace System { #ifdef WIN32 - struct EnumData - { + struct EnumData { native_processid_type process_id; ::HWND hWnd; }; @@ -34,7 +33,7 @@ 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; @@ -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 } @@ -297,7 +312,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..d7ae219 100644 --- a/src/system/System.h +++ b/src/system/System.h @@ -7,27 +7,27 @@ ::TCHAR 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 + #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 #else - #error "Undefine platform" + #error "Undefined platform" #endif #include @@ -41,7 +41,7 @@ namespace System #elif POSIX typedef int native_socket_type; #else - #error "Undefine platform" + #error "Undefined platform" #endif #ifdef WIN32 @@ -49,7 +49,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 2568b73..87e745b 100644 --- a/src/transfer/FileIncoming.h +++ b/src/transfer/FileIncoming.h @@ -18,7 +18,13 @@ namespace Transfer FileIncoming() = delete; public: - 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 +41,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 4b3ee40b97abd07e63a8614b0a66e123d3f1376d Mon Sep 17 00:00:00 2001 From: Ignat Prokopovich Date: Sun, 1 Apr 2018 17:26:45 +0300 Subject: [PATCH 47/50] Fixed code (and style) for Windows. --- src/server/config/ConfigParser.cpp | 6 +- src/server/data-variant/FormUrlencoded.cpp | 23 +++---- src/server/protocol/ServerHttp2Protocol.cpp | 5 +- src/server/protocol/extensions/Sendfile.cpp | 18 ++++- src/socket/AdapterTls.cpp | 4 +- src/socket/List.cpp | 12 ++-- src/socket/Socket.cpp | 23 ++++--- src/system/GlobalMutex.cpp | 38 +++++++++-- src/system/Module.cpp | 76 ++++++++++++++------- src/system/SharedMemory.cpp | 44 ++++++++++-- src/system/System.cpp | 9 ++- src/system/System.h | 6 +- 12 files changed, 179 insertions(+), 85 deletions(-) diff --git a/src/server/config/ConfigParser.cpp b/src/server/config/ConfigParser.cpp index 1bbb42a..ab08166 100644 --- a/src/server/config/ConfigParser.cpp +++ b/src/server/config/ConfigParser.cpp @@ -279,7 +279,7 @@ namespace HttpServer try { if (app_init) { - const std::string root = root_dir; + const std::string &root = root_dir; success = app_init(root.data() ); } } @@ -356,8 +356,8 @@ namespace HttpServer if (names.empty() ) { apps_tree.addApplication(app_name, settings); } else { - for (size_t i = 0; i < names.size(); ++i) { - apps_tree.addApplication(names[i], settings); + for (auto const &name : names) { + apps_tree.addApplication(name, settings); } } diff --git a/src/server/data-variant/FormUrlencoded.cpp b/src/server/data-variant/FormUrlencoded.cpp index 08f8180..28adff0 100644 --- a/src/server/data-variant/FormUrlencoded.cpp +++ b/src/server/data-variant/FormUrlencoded.cpp @@ -1,4 +1,4 @@ - + #include "FormUrlencoded.h" #include "../../utils/Utils.h" @@ -20,7 +20,7 @@ namespace DataVariant std::string::npos != var_end; var_pos = var_end + 1 ) { - // Поиск следующего параметра + // Search next parameter var_end = buf.find('&', var_pos); if (std::string::npos == var_end) { @@ -30,12 +30,11 @@ namespace DataVariant } } - // Поиск значения параметра + // Search parameter value size_t delimiter = buf.find('=', var_pos); - if (delimiter >= var_end) - { - // Получить имя параметра + if (delimiter >= var_end) { + // Get parameter name std::string var_name = Utils::urlDecode( buf.substr( var_pos, @@ -45,15 +44,13 @@ namespace DataVariant ) ); - // Сохранить параметр с пустым значением + // Store parameter with empty value rd->incoming_data.emplace( std::move(var_name), std::string() ); - } - else - { - // Получить имя параметра + } else { + // Get parameter name std::string var_name = Utils::urlDecode( buf.substr( var_pos, @@ -63,7 +60,7 @@ namespace DataVariant ++delimiter; - // Получить значение параметра + // Get parameter value std::string var_value = Utils::urlDecode( buf.substr( delimiter, @@ -73,7 +70,7 @@ namespace DataVariant ) ); - // Сохранить параметр и значение + // Store parameter and value rd->incoming_data.emplace( std::move(var_name), std::move(var_value) diff --git a/src/server/protocol/ServerHttp2Protocol.cpp b/src/server/protocol/ServerHttp2Protocol.cpp index fd4ed10..6cb996b 100644 --- a/src/server/protocol/ServerHttp2Protocol.cpp +++ b/src/server/protocol/ServerHttp2Protocol.cpp @@ -25,9 +25,8 @@ namespace HttpServer } std::random_device rd; - std::uniform_int_distribution dist; - uint8_t padding = dist(rd); + uint8_t padding = uint8_t(rd()); while (dataSize <= padding) { padding /= 2; @@ -177,7 +176,7 @@ namespace HttpServer } data += data_size; - send_size += data_size; + send_size += long(data_size); dt->send_total += data_size; // stream->window_size_out -= frame_size; diff --git a/src/server/protocol/extensions/Sendfile.cpp b/src/server/protocol/extensions/Sendfile.cpp index 1758515..2799f57 100644 --- a/src/server/protocol/extensions/Sendfile.cpp +++ b/src/server/protocol/extensions/Sendfile.cpp @@ -100,7 +100,9 @@ namespace HttpServer *resultRangeHeader += std::to_string(range_begin) + '-' + std::to_string(range_end) + ','; - ranges.emplace_back(std::tuple {range_begin, length}); + ranges.emplace_back(std::tuple { + range_begin, length + }); } } else // if range_end_str empty @@ -275,7 +277,12 @@ namespace HttpServer send_size_left -= send_size; } - while (false == file.eof() && false == file.fail() && send_size > 0 && send_size_left); + while ( + false == file.eof() && + false == file.fail() && + send_size > 0 && + send_size_left + ); } } @@ -407,7 +414,12 @@ namespace HttpServer &dt ); } - while (false == file.eof() && false == file.fail() && send_size > 0 && (dt.full_size - dt.send_total) ); + while ( + false == file.eof() && + false == file.fail() && + send_size > 0 && + (dt.full_size - dt.send_total) + ); } file.close(); diff --git a/src/socket/AdapterTls.cpp b/src/socket/AdapterTls.cpp index 118e885..0126830 100644 --- a/src/socket/AdapterTls.cpp +++ b/src/socket/AdapterTls.cpp @@ -97,10 +97,10 @@ 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 { diff --git a/src/socket/List.cpp b/src/socket/List.cpp index a1accbd..eab986d 100644 --- a/src/socket/List.cpp +++ b/src/socket/List.cpp @@ -1,4 +1,4 @@ - + #include "List.h" #ifdef POSIX @@ -271,17 +271,15 @@ namespace Socket 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, @@ -367,10 +365,8 @@ namespace Socket 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) ); } diff --git a/src/socket/Socket.cpp b/src/socket/Socket.cpp index 54904d3..40b0f92 100644 --- a/src/socket/Socket.cpp +++ b/src/socket/Socket.cpp @@ -188,7 +188,7 @@ namespace Socket 0 }; - if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLRDNORM) { + if (1 == ::WSAPoll(&event, 1, int(timeout.count()) ) && event.revents & POLLRDNORM) { client_socket = ::accept( this->socket_handle, static_cast(nullptr), @@ -235,7 +235,12 @@ 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, @@ -338,7 +343,7 @@ namespace Socket 0 }; - if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLRDNORM) { + if (1 == ::WSAPoll(&event, 1, int(timeout.count()) ) && event.revents & POLLRDNORM) { recv_len = ::recv( this->socket_handle, reinterpret_cast(buf), @@ -372,7 +377,7 @@ namespace Socket 0 }; - return ::WSAPoll(&event, 1, timeout.count() ) == 1; + return ::WSAPoll(&event, 1, int(timeout.count()) ) == 1; #elif POSIX struct ::pollfd event { this->socket_handle, @@ -405,7 +410,7 @@ namespace Socket return send_size; } - total += static_cast(send_size); + total += size_t(send_size); } return static_cast(total); @@ -435,7 +440,7 @@ namespace Socket }; while (total < length) { - if (1 == ::WSAPoll(&event, 1, static_cast<::INT>(timeout.count() ) ) && event.revents & POLLOUT) { + if (1 == ::WSAPoll(&event, 1, int(timeout.count()) ) && event.revents & POLLOUT) { const long send_size = ::send( socket_handle, reinterpret_cast(data) + total, @@ -447,7 +452,7 @@ namespace Socket return send_size; } - total += send_size; + total += size_t(send_size); } else { return -1; } @@ -473,7 +478,7 @@ namespace Socket return send_size; } - total += static_cast(send_size); + total += size_t(send_size); } else { return -1; } @@ -482,7 +487,7 @@ namespace Socket #error "Undefined platform" #endif - return static_cast(total); + return long(total); } long Socket::nonblock_send( diff --git a/src/system/GlobalMutex.cpp b/src/system/GlobalMutex.cpp index 0c72d06..9a5477e 100644 --- a/src/system/GlobalMutex.cpp +++ b/src/system/GlobalMutex.cpp @@ -39,7 +39,11 @@ namespace System const std::string &mutex_name = this->mtx_name; #endif - this->mtx_desc = ::CreateMutex(nullptr, false, mutex_name.c_str() ); + this->mtx_desc = ::CreateMutex( + nullptr, + false, + mutex_name.c_str() + ); if (nullptr == this->mtx_desc) { return false; @@ -77,7 +81,11 @@ namespace System const std::string &mutex_name = mtx_name; #endif - ::HANDLE hMutex = ::OpenMutex(DELETE, true, mutex_name.c_str() ); + const ::HANDLE hMutex = ::OpenMutex( + DELETE, + true, + mutex_name.c_str() + ); return 0 != ::CloseHandle(hMutex); #elif POSIX @@ -97,9 +105,15 @@ namespace System const std::string &mutex_name = this->mtx_name; #endif - ::HANDLE hMutex = ::OpenMutex(DELETE, true, mutex_name.c_str() ); + const ::HANDLE hMutex = ::OpenMutex( + DELETE, + true, + mutex_name.c_str() + ); - const bool ret = (0 != ::CloseHandle(hMutex) ); + const bool ret = ( + 0 != ::CloseHandle(hMutex) + ); this->close(); @@ -132,7 +146,11 @@ namespace System const std::string &mutex_name = this->mtx_name; #endif - this->mtx_desc = ::OpenMutex(SYNCHRONIZE, false, mutex_name.c_str() ); + this->mtx_desc = ::OpenMutex( + SYNCHRONIZE, + false, + mutex_name.c_str() + ); if (nullptr == this->mtx_desc) { return false; @@ -193,7 +211,10 @@ namespace System bool GlobalMutex::lock() const noexcept { #ifdef WIN32 - return WAIT_OBJECT_0 == ::WaitForSingleObject(this->mtx_desc, INFINITE); + return WAIT_OBJECT_0 == ::WaitForSingleObject( + this->mtx_desc, + INFINITE + ); #elif POSIX return 0 == ::sem_wait(this->mtx_desc); #else @@ -204,7 +225,10 @@ namespace System bool GlobalMutex::try_lock() const noexcept { #ifdef WIN32 - return WAIT_OBJECT_0 == ::WaitForSingleObject(this->mtx_desc, 0); + return WAIT_OBJECT_0 == ::WaitForSingleObject( + this->mtx_desc, + 0 + ); #elif POSIX return 0 == ::sem_trywait(this->mtx_desc); #else diff --git a/src/system/Module.cpp b/src/system/Module.cpp index a417a59..ef7f512 100644 --- a/src/system/Module.cpp +++ b/src/system/Module.cpp @@ -1,4 +1,4 @@ - + #include "Module.h" #ifdef WIN32 @@ -52,24 +52,26 @@ namespace System const size_t pos_slash = libPath.rfind('\\'); const size_t pos_slash_back = libPath.rfind('/'); - size_t pos = std::string::npos; - - if (pos_slash != std::string::npos && pos_slash > pos_slash_back) - { - pos = pos_slash; - } - else if (pos_slash_back != std::string::npos) - { - pos = pos_slash_back; - } - - DLL_DIRECTORY_COOKIE cookie = nullptr; - - if (std::string::npos != pos) - { - std::wstring directory(libPath.cbegin(), libPath.cbegin() + pos + 1); + const size_t pos = ( + pos_slash != std::string::npos && + pos_slash > pos_slash_back + ? pos_slash + : pos_slash_back != std::string::npos + ? pos_slash_back + : std::string::npos + ); + + ::DLL_DIRECTORY_COOKIE cookie = nullptr; + + if (std::string::npos != pos) { + const std::wstring directory( + libPath.cbegin(), + libPath.cbegin() + pos + 1 + ); - cookie = ::AddDllDirectory(directory.data() ); + cookie = ::AddDllDirectory( + directory.data() + ); } #ifdef UNICODE @@ -79,13 +81,20 @@ namespace System const std::string &lib_path = libPath; #endif - this->lib_handle = ::LoadLibraryEx(lib_path.c_str(), 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + this->lib_handle = ::LoadLibraryEx( + lib_path.c_str(), + 0, + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS + ); if (cookie) { ::RemoveDllDirectory(cookie); } #elif POSIX - this->lib_handle = ::dlopen(libPath.c_str(), RTLD_NOW | RTLD_LOCAL); + this->lib_handle = ::dlopen( + libPath.c_str(), + RTLD_NOW | RTLD_LOCAL + ); #else #error "Undefined platform" #endif @@ -121,17 +130,24 @@ namespace System const std::string &symbolName, void *(**addr)(void *) ) const noexcept { - if (lib_handle) - { + if (lib_handle) { #ifdef WIN32 - *addr = reinterpret_cast(::GetProcAddress(this->lib_handle, symbolName.c_str() ) ); + *addr = reinterpret_cast( + ::GetProcAddress( + this->lib_handle, + symbolName.c_str() + ) + ); return nullptr != *addr; #elif POSIX char *error = ::dlerror(); *addr = reinterpret_cast( - ::dlsym(this->lib_handle, symbolName.c_str() ) + ::dlsym( + this->lib_handle, + symbolName.c_str() + ) ); error = ::dlerror(); @@ -152,14 +168,22 @@ namespace System if (lib_handle) { #ifdef WIN32 - *addr = reinterpret_cast(::GetProcAddress(this->lib_handle, symbolName) ); + *addr = reinterpret_cast( + ::GetProcAddress( + this->lib_handle, + symbolName + ) + ); return nullptr != *addr; #elif POSIX char *error = ::dlerror(); *addr = reinterpret_cast( - ::dlsym(this->lib_handle, symbolName) + ::dlsym( + this->lib_handle, + symbolName + ) ); error = ::dlerror(); diff --git a/src/system/SharedMemory.cpp b/src/system/SharedMemory.cpp index 3169941..a88b1e7 100644 --- a/src/system/SharedMemory.cpp +++ b/src/system/SharedMemory.cpp @@ -103,7 +103,11 @@ namespace System const std::string &memory_name = this->shm_name; #endif - this->shm_desc = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, false, memory_name.c_str() ); + this->shm_desc = ::OpenFileMapping( + FILE_MAP_ALL_ACCESS, + false, + memory_name.c_str() + ); if (nullptr == this->shm_desc) { return false; @@ -150,7 +154,16 @@ namespace System ) const noexcept { #ifdef WIN32 - void * const addr = ::MapViewOfFile(this->shm_desc, FILE_MAP_WRITE, 0, static_cast<::DWORD>(offset), size); + ::ULARGE_INTEGER off; + off.QuadPart = ::ULONGLONG(offset); + + void * const addr = ::MapViewOfFile( + this->shm_desc, + FILE_MAP_WRITE, + off.HighPart, + off.LowPart, + size + ); if (nullptr == addr) { return false; @@ -193,7 +206,16 @@ namespace System ) const noexcept { #ifdef WIN32 - void * const addr = ::MapViewOfFile(this->shm_desc, FILE_MAP_READ, 0, static_cast<::DWORD>(offset), size); + ::ULARGE_INTEGER off; + off.QuadPart = ::ULONGLONG(offset); + + void * const addr = ::MapViewOfFile( + this->shm_desc, + FILE_MAP_READ, + off.HighPart, + off.LowPart, + size + ); if (nullptr == addr) { return false; @@ -261,9 +283,15 @@ namespace System const std::string &memory_name = this->shm_name; #endif - ::HANDLE hMemory = ::OpenFileMapping(DELETE, false, memory_name.c_str() ); + const ::HANDLE hMemory = ::OpenFileMapping( + DELETE, + false, + memory_name.c_str() + ); - const bool ret = (0 != ::CloseHandle(hMemory) ); + const bool ret = ( + 0 != ::CloseHandle(hMemory) + ); this->close(); @@ -293,7 +321,11 @@ namespace System const std::string &memory_name = shm_name; #endif - ::HANDLE hMemory = ::OpenFileMapping(DELETE, false, memory_name.c_str() ); + const ::HANDLE hMemory = ::OpenFileMapping( + DELETE, + false, + memory_name.c_str() + ); return 0 != ::CloseHandle(hMemory); #elif POSIX diff --git a/src/system/System.cpp b/src/system/System.cpp index af696d9..ebb5935 100644 --- a/src/system/System.cpp +++ b/src/system/System.cpp @@ -1,4 +1,4 @@ - + #include "System.h" #include @@ -37,7 +37,7 @@ namespace System { 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; @@ -284,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] {}; diff --git a/src/system/System.h b/src/system/System.h index d7ae219..8b637d4 100644 --- a/src/system/System.h +++ b/src/system/System.h @@ -1,9 +1,11 @@ -#pragma once +#pragma once #ifdef WIN32 #include - typedef long ssize_t; + #ifndef ssize_t + typedef long ssize_t; + #endif ::TCHAR myWndClassName[]; From 0e8c8dd92569d86fc7dae2da08e1731fe497c0a2 Mon Sep 17 00:00:00 2001 From: awwit Date: Mon, 2 Apr 2018 21:34:19 +0300 Subject: [PATCH 48/50] Optimized some copy operations. Added copy constructor for FileIncoming. --- src/server/protocol/ServerHttp2.cpp | 6 +++--- src/server/protocol/ServerHttp2Protocol.cpp | 8 +++++--- src/transfer/FileIncoming.h | 7 ++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/server/protocol/ServerHttp2.cpp b/src/server/protocol/ServerHttp2.cpp index 12ae2be..35632ad 100644 --- a/src/server/protocol/ServerHttp2.cpp +++ b/src/server/protocol/ServerHttp2.cpp @@ -590,9 +590,9 @@ namespace HttpServer } } else { std::copy( - buf.cbegin() + length, - buf.cbegin() + read_size, - buf.begin() + buf.data() + length, + buf.data() + read_size, + buf.data() ); read_size -= length; diff --git a/src/server/protocol/ServerHttp2Protocol.cpp b/src/server/protocol/ServerHttp2Protocol.cpp index 6cb996b..857c216 100644 --- a/src/server/protocol/ServerHttp2Protocol.cpp +++ b/src/server/protocol/ServerHttp2Protocol.cpp @@ -106,7 +106,9 @@ namespace HttpServer } } - 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); @@ -141,7 +143,7 @@ namespace HttpServer this->stream->setHttp2FrameHeader( buf.data(), - static_cast(frame_size), + frame_size, Http2::FrameType::DATA, flags ); @@ -149,7 +151,7 @@ namespace HttpServer std::copy( data, data + data_size, - buf.begin() + long(cur) + buf.data() + cur ); if (padding) { diff --git a/src/transfer/FileIncoming.h b/src/transfer/FileIncoming.h index 87e745b..448c8c8 100644 --- a/src/transfer/FileIncoming.h +++ b/src/transfer/FileIncoming.h @@ -14,10 +14,9 @@ namespace Transfer std::string file_type; size_t file_size; - private: - FileIncoming() = delete; - public: + FileIncoming() = default; + FileIncoming( std::string &&fileTmpName, std::string &&fileName, @@ -30,6 +29,8 @@ namespace Transfer ~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; From a3389a3fee20b8186754bca73faac8ee8c4e7146 Mon Sep 17 00:00:00 2001 From: awwit Date: Thu, 31 May 2018 16:12:19 +0300 Subject: [PATCH 49/50] Added output of messages with exceptions. --- src/server/Server.cpp | 4 ++-- src/server/ServerSettings.cpp | 6 ++---- src/server/config/ConfigParser.cpp | 2 +- src/server/protocol/ServerProtocol.cpp | 12 ++++++++---- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/server/Server.cpp b/src/server/Server.cpp index df464eb..ca069e9 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -313,7 +313,7 @@ namespace HttpServer app->application_final(root.data() ); } } - catch (std::exception &exc) { + catch (const std::exception &exc) { std::cout << "Warning: an exception was thrown when the application '" << app->server_module << "' was finishes: " << exc.what() << std::endl; } @@ -460,7 +460,7 @@ namespace HttpServer app->application_init(root.data() ); } } - catch (std::exception &exc) { + catch (const std::exception &exc) { std::cout << "Warning: an exception was thrown when the application '" << module_name << "' was initialized: " << exc.what() << std::endl; } } diff --git a/src/server/ServerSettings.cpp b/src/server/ServerSettings.cpp index 3677a62..4370d1e 100644 --- a/src/server/ServerSettings.cpp +++ b/src/server/ServerSettings.cpp @@ -34,15 +34,13 @@ namespace HttpServer for (auto &app : applications) { - try - { + try { if (app->application_final) { const std::string root = app->root_dir; app->application_final(root.data() ); } } - catch (std::exception &exc) - { + catch (const std::exception &exc) { std::cout << "Warning: an exception was thrown when the application '" << app->server_module << "' was finishes: " << exc.what() << std::endl; } diff --git a/src/server/config/ConfigParser.cpp b/src/server/config/ConfigParser.cpp index ab08166..c00ea41 100644 --- a/src/server/config/ConfigParser.cpp +++ b/src/server/config/ConfigParser.cpp @@ -283,7 +283,7 @@ namespace HttpServer success = app_init(root.data() ); } } - catch (std::exception &exc) { + catch (const std::exception &exc) { std::cout << "Warning: an exception was thrown when the application '" << it_module->second << "' was initialized: " << exc.what() << std::endl; success = false; } diff --git a/src/server/protocol/ServerProtocol.cpp b/src/server/protocol/ServerProtocol.cpp index 42628eb..4f3010d 100644 --- a/src/server/protocol/ServerProtocol.cpp +++ b/src/server/protocol/ServerProtocol.cpp @@ -2,6 +2,8 @@ #include "ServerProtocol.h" #include "../../utils/Utils.h" +#include + namespace HttpServer { ServerProtocol::ServerProtocol( @@ -167,8 +169,9 @@ namespace HttpServer // Launch application req.app_exit_code = appSets.application_call(&request, &response); } - catch (std::exception &exc) { - // TODO: exception output + catch (const std::exception &exc) { + // Exception output + std::cout << "Exception when application_call: " << exc.what() << std::endl; } if (response.response_data && response.data_size) @@ -181,8 +184,9 @@ namespace HttpServer try { appSets.application_clear(response.response_data, response.data_size); } - catch (std::exception &exc) { - // TODO: exception output + catch (const std::exception &exc) { + // Exception output + std::cout << "Exception when application_clear: " << exc.what() << std::endl; } } } From d824fe72fe134e5abcddbb7879dd339a06142b92 Mon Sep 17 00:00:00 2001 From: awwit Date: Mon, 30 Jul 2018 15:31:31 +0300 Subject: [PATCH 50/50] Fixed issue #6 --- src/server/protocol/extensions/Sendfile.cpp | 6 +++-- src/socket/Socket.cpp | 26 ++++++++++++--------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/server/protocol/extensions/Sendfile.cpp b/src/server/protocol/extensions/Sendfile.cpp index 2799f57..dc46186 100644 --- a/src/server/protocol/extensions/Sendfile.cpp +++ b/src/server/protocol/extensions/Sendfile.cpp @@ -221,7 +221,8 @@ namespace HttpServer additionalHeaders.emplace_back("last-modified", Utils::getDatetimeAsString(fileTime, true) ); // Отправить заголовки (206 Partial Content) - if (prot.sendHeaders( + if ( + prot.sendHeaders( Http::StatusCode::PARTIAL_CONTENT, additionalHeaders, req.timeout, @@ -377,7 +378,8 @@ namespace HttpServer additionalHeaders.emplace_back("last-modified", Utils::getDatetimeAsString(file_time, true) ); // Отправить заголовки (200 OK) - if (prot.sendHeaders( + if ( + prot.sendHeaders( Http::StatusCode::OK, additionalHeaders, req.timeout, diff --git a/src/socket/Socket.cpp b/src/socket/Socket.cpp index 40b0f92..05263db 100644 --- a/src/socket/Socket.cpp +++ b/src/socket/Socket.cpp @@ -103,17 +103,21 @@ namespace Socket } bool Socket::bind(const int port) const noexcept { + // GCC bug with global namespace: https://bbs.archlinux.org/viewtopic.php?id=53751 + auto const net_port = htons(static_cast(port)); + auto const net_addr = ::htonl(INADDR_ANY); + const ::sockaddr_in sock_addr { AF_INET, - ::htons(port), - ::htonl(INADDR_ANY), - 0 + net_port, + { net_addr }, + { 0 } // sin_zero }; return 0 == ::bind( this->socket_handle, - reinterpret_cast(&sock_addr), - sizeof(sockaddr_in) + reinterpret_cast(&sock_addr), + sizeof(::sockaddr_in) ); } @@ -147,9 +151,9 @@ namespace Socket #ifdef WIN32 WSAPOLLFD event { this->socket_handle, - POLLRDNORM, - 0 - }; + POLLRDNORM, + 0 + }; if (1 == ::WSAPoll(&event, 1, ~0) && event.revents & POLLRDNORM) { client_socket = ::accept( @@ -161,9 +165,9 @@ namespace Socket #elif POSIX struct ::pollfd event { this->socket_handle, - POLLIN, - 0 - }; + POLLIN, + 0 + }; if (1 == ::poll(&event, 1, ~0) && event.revents & POLLIN) { client_socket = ::accept(