commit - 2f4289de81ec2f59955947bad61a6e9037183b63
commit + 75d552576b36e6005329689689467468eb3bebca
blob - 218df0d6e740a53293ed9e6279ada706563aa26d
blob + 28e9c68f37b47c27910971722aaf6032a9f213d6
--- .gitignore
+++ .gitignore
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
.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
-#include "parse_url.h"
-#include <string.h>
-#include <iostream>
-
-#include "tests.h"
-
-
-namespace vostok
-{
-namespace
-{
-template <std::size_t N>
-void init(std::vector<char> &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 <unnamed>
-
-TEST_START(test_extract_url_path)
- std::vector<char> 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
+#include "request.h"
+#include <string.h>
+#include <iostream>
+
+#include "tests.h"
+
+
+namespace vostok
+{
+namespace
+{
+template <std::size_t N>
+void fill_request_buffer(std::vector<char> &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 <unnamed>
+
+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
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
-/** URL normalization */
-
-#include "parse_url.h"
-#include "error.h"
-
-#include <list>
-#include <utility>
-#include <cctype>
-
-
-namespace vostok
-{
-
-namespace
-{
-
-const auto gemini_scheme = cut_null("gemini://");
-inline bool is_gemini_scheme(const std::vector<char> &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<const char> >;
-
- url_normalization_result
- operator() (
- std::vector<char>::const_iterator p,
- std::vector<char> &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<char> &url) const;
-
-private:
- Components::value_type m_inprogress;
- Components m_result;
-};
-
-
-url_normalization_result
-PathNormalization::operator() (
- std::vector<char>::const_iterator p,
- std::vector<char> &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<char> &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 <unnamed>
-
-
-url_normalization_result
-extract_url_path(
- /* in/out */ std::vector<char> &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
+/** URL normalization */
+
+#include "request.h"
+#include "gemini.h"
+#include "error.h"
+#include "utils.h"
+
+#include <list>
+#include <cctype>
+
+
+namespace vostok
+{
+
+namespace
+{
+
+const auto gemini_scheme = cut_null("gemini://");
+inline bool is_gemini_scheme(const std::vector<char> &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<char> &buffer)
+{
+ // > servers MUST ignore anything sent after the first occurrence of a <CR><LF>.
+ 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<const char> >;
+
+ Request::ParseResult
+ operator() (
+ std::vector<char>::const_iterator p,
+ std::vector<char> &url
+ );
+
+protected:
+ Request::ParseResult on_component();
+ Request::ParseResult on_component_ok()
+ {
+ m_inprogress = decltype(m_inprogress){};
+ return Request::URL_OK;
+ }
+
+ void fill(std::vector<char> &url) const;
+
+private:
+ Components::value_type m_inprogress;
+ Components m_result;
+};
+
+
+Request::ParseResult
+PathNormalization::operator() (
+ std::vector<char>::const_iterator p,
+ std::vector<char> &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<char> &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 <unnamed>
+
+
+std::vector<char> &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<char> &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
-/** URL normalization */
-
-#include "utils.h"
-#include "gemini.h"
-
-#include <vector>
-
-
-#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<char> &url
-);
-
-
-} // namespace vostok
blob - /dev/null
blob + 980e20c255154fbbd82759f47d31da52140da1e2 (mode 644)
--- /dev/null
+++ vostok/request.h
+/** Gemini request parser */
+
+#include <vector>
+
+#pragma once
+
+
+namespace vostok
+{
+
+
+class Request
+{
+public:
+ /* Get buffer for incoming Gemini request */
+ std::vector<char> &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<char> &get_path() const;
+
+private:
+ std::vector<char> 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<char> &url
+);
+
+
+} // namespace vostok
blob - 88f9a8d0e00e67af58036b1876e9f289344e7fcd
blob + ce1c426013b7734b3cb83baba2ea6915037fc386
--- vostok/transport.cc
+++ vostok/transport.cc
namespace
{
+
constexpr auto protocols = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
};
-bool read(NotNull<struct tls *> ctx, std::vector<char> &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 <unnamed>
}
-void create_server(NotNull<czstring> cert_file, NotNull<czstring> key_file, ContextPtr &ret_ctx)
+Server::Server(NotNull<czstring> cert_file, NotNull<czstring> key_file)
{
ConfigPtr cfg{tls_config_new()};
if (!cfg)
return;
}
- ctx.swap(ret_ctx);
+ ctx.swap(*this);
}
}
-bool read_request(NotNull<struct tls *> ctx, std::vector<char> &url)
+bool recv(
+ /* in */ NotNull<struct tls *> ctx,
+ /* in/out */ std::vector<char> &buff
+)
{
- // <URL><CR><LF>
- 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 <CR><LF>.
- 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<struct tls *> ctx, gemini::Status status, Span<const char> meta)
-{
- // <STATUS><SPACE><META><CR><LF>
- 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<struct tls *> ctx, Span<const char> buff)
+bool
+send(
+ /* in */ NotNull<struct tls *> ctx,
+ /* in */ Span<const char> buff
+)
{
ssize_t ret{0};
while (buff.size() > 0)
blob - 102e54212f998f9aaa530cede0eef43433d2b84b
blob + e4e5c5bc74e604ca45c322c02d57bed199bdacdf
--- vostok/transport.h
+++ vostok/transport.h
/** Wrap libtls for gemini protocol */
#include "utils.h"
-#include "gemini.h"
#include <vector>
#include <tls.h>
/* Create new TLS context for gemini server */
-void create_server(NotNull<czstring> cert_file, NotNull<czstring> key_file, ContextPtr &server_ctx);
+class Server : public ContextPtr
+{
+public:
+ Server(NotNull<czstring> cert_file, NotNull<czstring> key_file);
+};
/** Accept new client */
};
-/** Read genimi request and return url */
-bool read_request(NotNull<struct tls *> ctx, std::vector<char> &url);
+/** Receive raw bytes */
+bool
+recv(
+ /* in */ NotNull<struct tls *> ctx,
+ /* in/out */ std::vector<char> &buff
+);
-/** Write gemini response */
-bool send_response(NotNull<struct tls *> ctx, gemini::Status status, Span<const char> meta);
-
-
/** Send raw bytes */
-bool send(NotNull<struct tls *> ctx, Span<const char> buff);
+bool
+send(
+ /* in */ NotNull<struct tls *> ctx,
+ /* in */ Span<const char> buff
+);
-
} // namespace transport
} // namespace vostok<C-F12>
blob - c1151107c5b33b391e6681df5f6523245e2d71ed
blob + 95ed0e83b4699dcba4526fc6e971df47fb692a6c
--- vostok/vostok.cc
+++ vostok/vostok.cc
#include "error.h"
#include "transport.h"
#include "args.h"
-#include "parse_url.h"
+#include "request.h"
#include "open_file.h"
+#include "gemini.h"
#include <sys/socket.h>
#include <arpa/inet.h>
const auto temporary_failure = cut_null(sz_temporary_failure);
} // namespace meta
+bool send_response(NotNull<struct tls *> ctx, gemini::Status status, Span<const char> meta)
+{
+ // <STATUS><SPACE><META><CR><LF>
+ 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<const transport::AcceptedClient> accepted_client_deleter{accepted_client};
- std::vector<char> 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:
}
// > If <META> 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<char> buffer;
buffer.resize(64 * 1024);
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{}
);
if (readed < buffer.size())
break;
}
- error::g_log << "20 " << "\"" << url.data() << "\"" << std::endl;
+ error::g_log << "20 " << "\"" << request.get_path().data() << "\"" << std::endl;
}
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;