commit 5b1ce226061f6be85ef5848a7df637ec2f069704 from: Aleksey Ryndin date: Fri Aug 11 21:12:02 2023 UTC Parse URL (initial implemetation) commit - 679cbc0acc9ceb3822cb8574013f0bfcb6460b0d commit + 5b1ce226061f6be85ef5848a7df637ec2f069704 blob - 313082479108a8f36277c1ba6d8cb506e91fe54f blob + cb103a9a567aed21307000a84fbdb6a952ee0c64 --- shared/transport.cc +++ shared/transport.cc @@ -47,8 +47,9 @@ tcb::span read(not_null ctx, tcb:: const std::array CRLF{'\r', '\n'}; const std::array SPACE{' '}; -const std::array STATUS_20_SUCCESS{'2', '0'}; -const std::array STATUS_59_BAD_REQUEST{'5', '9'}; +const status_t STATUS_20_SUCCESS{'2', '0'}; +const status_t STATUS_53_PROXY_REQUEST_REFUSED{'5', '3'}; +const status_t STATUS_59_BAD_REQUEST{'5', '9'}; bool init() @@ -165,7 +166,7 @@ tcb::span read_request(not_null ct } -bool send_response(not_null ctx, std::array status, tcb::span meta) +bool send_response(not_null ctx, status_t status, tcb::span meta) { // > std::array buff; @@ -189,7 +190,7 @@ bool send(not_null ctx, tcb::span{&buff[ret], buff.size() - ret}; + buff = decltype(buff){&buff[ret], buff.size() - ret}; } if (ret == -1) { blob - b7518fc07c0e247aef385cbc777f032258efc06c blob + 137cf9aaf8f4cdfe634162e8481daef491e79f28 --- shared/transport.h +++ shared/transport.h @@ -23,8 +23,10 @@ constexpr auto MAX_URL_LENGTH = 1024; constexpr auto MAX_META_LENGTH = 1024; extern const std::array CRLF; -extern const std::array STATUS_20_SUCCESS; -extern const std::array STATUS_59_BAD_REQUEST; +using status_t = std::array; +extern const status_t STATUS_20_SUCCESS; +extern const status_t STATUS_53_PROXY_REQUEST_REFUSED; +extern const status_t STATUS_59_BAD_REQUEST; constexpr auto MAX_REQUEST_LENGTH = MAX_URL_LENGTH + CRLF.size(); @@ -87,7 +89,7 @@ tcb::span read_request(not_null ct /** Write gemini response */ -bool send_response(not_null ctx, std::array status, tcb::span meta); +bool send_response(not_null ctx, status_t status, tcb::span meta); /** Send raw bytes */ blob - 66f41bfe0404e451318143c2be6792916a4a1513 blob + 8244dc2b89c635fe09a9d5489f4765b3ff222a03 --- vostokd/vostokd.cc +++ vostokd/vostokd.cc @@ -30,10 +30,14 @@ constexpr tcb::span cut_null(const char (& namespace meta { -const auto badrequest = cut_null("Bad request"); +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"); } // namespace meta +const auto gemini_scheme = cut_null("gemini://"); + struct command_line_arguments { not_null m_addr{"127.0.0.1"}; @@ -111,18 +115,45 @@ void client_thread(transport::accepted_context::value assert(ctx); std::array buffer; - const auto url = transport::read_request(ctx.get_ctx(), buffer); + auto url = transport::read_request(ctx.get_ctx(), buffer); + if (!url.size()) + { + transport::send_response(ctx.get_ctx(), transport::STATUS_59_BAD_REQUEST, meta::bad_request); + return; + } + // check and skip scheme + if (url.size() < gemini_scheme.size()) + { + transport::send_response(ctx.get_ctx(), transport::STATUS_59_BAD_REQUEST, meta::url_too_short); + return; + } + if (!std::equal(gemini_scheme.begin(), gemini_scheme.end(), url.begin())) + { + transport::send_response(ctx.get_ctx(), transport::STATUS_53_PROXY_REQUEST_REFUSED, meta::non_gemini); + return; + } + url = decltype(url){&url[gemini_scheme.size()], url.size() - 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 = decltype(url){&url[skip_len], url.size() - skip_len}; + break; + } + } + if (current == url.end()) + url = decltype(url){}; + error::g_log << "Requested URL: \""; for (auto c : url) error::g_log << c; error::g_log << "\"" << std::endl; - if (!url.size()) - { - transport::send_response(ctx.get_ctx(), transport::STATUS_59_BAD_REQUEST, meta::badrequest); - return; - } // > If is an empty string, the MIME type MUST default to "text/gemini; charset=utf-8". transport::send_response(ctx.get_ctx(), transport::STATUS_20_SUCCESS, tcb::span{});