From 03ae11a8427af4e28da40e5bd688e666ef63728d Mon Sep 17 00:00:00 2001 From: tastytea Date: Thu, 9 Jun 2022 04:28:50 +0200 Subject: [PATCH] Parse REQUEST_URI --- src/main.cpp | 29 ++++++++++++---- src/request.cpp | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ src/request.hpp | 39 +++++++++++++++++++++ 3 files changed, 153 insertions(+), 6 deletions(-) create mode 100644 src/request.cpp create mode 100644 src/request.hpp diff --git a/src/main.cpp b/src/main.cpp index 6c668f4..071c143 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,9 +16,12 @@ #include "config.hpp" #include "helpers.hpp" +#include "request.hpp" #include "version.hpp" +#include #include +#include #include int main(int /*argc*/, char * /*argv*/[]) { @@ -26,14 +29,28 @@ int main(int /*argc*/, char * /*argv*/[]) { std::cout << "Server: libravatarserv/" << version << '\n'; - const std::string uri{read_env("REQUEST_URI")}; - if (uri.empty()) { - std::cout << "Status: 400 Bad Request\n\n"; - std::cerr << "ERROR: REQUEST_URI is empty.\n"; + try { + const std::string uri{read_env("REQUEST_URI")}; + if (uri.empty()) { + std::cout << "Status: 400 Bad Request\n\n"; + throw std::runtime_error{"REQUEST_URI is empty"}; + } + + auto cfg{config::read()}; + + auto req{request::parse(uri)}; + if (req.fallback.empty()) { + req.fallback = cfg.default_fallback; + } + std::cout << " HASH: " << req.hash << "\n SIZE: " << req.size + << "\n FALLBACK: " << req.fallback << '\n'; + + } catch (const std::runtime_error &e) { + if (std::strlen(e.what()) != 0) { + std::cerr << "ERROR: " << e.what() << '\n'; + } return 1; } - auto cfg{config::read()}; - return 0; } diff --git a/src/request.cpp b/src/request.cpp new file mode 100644 index 0000000..12eb073 --- /dev/null +++ b/src/request.cpp @@ -0,0 +1,91 @@ +/* This file is part of libravatarserv. + * Copyright © 2022 tastytea + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "request.hpp" + +#include +#include +#include +#include +#include +#include + +namespace libravatarserv::request { + +request parse(const std::string_view uri) { + constexpr std::uint8_t offset{8}; + if (uri.substr(0, offset) != "/avatar/" + || uri.find("..", offset) != std::string_view::npos) { + std::cout << "Status: 400 Bad Request\n\n"; + throw std::runtime_error{"Invalid URL"}; + } + + request req; + req.size = 80; + + size_t pos{uri.find('?')}; + if (pos == std::string_view::npos) { + pos = uri.size(); + } + req.hash.resize(pos - offset); + std::transform(uri.begin() + offset, uri.begin() + pos, req.hash.begin(), + ::tolower); + + if (pos != uri.size()) { + std::string uri_rest; + uri_rest.resize(uri.size() - pos); + std::transform(uri.begin() + pos, uri.end(), uri_rest.begin(), + ::tolower); + + auto strsize{get_parameter(uri_rest, "s")}; + if (strsize.empty()) { + strsize = get_parameter(uri_rest, "size"); + } + if (!strsize.empty()) { + try { + req.size = static_cast(std::stoul(strsize.data())); + if (req.size > 512) { + req.size = 512; + } else if (req.size < 1) { + req.size = 80; + } + } catch (...) {} + } + + req.fallback = get_parameter(uri_rest, "d"); + if (req.fallback.empty()) { + req.fallback = get_parameter(uri_rest, "default"); + } + } + + return req; +} + +std::string_view get_parameter(const std::string_view uri, + const std::string ¶meter) { + size_t pos{uri.find("?" + parameter + "=")}; + if (pos == std::string_view::npos) { + pos = uri.find("&" + parameter + "="); + } + if (pos != std::string_view::npos) { + pos += (2 + parameter.length()); + return uri.substr(pos, uri.find('&', pos)); + } + + return {}; +} + +} // namespace libravatarserv::request diff --git a/src/request.hpp b/src/request.hpp new file mode 100644 index 0000000..1b868cc --- /dev/null +++ b/src/request.hpp @@ -0,0 +1,39 @@ +/* This file is part of libravatarserv. + * Copyright © 2022 tastytea + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LIBRAVATARSERV_REQUEST_HPP +#define LIBRAVATARSERV_REQUEST_HPP + +#include +#include +#include + +namespace libravatarserv::request { + +struct request { + std::string hash; + std::int16_t size; + std::string fallback; +}; + +[[nodiscard]] request parse(std::string_view uri); + +[[nodiscard]] std::string_view get_parameter(std::string_view uri, + const std::string ¶meter); + +} // namespace libravatarserv::request + +#endif // LIBRAVATARSERV_REQUEST_HPP