commit 75d552576b36e6005329689689467468eb3bebca from: Aleksey Ryndin date: Wed Aug 30 12:04:14 2023 UTC Refectoring: URL parser -> Gemini request parser commit - 2f4289de81ec2f59955947bad61a6e9037183b63 commit + 75d552576b36e6005329689689467468eb3bebca blob - 218df0d6e740a53293ed9e6279ada706563aa26d blob + 28e9c68f37b47c27910971722aaf6032a9f213d6 --- .gitignore +++ .gitignore @@ -1,7 +1,7 @@ syntax: glob cert/ vostok/vostok -tests/test_parse_url +tests/test_request tests/test_open_file **/*.swp **/*.o blob - d209b7c61c4cebf765b97b2a42a5b6ffd81b706b blob + 0f3019466b5fcf8c9cc286c34515fa9ff67f0576 --- tests/Makefile +++ tests/Makefile @@ -1,16 +1,16 @@ .PHONY: tests clean -CXXFLAGS += -I../vostok +CXXFLAGS = -D_GLIBCXX_DEBUG -D_LIBCPP_DEBUG -DDEBUG -D_DEBUG -I../vostok -tests: test_parse_url test_open_file - ./test_parse_url +tests: test_request test_open_file + ./test_request ./test_open_file -test_parse_url: test_parse_url.cc ../vostok/parse_url.cc ../vostok/parse_url.h - ${CXX} ${CXXFLAGS} test_parse_url.cc ../vostok/parse_url.cc -o test_parse_url +test_request: test_request.cc ../vostok/request.cc ../vostok/request.h ../vostok/gemini.cc + ${CXX} ${CXXFLAGS} test_request.cc ../vostok/request.cc ../vostok/gemini.cc -o test_request test_open_file: test_open_file.cc ../vostok/open_file.cc ../vostok/open_file.h ${CXX} ${CXXFLAGS} test_open_file.cc ../vostok/open_file.cc -o test_open_file clean: - rm -f test_parse_url test_open_file + rm -f test_request test_open_file blob - 3ae18a4e563aa1dbdc476b126a710a87fdc15ad2 (mode 644) blob + /dev/null --- tests/test_parse_url.cc +++ /dev/null @@ -1,76 +0,0 @@ -#include "parse_url.h" -#include -#include - -#include "tests.h" - - -namespace vostok -{ -namespace -{ -template -void init(std::vector &v, const char (&arr)[N], bool cut_null=false) -{ - static_assert(N > 0, "N"); - const auto n = cut_null ? (N - 1) : N; - v.resize(n); - std::copy(&arr[0], &arr[n], v.begin()); -} -} // namespace - -TEST_START(test_extract_url_path) - std::vector url, expected; - -#define CASE_OK(url_literal, path_literal) \ - init(url, url_literal, true); \ - init(expected, path_literal); \ - IS_TRUE(extract_url_path(url) == url_ok && (url.size() == expected.size() && std::equal(url.cbegin(), url.cend(), expected.cbegin()))) - - CASE_OK("gemini://host", ""); - CASE_OK("gemini://host/", ""); - CASE_OK("gemini://host/a", "a"); - CASE_OK("gemini://host/a/", "a"); - CASE_OK("gemini://host/a/b", "a/b"); - CASE_OK("gemini://host/a/b/", "a/b"); - - CASE_OK("gemini://host:1965", ""); - CASE_OK("gemini://host:1965/", ""); - CASE_OK("gemini://host:1965/a", "a"); - CASE_OK("gemini://host:1965/a/", "a"); - CASE_OK("gemini://host:1965/a/b", "a/b"); - CASE_OK("gemini://host:1965/a/b/", "a/b"); - - CASE_OK("gemini://host/a/b/../c/./d", "a/c/d"); - - // RFC 3986, 3.1. Scheme - // > ... An implementation - // > should accept uppercase letters as equivalent to lowercase in scheme - // > names (e.g., allow "HTTP" as well as "http") - CASE_OK("GeMiNi://host", ""); - -#define CASE_ERROR(url_literal, expected_result) \ - init(url, url_literal, true); \ - IS_TRUE(extract_url_path(url) == expected_result) - - CASE_ERROR("", url_too_short); - CASE_ERROR("g", url_too_short); - CASE_ERROR("gemini:/", url_too_short); - - CASE_ERROR("gemini1://", url_non_gemini); - CASE_ERROR("semini://", url_non_gemini); - - CASE_ERROR("gemini://host/../secret.txt", url_root_traverse); - CASE_ERROR("gemini://host/dir/../../secret.txt", url_root_traverse); - -TEST_END() - -} // namespace vostok - - -extern "C" -int -main(int, char **) -{ - return vostok::test_extract_url_path(); -} blob - /dev/null blob + 7a61653e524b22ec02a4d5d321f6ade1014aeb3e (mode 644) --- /dev/null +++ tests/test_request.cc @@ -0,0 +1,85 @@ +#include "request.h" +#include +#include + +#include "tests.h" + + +namespace vostok +{ +namespace +{ +template +void fill_request_buffer(std::vector &v, const char (&arr)[N]) +{ + static_assert(N > 0, "N"); + v.resize(N + 1); + auto p = std::copy(&arr[0], &arr[N - 1], v.begin()); + *p = '\r'; + ++p; + *p = '\n'; + ++p; +} +} // namespace + +TEST_START(test_request) + Request request; + + auto &buffer = request.get_buffer(); + IS_TRUE(buffer.size() == 1026); + + fill_request_buffer(buffer, "gemini://host"); + buffer[buffer.size() - 1] = '\0'; + IS_TRUE(request.parse() == Request::BAD_REQUEST); + +#define CASE_ERROR(url_literal, expected_result) \ + fill_request_buffer(request.get_buffer(), url_literal); \ + IS_TRUE(request.parse() == expected_result) + + CASE_ERROR("", Request::URL_TOO_SHORT); + CASE_ERROR("g", Request::URL_TOO_SHORT); + CASE_ERROR("gemini:/", Request::URL_TOO_SHORT); + + CASE_ERROR("gemini1://", Request::URL_NON_GEMINI); + CASE_ERROR("semini://", Request::URL_NON_GEMINI); + + CASE_ERROR("gemini://host/../secret.txt", Request::URL_ROOT_TRAVERSE); + CASE_ERROR("gemini://host/dir/../../secret.txt", Request::URL_ROOT_TRAVERSE); + +#define CASE_OK(url_literal, path_literal) \ + fill_request_buffer(request.get_buffer(), url_literal); \ + IS_TRUE(request.parse() == Request::URL_OK && !strcmp(request.get_path().data(), path_literal)) + + CASE_OK("gemini://host", ""); + CASE_OK("gemini://host/", ""); + CASE_OK("gemini://host/a", "a"); + CASE_OK("gemini://host/a/", "a"); + CASE_OK("gemini://host/a/b", "a/b"); + CASE_OK("gemini://host/a/b/", "a/b"); + + CASE_OK("gemini://host:1965", ""); + CASE_OK("gemini://host:1965/", ""); + CASE_OK("gemini://host:1965/a", "a"); + CASE_OK("gemini://host:1965/a/", "a"); + CASE_OK("gemini://host:1965/a/b", "a/b"); + CASE_OK("gemini://host:1965/a/b/", "a/b"); + + CASE_OK("gemini://host/a/b/../c/./d", "a/c/d"); + + // RFC 3986, 3.1. Scheme + // > ... An implementation + // > should accept uppercase letters as equivalent to lowercase in scheme + // > names (e.g., allow "HTTP" as well as "http") + CASE_OK("GeMiNi://host", ""); + +TEST_END() + +} // namespace vostok + + +extern "C" +int +main(int, char **) +{ + return vostok::test_request(); +} blob - 83054350c7bcd01ca738e4810455fc399ff75232 blob + 65f8d32addaca2f9201a5b5e06104c92c6b90769 --- vostok/Makefile +++ vostok/Makefile @@ -5,7 +5,7 @@ CXXFILES = transport.cc CXXFILES += error.cc CXXFILES += gemini.cc CXXFILES += args.cc -CXXFILES += parse_url.cc +CXXFILES += request.cc CXXFILES += open_file.cc CXXFILES += vostok.cc OFILES = ${CXXFILES:.cc=.o} blob - d81f5fd62b340269f56acd085a42c8a107fe12e0 (mode 644) blob + /dev/null --- vostok/parse_url.cc +++ /dev/null @@ -1,156 +0,0 @@ -/** URL normalization */ - -#include "parse_url.h" -#include "error.h" - -#include -#include -#include - - -namespace vostok -{ - -namespace -{ - -const auto gemini_scheme = cut_null("gemini://"); -inline bool is_gemini_scheme(const std::vector &url) -{ - return std::equal( - gemini_scheme.begin(), - gemini_scheme.end(), - url.begin(), - [](char v1, char v2){return std::tolower(v1) == std::tolower(v2);} - ); -} - -class PathNormalization -{ -public: - using Components = std::list< Span >; - - url_normalization_result - operator() ( - std::vector::const_iterator p, - std::vector &url - ); - -protected: - url_normalization_result on_component(); - url_normalization_result on_component_ok() - { - m_inprogress = decltype(m_inprogress){}; - return url_ok; - } - - void fill(std::vector &url) const; - -private: - Components::value_type m_inprogress; - Components m_result; -}; - - -url_normalization_result -PathNormalization::operator() ( - std::vector::const_iterator p, - std::vector &url -) -{ - m_inprogress = Components::value_type{nullptr, 0}; - m_result.clear(); - - for (; p != url.cend(); ++p) - { - if (*p != '/') - { - if (m_inprogress.size()) - m_inprogress = decltype(m_inprogress){m_inprogress.begin(), m_inprogress.size() + 1}; - else - m_inprogress = decltype(m_inprogress){&*p, 1}; - continue; - } - - const auto parse_result = on_component(); - if (parse_result != url_ok) - return parse_result; - } - const auto parse_result = on_component(); - if (parse_result != url_ok) - return parse_result; - - fill(url); - return url_ok; -} - - -url_normalization_result PathNormalization::on_component() -{ - if ((m_inprogress.size() == 0) || (m_inprogress.size() == 1 && m_inprogress[0] == '.')) - { - return on_component_ok(); - } - if (m_inprogress.size() == 2 && m_inprogress[0] == '.' && m_inprogress[1] == '.') - { - if (m_result.empty()) - return url_root_traverse; - - m_result.pop_back(); - return on_component_ok(); - } - - m_result.push_back(std::move(m_inprogress)); - return on_component_ok(); -} - -void PathNormalization::fill(std::vector &url) const -{ - auto current = url.begin(); - for (auto it = m_result.cbegin(); it != m_result.cend(); ++it) - { - if (current != url.begin()) - { - // non-first path component: insert separator - *current = '/'; - ++current; - } - current = std::copy(it->begin(), it->end(), current); - } - *current = '\0'; - ++current; - - url.resize(current - url.begin()); -} - -} // namespace - - -url_normalization_result -extract_url_path( - /* in/out */ std::vector &url -) -{ - // check and skip scheme - if (url.size() < gemini_scheme.size()) - return url_too_short; - if (!is_gemini_scheme(url)) - return url_non_gemini; - auto current = url.cbegin() + gemini_scheme.size(); - - // skip domain[:port] - for (; current != url.cend(); ++current) - { - if (*current == '/') - { - ++current; - break; - } - } - - // normalize '.' and '..' - return PathNormalization{}(current, url); -} - - -} // namespace vostok blob - /dev/null blob + 8a5780ade2c7ca8084f2837d2d5a24189be0f2d0 (mode 644) --- /dev/null +++ vostok/request.cc @@ -0,0 +1,193 @@ +/** URL normalization */ + +#include "request.h" +#include "gemini.h" +#include "error.h" +#include "utils.h" + +#include +#include + + +namespace vostok +{ + +namespace +{ + +const auto gemini_scheme = cut_null("gemini://"); +inline bool is_gemini_scheme(const std::vector &url) +{ + return std::equal( + gemini_scheme.begin(), + gemini_scheme.end(), + url.begin(), + [](char v1, char v2){return std::tolower(v1) == std::tolower(v2);} + ); +} + + +bool cut_crlf(std::vector &buffer) +{ + // > servers MUST ignore anything sent after the first occurrence of a . + for (auto current = buffer.cbegin(); current != buffer.cend(); ++current) + { + const auto next = current + 1; + if (next == buffer.cend()) + break; + + if (*current == gemini::CRLF[0] && *next == gemini::CRLF[1]) + { + buffer.resize(current - buffer.cbegin()); + return true; + } + } + return false; +} + + +class PathNormalization +{ +public: + using Components = std::list< Span >; + + Request::ParseResult + operator() ( + std::vector::const_iterator p, + std::vector &url + ); + +protected: + Request::ParseResult on_component(); + Request::ParseResult on_component_ok() + { + m_inprogress = decltype(m_inprogress){}; + return Request::URL_OK; + } + + void fill(std::vector &url) const; + +private: + Components::value_type m_inprogress; + Components m_result; +}; + + +Request::ParseResult +PathNormalization::operator() ( + std::vector::const_iterator p, + std::vector &url +) +{ + m_inprogress = Components::value_type{nullptr, 0}; + m_result.clear(); + + for (; p != url.cend(); ++p) + { + if (*p != '/') + { + if (m_inprogress.size()) + m_inprogress = decltype(m_inprogress){m_inprogress.begin(), m_inprogress.size() + 1}; + else + m_inprogress = decltype(m_inprogress){&*p, 1}; + continue; + } + + const auto parse_result = on_component(); + if (parse_result != Request::URL_OK) + return parse_result; + } + const auto parse_result = on_component(); + if (parse_result != Request::URL_OK) + return parse_result; + + fill(url); + return Request::URL_OK; +} + + +Request::ParseResult PathNormalization::on_component() +{ + if ((m_inprogress.size() == 0) || (m_inprogress.size() == 1 && m_inprogress[0] == '.')) + { + return on_component_ok(); + } + if (m_inprogress.size() == 2 && m_inprogress[0] == '.' && m_inprogress[1] == '.') + { + if (m_result.empty()) + return Request::URL_ROOT_TRAVERSE; + + m_result.pop_back(); + return on_component_ok(); + } + + m_result.push_back(std::move(m_inprogress)); + return on_component_ok(); +} + +void PathNormalization::fill(std::vector &url) const +{ + auto current = url.begin(); + for (auto it = m_result.cbegin(); it != m_result.cend(); ++it) + { + if (current != url.begin()) + { + // non-first path component: insert separator + *current = '/'; + ++current; + } + current = std::copy(it->begin(), it->end(), current); + } + *current = '\0'; + ++current; + + url.resize(current - url.begin()); +} + +} // namespace + + +std::vector &Request::get_buffer() +{ + m_buffer.resize(gemini::MAX_REQUEST_LENGTH); + return m_buffer; +} + + +Request::ParseResult Request::parse() +{ + if (!cut_crlf(m_buffer)) + return BAD_REQUEST; + + // check and skip scheme + if (m_buffer.size() < gemini_scheme.size()) + return URL_TOO_SHORT; + if (!is_gemini_scheme(m_buffer)) + return URL_NON_GEMINI; + auto current = m_buffer.cbegin() + gemini_scheme.size(); + + // skip domain[:port] + for (; current != m_buffer.cend(); ++current) + { + if (*current == '/') + { + ++current; + break; + } + } + + // normalize '.' and '..' + return PathNormalization{}(current, m_buffer); +} + + +const std::vector &Request::get_path() const +{ + assert(m_buffer.size() > 0); + assert(m_buffer.size() < gemini::MAX_REQUEST_LENGTH); + assert(m_buffer[m_buffer.size() - 1] == '\0'); + return m_buffer; +} + + +} // namespace vostok blob - 4fece0d30541a02b52be7cfc58bc84d700aaaab7 (mode 644) blob + /dev/null --- vostok/parse_url.h +++ /dev/null @@ -1,32 +0,0 @@ -/** URL normalization */ - -#include "utils.h" -#include "gemini.h" - -#include - - -#pragma once - - -namespace vostok -{ - - -enum url_normalization_result -{ - url_ok, - - url_too_short, - url_non_gemini, - url_root_traverse, -}; - -/** Extract normalized path from URL as null-terminated string (inplace) */ -url_normalization_result -extract_url_path( - /* in/out */ std::vector &url -); - - -} // namespace vostok blob - /dev/null blob + 980e20c255154fbbd82759f47d31da52140da1e2 (mode 644) --- /dev/null +++ vostok/request.h @@ -0,0 +1,54 @@ +/** Gemini request parser */ + +#include + +#pragma once + + +namespace vostok +{ + + +class Request +{ +public: + /* Get buffer for incoming Gemini request */ + std::vector &get_buffer(); + + /* Parse incoming Gemini request */ + enum ParseResult + { + URL_OK, + + BAD_REQUEST, + URL_TOO_SHORT, + URL_NON_GEMINI, + URL_ROOT_TRAVERSE, + }; + ParseResult parse(); + + + /* Get normalized path (if parse() return URL_OK) as zero-terminated string */ + const std::vector &get_path() const; + +private: + std::vector m_buffer; +}; + +enum url_normalization_result +{ + url_ok, + + url_too_short, + url_non_gemini, + url_root_traverse, +}; + +/** Extract normalized path from URL as null-terminated string (inplace) */ +url_normalization_result +extract_url_path( + /* in/out */ std::vector &url +); + + +} // namespace vostok blob - 88f9a8d0e00e67af58036b1876e9f289344e7fcd blob + ce1c426013b7734b3cb83baba2ea6915037fc386 --- vostok/transport.cc +++ vostok/transport.cc @@ -14,6 +14,7 @@ namespace transport namespace { + constexpr auto protocols = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3; @@ -40,26 +41,6 @@ class PrintIfError (private) }; -bool read(NotNull ctx, std::vector &buff) -{ - ssize_t ret{}; - for (; ; ) - { - ret = tls_read(ctx, buff.data(), buff.size()); - if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) - continue; - break; - } - if (ret == -1) - { - error::occurred("TLS read", PrintIfError{tls_error(ctx)}); - return false; - } - buff.resize(ret); - return true; -} - - } // namespace @@ -75,7 +56,7 @@ bool init() } -void create_server(NotNull cert_file, NotNull key_file, ContextPtr &ret_ctx) +Server::Server(NotNull cert_file, NotNull key_file) { ConfigPtr cfg{tls_config_new()}; if (!cfg) @@ -125,7 +106,7 @@ void create_server(NotNull cert_file, NotNul return; } - ctx.swap(ret_ctx); + ctx.swap(*this); } @@ -153,49 +134,34 @@ AcceptedClient::AcceptedClient(int server_socket, stru } -bool read_request(NotNull ctx, std::vector &url) +bool recv( + /* in */ NotNull ctx, + /* in/out */ std::vector &buff +) { - // - url.resize(gemini::MAX_REQUEST_LENGTH); - if (!read(ctx, url)) - return false; - - for (auto current = url.begin(); current < url.end(); ++current) + ssize_t ret{}; + for (; ; ) { - const auto next = (current + 1); - if (next == url.end()) - break; - - if (*current == gemini::CRLF[0] && *next == gemini::CRLF[1]) - { - // > servers MUST ignore anything sent after the first occurrence of a . - url.resize(current - url.begin()); - return true; - } + ret = tls_read(ctx, buff.data(), buff.size()); + if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) + continue; + break; } - - error::occurred("Parse request", error::None{}); - return false; -} - - -bool send_response(NotNull ctx, gemini::Status status, Span meta) -{ - // - if (!send(ctx, status)) + if (ret == -1) + { + error::occurred("TLS read", PrintIfError{tls_error(ctx)}); return false; - if (!send(ctx, gemini::SPACE)) - return false; - if (meta.size()) - if (!send(ctx, meta)) - return false; - if (!send(ctx, gemini::CRLF)) - return false; + } + buff.resize(ret); return true; } -bool send(NotNull ctx, Span buff) +bool +send( + /* in */ NotNull ctx, + /* in */ Span buff +) { ssize_t ret{0}; while (buff.size() > 0) blob - 102e54212f998f9aaa530cede0eef43433d2b84b blob + e4e5c5bc74e604ca45c322c02d57bed199bdacdf --- vostok/transport.h +++ vostok/transport.h @@ -1,7 +1,6 @@ /** Wrap libtls for gemini protocol */ #include "utils.h" -#include "gemini.h" #include #include @@ -29,7 +28,11 @@ bool init(); /* Create new TLS context for gemini server */ -void create_server(NotNull cert_file, NotNull key_file, ContextPtr &server_ctx); +class Server : public ContextPtr +{ +public: + Server(NotNull cert_file, NotNull key_file); +}; /** Accept new client */ @@ -49,17 +52,20 @@ class AcceptedClient (private) }; -/** Read genimi request and return url */ -bool read_request(NotNull ctx, std::vector &url); +/** Receive raw bytes */ +bool +recv( + /* in */ NotNull ctx, + /* in/out */ std::vector &buff +); -/** Write gemini response */ -bool send_response(NotNull ctx, gemini::Status status, Span meta); - - /** Send raw bytes */ -bool send(NotNull ctx, Span buff); +bool +send( + /* in */ NotNull ctx, + /* in */ Span buff +); - } // namespace transport } // namespace vostok blob - c1151107c5b33b391e6681df5f6523245e2d71ed blob + 95ed0e83b4699dcba4526fc6e971df47fb692a6c --- vostok/vostok.cc +++ vostok/vostok.cc @@ -3,8 +3,9 @@ #include "error.h" #include "transport.h" #include "args.h" -#include "parse_url.h" +#include "request.h" #include "open_file.h" +#include "gemini.h" #include #include @@ -40,49 +41,67 @@ const char sz_temporary_failure[] = "Temporary failure const auto temporary_failure = cut_null(sz_temporary_failure); } // namespace meta +bool send_response(NotNull ctx, gemini::Status status, Span meta) +{ + // + if (!transport::send(ctx, status)) + return false; + if (!transport::send(ctx, gemini::SPACE)) + return false; + if (meta.size()) + { + if (!transport::send(ctx, meta)) + return false; + } + if (!transport::send(ctx, gemini::CRLF)) + return false; + return true; +} + + void client_thread(const transport::AcceptedClient *accepted_client, int directory_fd) { assert(accepted_client); std::unique_ptr accepted_client_deleter{accepted_client}; - std::vector url; - if (!transport::read_request(accepted_client->get_ctx(), url)) - { - transport::send_response(accepted_client->get_ctx(), gemini::STATUS_59_BAD_REQUEST, meta::bad_request); + Request request; + if (!transport::recv(accepted_client->get_ctx(), request.get_buffer())) return; - } - - const auto parse_result = extract_url_path(url); + const auto parse_result = request.parse(); switch (parse_result) { - case url_too_short: - error::occurred("parse URL", []{error::g_log << meta::sz_url_too_short;}); - transport::send_response(accepted_client->get_ctx(), gemini::STATUS_59_BAD_REQUEST, meta::url_too_short); + case Request::BAD_REQUEST: + error::occurred("Parse request", []{error::g_log << meta::sz_bad_request;}); + send_response(accepted_client->get_ctx(), gemini::STATUS_59_BAD_REQUEST, meta::bad_request); return; - case url_non_gemini: - error::occurred("parse URL", []{error::g_log << meta::sz_non_gemini;}); - transport::send_response(accepted_client->get_ctx(), gemini::STATUS_53_PROXY_REQUEST_REFUSED, meta::non_gemini); + case Request::URL_TOO_SHORT: + error::occurred("Parse request", []{error::g_log << meta::sz_url_too_short;}); + send_response(accepted_client->get_ctx(), gemini::STATUS_59_BAD_REQUEST, meta::url_too_short); return; - case url_root_traverse: - error::occurred("parse URL", []{error::g_log << meta::sz_root_traverse;}); - transport::send_response(accepted_client->get_ctx(), gemini::STATUS_50_PERMANENT_FAILURE, meta::root_traverse); + case Request::URL_NON_GEMINI: + error::occurred("Parse request", []{error::g_log << meta::sz_non_gemini;}); + send_response(accepted_client->get_ctx(), gemini::STATUS_53_PROXY_REQUEST_REFUSED, meta::non_gemini); return; + case Request::URL_ROOT_TRAVERSE: + error::occurred("Parse request", []{error::g_log << meta::sz_root_traverse;}); + send_response(accepted_client->get_ctx(), gemini::STATUS_50_PERMANENT_FAILURE, meta::root_traverse); + return; - case url_ok: + case Request::URL_OK: break; } UniqueFd opened_file{}; - const auto open_file_result = open_file(directory_fd, url.data(), opened_file); + const auto open_file_result = open_file(directory_fd, request.get_path().data(), opened_file); switch (open_file_result) { case file_not_found: - transport::send_response(accepted_client->get_ctx(), gemini::STATUS_51_NOT_FOUND, meta::not_found); + send_response(accepted_client->get_ctx(), gemini::STATUS_51_NOT_FOUND, meta::not_found); return; case file_opening_error: - transport::send_response(accepted_client->get_ctx(), gemini::STATUS_40_TEMPORARY_FAILURE, meta::temporary_failure); + send_response(accepted_client->get_ctx(), gemini::STATUS_40_TEMPORARY_FAILURE, meta::temporary_failure); return; case file_opened: @@ -91,7 +110,7 @@ void client_thread(const transport::AcceptedClient *ac } // > If is an empty string, the MIME type MUST default to "text/gemini; charset=utf-8". - transport::send_response(accepted_client->get_ctx(), gemini::STATUS_20_SUCCESS, {}); + send_response(accepted_client->get_ctx(), gemini::STATUS_20_SUCCESS, {}); std::vector buffer; buffer.resize(64 * 1024); @@ -101,9 +120,9 @@ void client_thread(const transport::AcceptedClient *ac if (ret == -1) { error::occurred( - [&url] + [&request] { - error::g_log << "Read file \"" << url.data() << "\""; + error::g_log << "Read file \"" << request.get_path().data() << "\""; }, error::Print{} ); @@ -118,7 +137,7 @@ void client_thread(const transport::AcceptedClient *ac if (readed < buffer.size()) break; } - error::g_log << "20 " << "\"" << url.data() << "\"" << std::endl; + error::g_log << "20 " << "\"" << request.get_path().data() << "\"" << std::endl; } @@ -166,8 +185,7 @@ bool main(const CommandLineArguments &args) if (!transport::init()) return false; - transport::ContextPtr server_ctx; - transport::create_server(args.cert_file, args.key_file, server_ctx); + transport::Server server_ctx{args.cert_file, args.key_file}; if (!server_ctx) return false;