commit 9a6cb9d51e84cd86ea58319a30046fc2f434246d from: Aleksey Ryndin date: Mon Aug 14 15:30:21 2023 UTC Refactoring: URL normalization to separate module commit - 59d5920624133077e335a537038eca69788aed94 commit + 9a6cb9d51e84cd86ea58319a30046fc2f434246d blob - /dev/null blob + e124e72c5414367ddacc70318254ba0945a59634 (mode 644) --- /dev/null +++ shared/cut_null @@ -0,0 +1,20 @@ +/** Remove null terminating character */ + + +#pragma once + + +namespace vostok +{ + + +/** Remove null terminating character and return as span */ +template +constexpr span cut_null(const char (&arr)[N]) +{ + static_assert(N > 0, "!(N > 0)"); + return span{arr, N - 1}; +} + + +} // vostok blob - ac1dcb2ed0c78c1415494b53d0518659100a06fb blob + fb1b6382ef772db709bc9de4897bc5b28d551339 --- shared/gemini.cc +++ shared/gemini.cc @@ -13,9 +13,8 @@ const std::array CRLF{'\r', '\n'}; const std::array SPACE{' '}; const status_t STATUS_20_SUCCESS{'2', '0'}; - +const status_t STATUS_50_PERMANENT_FAILURE{'5', '0'}; const status_t STATUS_53_PROXY_REQUEST_REFUSED{'5', '3'}; - const status_t STATUS_59_BAD_REQUEST{'5', '9'}; blob - 350150182502bef33d71ddafd969c9b088bfc363 blob + 2230496a1499e62f60cfa32596d71516e0576f7f --- shared/gemini.h +++ shared/gemini.h @@ -19,6 +19,7 @@ extern const std::array SPACE; using status_t = std::array; extern const status_t STATUS_20_SUCCESS; +extern const status_t STATUS_50_PERMANENT_FAILURE; extern const status_t STATUS_53_PROXY_REQUEST_REFUSED; extern const status_t STATUS_59_BAD_REQUEST; blob - 08a5d754c5e4e8f433a230fce92b6a1438a8ade7 blob + b9362c84dc012a844b06927892c48b03ef6817a1 --- shared/span +++ shared/span @@ -1,5 +1,8 @@ /** Simply std::span implementation for C++11 */ +#include +#include + #pragma once blob - 4f075e2d60ec499d9d3872b8bc76526e840a77b8 blob + d80d60dae0f1e151f0e6f93adba30d597190355f --- shared/transport.cc +++ shared/transport.cc @@ -1,7 +1,7 @@ /** Wrap libtls for gemini protocol */ -#include -#include +#include "error.h" +#include "transport.h" namespace vostok blob - 9f0cf3c93d468653b56bbdb97def9bd47655f70a blob + c842f06d2f8051e40b5b6eafeeb763195a489e99 --- shared/transport.h +++ shared/transport.h @@ -1,11 +1,10 @@ /** Wrap libtls for gemini protocol */ -#include -#include -#include -#include -#include - +#include "zstring" +#include "not_null" +#include "non_copiable" +#include "unique_fd" +#include "span" #include "gemini.h" #include blob - 9d3cb21091bc3851c1517677466510156fa16d9a blob + 673540d1db66509e57e5ec76656eeadd308f3a3f --- vostokd/Makefile +++ vostokd/Makefile @@ -9,14 +9,17 @@ HXXFILES += ${.PATH}../shared/unique_fd HXXFILES += ${.PATH}../shared/non_copiable HXXFILES += ${.PATH}../shared/unique_fd HXXFILES += ${.PATH}../shared/span +HXXFILES += ${.PATH}../shared/cut_null CXXFILES += ${.PATH}../shared/transport.cc HXXFILES += ${.PATH}../shared/transport.h CXXFILES += ${.PATH}../shared/error.cc HXXFILES += ${.PATH}../shared/error.h -CXXFILES += command_line_arguments.cc -HXXFILES += command_line_arguments.h CXXFILES += ${.PATH}../shared/gemini.cc HXXFILES += ${.PATH}../shared/gemini.h +CXXFILES += command_line_arguments.cc +HXXFILES += command_line_arguments.h +CXXFILES += url_normalization.cc +HXXFILES += url_normalization.h vostokd: ${CXXFILES} ${HXXFILES} ${CXX} ${CXXFLAGS} ${CXXFILES} -o vostokd blob - 2b52c558ec36360add80c7d61fc57b7506b75a58 blob + d2bbca5e948ac44e480e5a641162aa6e918408c8 --- vostokd/vostokd.cc +++ vostokd/vostokd.cc @@ -3,8 +3,10 @@ #include "error.h" #include "transport.h" #include "command_line_arguments.h" +#include "url_normalization.h" +#include "cut_null" +#include "unique_fd" -#include #include #include #include @@ -33,11 +35,10 @@ namespace meta const auto bad_request = cut_null("Bad request"); const auto url_too_short = cut_null("URL is too short"); const auto non_gemini = cut_null("No proxying to non-Gemini content"); +const auto root_traverse = cut_null("Wrong traverse"); } // namespace meta -const auto gemini_scheme = cut_null("gemini://"); - void client_thread(transport::accepted_context::value raw_value) { const transport::accepted_context ctx{raw_value}; @@ -51,35 +52,26 @@ void client_thread(transport::accepted_context::value return; } - // check and skip scheme - if (url.size() < gemini_scheme.size()) + span path_from_url; + const auto parse_result = parse_url(url, path_from_url); + switch (parse_result) { + case url_too_short: transport::send_response(ctx.get_ctx(), gemini::STATUS_59_BAD_REQUEST, meta::url_too_short); return; - } - if (!std::equal(gemini_scheme.begin(), gemini_scheme.end(), url.begin())) - { + case url_non_gemini: transport::send_response(ctx.get_ctx(), gemini::STATUS_53_PROXY_REQUEST_REFUSED, meta::non_gemini); return; - } - url = url.subspan(gemini_scheme.size()); + case url_root_traverse: + transport::send_response(ctx.get_ctx(), gemini::STATUS_50_PERMANENT_FAILURE, meta::root_traverse); + return; - // skip domain[:port] - const char *current = url.begin(); - for (; current != url.end(); ++current) - { - if (*current == '/') - { - const auto skip_len = (current + 1) - url.begin(); - url = url.subspan(skip_len); - break; - } + case url_ok: + break; } - if (current == url.end()) - url = decltype(url){}; error::g_log << "Requested URL: \""; - for (auto c : url) + for (auto c : path_from_url) error::g_log << c; error::g_log << "\"" << std::endl; blob - /dev/null blob + bbfa867bfda0bfeec12c6582edd249a27ade03a0 (mode 644) --- /dev/null +++ vostokd/url_normalization.cc @@ -0,0 +1,44 @@ +/** URL normalization */ + +#include "url_normalization.h" +#include "cut_null" + + +namespace vostok +{ +namespace +{ +const auto gemini_scheme = cut_null("gemini://"); +} // namespace + + + +url_normalization_result parse_url(span url, span &path) +{ + // check and skip scheme + if (url.size() < gemini_scheme.size()) + return url_too_short; + if (!std::equal(gemini_scheme.begin(), gemini_scheme.end(), url.begin())) + return url_non_gemini; + url = url.subspan(gemini_scheme.size()); + + // skip domain[:port] + const char *current = url.begin(); + for (; current != url.end(); ++current) + { + if (*current == '/') + { + const auto skip_len = (current + 1) - url.begin(); + url = url.subspan(skip_len); + break; + } + } + if (current == url.end()) + url = decltype(url){}; + + path = url; + return url_ok; +} + + +} // namespace vostok blob - /dev/null blob + 9d1800b61158c3a0756ab9deb68803d60e1d92eb (mode 644) --- /dev/null +++ vostokd/url_normalization.h @@ -0,0 +1,27 @@ +/** URL normalization */ + +#include "span" + + +#pragma once + + +namespace vostok +{ + + +enum url_normalization_result +{ + url_ok, + + url_too_short, + url_non_gemini, + url_root_traverse, +}; + + +/** Inplace: extract normalized path from URL */ +url_normalization_result parse_url(span url, span &path); + + +} // namespace vostok