commit - 59d5920624133077e335a537038eca69788aed94
commit + 9a6cb9d51e84cd86ea58319a30046fc2f434246d
blob - /dev/null
blob + e124e72c5414367ddacc70318254ba0945a59634 (mode 644)
--- /dev/null
+++ shared/cut_null
+/** Remove null terminating character */
+
+
+#pragma once
+
+
+namespace vostok
+{
+
+
+/** Remove null terminating character and return as span */
+template <size_t N>
+constexpr span<const char> cut_null(const char (&arr)[N])
+{
+ static_assert(N > 0, "!(N > 0)");
+ return span<const char>{arr, N - 1};
+}
+
+
+} // vostok
blob - ac1dcb2ed0c78c1415494b53d0518659100a06fb
blob + fb1b6382ef772db709bc9de4897bc5b28d551339
--- shared/gemini.cc
+++ shared/gemini.cc
const std::array<char, 1> 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
using status_t = std::array<char, 2>;
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
/** Simply std::span implementation for C++11 */
+#include <cassert>
+#include <array>
+
#pragma once
blob - 4f075e2d60ec499d9d3872b8bc76526e840a77b8
blob + d80d60dae0f1e151f0e6f93adba30d597190355f
--- shared/transport.cc
+++ shared/transport.cc
/** Wrap libtls for gemini protocol */
-#include <error.h>
-#include <transport.h>
+#include "error.h"
+#include "transport.h"
namespace vostok
blob - 9f0cf3c93d468653b56bbdb97def9bd47655f70a
blob + c842f06d2f8051e40b5b6eafeeb763195a489e99
--- shared/transport.h
+++ shared/transport.h
/** Wrap libtls for gemini protocol */
-#include <zstring>
-#include <not_null>
-#include <non_copiable>
-#include <unique_fd>
-#include <span>
-
+#include "zstring"
+#include "not_null"
+#include "non_copiable"
+#include "unique_fd"
+#include "span"
#include "gemini.h"
#include <tls.h>
blob - 9d3cb21091bc3851c1517677466510156fa16d9a
blob + 673540d1db66509e57e5ec76656eeadd308f3a3f
--- vostokd/Makefile
+++ vostokd/Makefile
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
#include "error.h"
#include "transport.h"
#include "command_line_arguments.h"
+#include "url_normalization.h"
+#include "cut_null"
+#include "unique_fd"
-#include <unique_fd>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
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};
return;
}
- // check and skip scheme
- if (url.size() < gemini_scheme.size())
+ span<char> 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
+/** URL normalization */
+
+#include "url_normalization.h"
+#include "cut_null"
+
+
+namespace vostok
+{
+namespace
+{
+const auto gemini_scheme = cut_null("gemini://");
+} // namespace <unnamed>
+
+
+
+url_normalization_result parse_url(span<char> url, span<char> &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
+/** 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<char> url, span<char> &path);
+
+
+} // namespace vostok