commit - 679cbc0acc9ceb3822cb8574013f0bfcb6460b0d
commit + 5b1ce226061f6be85ef5848a7df637ec2f069704
blob - 313082479108a8f36277c1ba6d8cb506e91fe54f
blob + cb103a9a567aed21307000a84fbdb6a952ee0c64
--- shared/transport.cc
+++ shared/transport.cc
const std::array<char, 2> CRLF{'\r', '\n'};
const std::array<char, 1> SPACE{' '};
-const std::array<char, 2> STATUS_20_SUCCESS{'2', '0'};
-const std::array<char, 2> 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()
}
-bool send_response(not_null<struct tls *> ctx, std::array<char, 2> status, tcb::span<const char> meta)
+bool send_response(not_null<struct tls *> ctx, status_t status, tcb::span<const char> meta)
{
// > <STATUS><SPACE><META><CR><LF>
std::array<char, status.size() + SPACE.size() + MAX_META_LENGTH + CRLF.size()> buff;
if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT)
continue;
break;
- buff = tcb::span<const char>{&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
constexpr auto MAX_META_LENGTH = 1024;
extern const std::array<char, 2> CRLF;
-extern const std::array<char, 2> STATUS_20_SUCCESS;
-extern const std::array<char, 2> STATUS_59_BAD_REQUEST;
+using status_t = std::array<char, 2>;
+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();
/** Write gemini response */
-bool send_response(not_null<struct tls *> ctx, std::array<char, 2> status, tcb::span<const char> meta);
+bool send_response(not_null<struct tls *> ctx, status_t status, tcb::span<const char> meta);
/** Send raw bytes */
blob - 66f41bfe0404e451318143c2be6792916a4a1513
blob + 8244dc2b89c635fe09a9d5489f4765b3ff222a03
--- vostokd/vostokd.cc
+++ vostokd/vostokd.cc
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<czstring> m_addr{"127.0.0.1"};
assert(ctx);
std::array<char, transport::MAX_REQUEST_LENGTH> 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 <META> 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<const char>{});