mirror of
https://github.com/KingDuckZ/kamokan.git
synced 2025-08-03 12:50:02 +00:00
Rename tawashi to duckbin.
The library that used to be "tawashi_implem" now is simply called tawashi.
This commit is contained in:
parent
2f00014758
commit
9cda58d0c0
67 changed files with 156 additions and 128 deletions
|
@ -1,27 +1,70 @@
|
|||
project(tawashi LANGUAGES CXX)
|
||||
project(tawashi VERSION 0.1.11 LANGUAGES CXX C)
|
||||
|
||||
option(TAWASHI_WITH_IP_LOGGING "Enable code in Tawashi that may result in users IPs being stored in the DB or in logs" ON)
|
||||
|
||||
find_package(Boost 1.53.0 REQUIRED COMPONENTS program_options filesystem system)
|
||||
find_package(SourceHighlight REQUIRED)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
main.cpp
|
||||
)
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE tawashi_implem
|
||||
#hack - add duckhandy to the project instead of picking from inside redis
|
||||
PRIVATE duckhandy
|
||||
)
|
||||
|
||||
set_target_properties(
|
||||
${PROJECT_NAME}
|
||||
PROPERTIES SUFFIX .cgi
|
||||
add_library(${PROJECT_NAME} STATIC
|
||||
split_get_vars.cpp
|
||||
response.cpp
|
||||
submit_paste_response.cpp
|
||||
cgi_environment_vars.cpp
|
||||
cgi_env.cpp
|
||||
num_to_token.cpp
|
||||
cgi_post.cpp
|
||||
escapist.cpp
|
||||
index_response.cpp
|
||||
pastie_response.cpp
|
||||
ini_file.cpp
|
||||
pathname/pathname.cpp
|
||||
response_factory.cpp
|
||||
list_highlight_langs.cpp
|
||||
settings_bag.cpp
|
||||
sanitized_utf8.cpp
|
||||
tiger.c
|
||||
error_response.cpp
|
||||
tawashi_exception.cpp
|
||||
http_header.cpp
|
||||
quick_submit_paste_response.cpp
|
||||
ip_utils.cpp
|
||||
mime_split.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PRIVATE ${TAWASHI_GEN_INCLUDE_DIR}
|
||||
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include
|
||||
PUBLIC ${TAWASHI_SOURCE_ROOT}/lib/kakoune
|
||||
PUBLIC ${TAWASHI_SOURCE_ROOT}/lib/mstch/include
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
LIBRARY DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
ARCHIVE DESTINATION lib/static
|
||||
target_include_directories(${PROJECT_NAME} SYSTEM
|
||||
PUBLIC ${Boost_INCLUDE_DIRS}
|
||||
PUBLIC ${TAWASHI_SOURCE_ROOT}/lib/better-enums
|
||||
PRIVATE ${SourceHighlight_INCLUDE_DIR}
|
||||
PRIVATE ${TAWASHI_SOURCE_ROOT}/lib/utf8_v2_3_4/source
|
||||
PUBLIC ${TAWASHI_SOURCE_ROOT}/lib/spdlog/include
|
||||
)
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE ${Boost_LIBRARIES}
|
||||
PRIVATE incredis
|
||||
PRIVATE ${SourceHighlight_LIBRARIES}
|
||||
PUBLIC mstch
|
||||
PRIVATE houdini
|
||||
PRIVATE pthread
|
||||
)
|
||||
target_compile_definitions(${PROJECT_NAME}
|
||||
PRIVATE BOOST_SPIRIT_USE_PHOENIX_V3=1
|
||||
PUBLIC $<$<CONFIG:Debug>:SPDLOG_DEBUG_ON>
|
||||
PUBLIC $<$<CONFIG:Debug>:SPDLOG_TRACE_ON>
|
||||
)
|
||||
target_compile_options(${PROJECT_NAME}
|
||||
PRIVATE -fdiagnostics-color=always
|
||||
)
|
||||
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tawashi_config.h.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/include/tawashi_config.h"
|
||||
)
|
||||
|
|
246
src/tawashi/cgi_env.cpp
Normal file
246
src/tawashi/cgi_env.cpp
Normal file
|
@ -0,0 +1,246 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cgi_env.hpp"
|
||||
#include "cgi_environment_vars.hpp"
|
||||
#include "duckhandy/lexical_cast.hpp"
|
||||
#include "tawashi_exception.hpp"
|
||||
#include <cassert>
|
||||
#include <ciso646>
|
||||
#include <boost/spirit/include/qi_core.hpp>
|
||||
#include <boost/spirit/include/qi_numeric.hpp>
|
||||
#include <boost/spirit/include/qi_plus.hpp>
|
||||
#include <boost/spirit/include/qi_raw.hpp>
|
||||
#include <boost/spirit/include/qi_lit.hpp>
|
||||
#include <boost/phoenix/object/construct.hpp>
|
||||
#include <boost/phoenix/bind/bind_member_function.hpp>
|
||||
#include <boost/phoenix/operator.hpp>
|
||||
#include <boost/fusion/adapted/struct.hpp>
|
||||
#include <boost/phoenix/stl/container.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
BOOST_FUSION_ADAPT_STRUCT(
|
||||
tawashi::cgi::Env::VersionInfo,
|
||||
(boost::string_ref, name)
|
||||
(uint16_t, major)
|
||||
(uint16_t, minor)
|
||||
);
|
||||
|
||||
namespace tawashi {
|
||||
namespace cgi {
|
||||
namespace {
|
||||
boost::optional<Env::VersionInfo> split_version (const std::string& parString) {
|
||||
namespace px = boost::phoenix;
|
||||
|
||||
using boost::spirit::ascii::space;
|
||||
using boost::spirit::qi::raw;
|
||||
using boost::spirit::qi::char_;
|
||||
using boost::string_ref;
|
||||
using VerNum = boost::spirit::qi::uint_parser<uint16_t, 10, 1, 1>;
|
||||
using RuleType = boost::spirit::qi::rule<std::string::const_iterator, string_ref(), boost::spirit::ascii::space_type>;
|
||||
using boost::spirit::_1;
|
||||
using boost::spirit::qi::_val;
|
||||
using boost::phoenix::begin;
|
||||
using boost::phoenix::size;
|
||||
using boost::phoenix::construct;
|
||||
using boost::make_optional;
|
||||
using boost::optional;
|
||||
|
||||
assert(not parString.empty());
|
||||
|
||||
auto beg = parString.cbegin();
|
||||
RuleType protocol = raw[+(char_ - '/')][_val = px::bind(&string_ref::substr, construct<string_ref>(px::ref(parString)), begin(_1) - px::ref(beg), size(_1))];
|
||||
VerNum ver_num;
|
||||
|
||||
auto it_curr = parString.cbegin();
|
||||
Env::VersionInfo retval;
|
||||
const bool parse_ret = boost::spirit::qi::phrase_parse(
|
||||
it_curr,
|
||||
parString.end(),
|
||||
protocol >> '/' >> ver_num >> '.' >> ver_num,
|
||||
space,
|
||||
retval
|
||||
);
|
||||
|
||||
if (parse_ret and parString.end() == it_curr)
|
||||
return make_optional(retval);
|
||||
else
|
||||
return optional<Env::VersionInfo>();
|
||||
}
|
||||
|
||||
std::size_t calculate_skip_path_length (const boost::string_ref& parPathInfo, const boost::string_ref& parBasePath) {
|
||||
const std::size_t base_path_tr_slash = (not parBasePath.empty() and parBasePath[parBasePath.size() - 1] == '/' ? 1 : 0);
|
||||
boost::string_ref base_path = parBasePath.substr(0, parBasePath.size() - base_path_tr_slash);
|
||||
SPDLOG_TRACE(spdlog::get("statuslog"), "calculating skip prefix for PATH_INFO=\"{}\", base path=\"{}\", parBasePath=\"{}\", base path trailing slash={}",
|
||||
std::string(parPathInfo.begin(), parPathInfo.end()),
|
||||
std::string(base_path.begin(), base_path.end()),
|
||||
std::string(parBasePath.begin(), parBasePath.end()),
|
||||
base_path_tr_slash
|
||||
);
|
||||
|
||||
if (boost::starts_with(parPathInfo, base_path)) {
|
||||
//account for the trailing slash in either base path and path info
|
||||
return std::min(parBasePath.size(), parPathInfo.size());
|
||||
}
|
||||
else {
|
||||
std::string str_base_path(parBasePath.begin(), parBasePath.end());
|
||||
std::string str_path(parPathInfo.begin(), parPathInfo.end());
|
||||
spdlog::get("statuslog")->error(
|
||||
"base path is not a prefix of PATH_INFO: base path={}, PATH_INFO={}, tawashi will most likely malfunction",
|
||||
str_base_path,
|
||||
str_path
|
||||
);
|
||||
return 1; //try with the default, maybe the user is lucky and it will work (ie base path = /)
|
||||
}
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
Env::Env(const char* const* parEnvList, const boost::string_ref& parBasePath) :
|
||||
m_cgi_env(cgi_environment_vars(parEnvList)),
|
||||
m_skip_path_info(calculate_skip_path_length(m_cgi_env[CGIVars::PATH_INFO], parBasePath)),
|
||||
m_request_method_type(RequestMethodType::_from_string(m_cgi_env[CGIVars::REQUEST_METHOD].data()))
|
||||
{
|
||||
{
|
||||
const std::string& content_type = m_cgi_env.at(CGIVars::CONTENT_TYPE);
|
||||
int parsed_chars;
|
||||
bool parse_ok;
|
||||
m_split_mime = string_to_mime(&content_type, parse_ok, parsed_chars);
|
||||
if (not parse_ok) {
|
||||
std::string err_msg = "Parsing failed at position " +
|
||||
std::to_string(parsed_chars) + " for input \"" +
|
||||
content_type + "\"";
|
||||
throw TawashiException(ErrorReasons::InvalidContentType, boost::string_ref(err_msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Env::~Env() noexcept = default;
|
||||
|
||||
const std::string& Env::auth_type() const {
|
||||
return m_cgi_env[CGIVars::AUTH_TYPE];
|
||||
}
|
||||
|
||||
std::size_t Env::content_length() const {
|
||||
using dhandy::lexical_cast;
|
||||
const std::string& value = m_cgi_env[CGIVars::CONTENT_LENGTH];
|
||||
return (value.empty() ? 0U : lexical_cast<std::size_t>(value));
|
||||
}
|
||||
|
||||
const std::string& Env::content_type() const {
|
||||
return m_cgi_env[CGIVars::CONTENT_TYPE];
|
||||
}
|
||||
|
||||
auto Env::gateway_interface() const -> boost::optional<VersionInfo> {
|
||||
return split_version(m_cgi_env[CGIVars::GATEWAY_INTERFACE]);
|
||||
}
|
||||
|
||||
boost::string_ref Env::path_info() const {
|
||||
const std::string& path = m_cgi_env[CGIVars::PATH_INFO];
|
||||
assert(m_skip_path_info <= path.size());
|
||||
return boost::string_ref(path).substr(m_skip_path_info);
|
||||
}
|
||||
|
||||
const std::string& Env::path_translated() const {
|
||||
return m_cgi_env[CGIVars::PATH_TRANSLATED];
|
||||
}
|
||||
|
||||
const std::string& Env::query_string() const {
|
||||
return m_cgi_env[CGIVars::QUERY_STRING];
|
||||
}
|
||||
|
||||
const std::string& Env::http_client_ip() const {
|
||||
return m_cgi_env[CGIVars::HTTP_CLIENT_IP];
|
||||
}
|
||||
|
||||
const std::string& Env::http_x_forwarded_for() const {
|
||||
return m_cgi_env[CGIVars::HTTP_X_FORWARDED_FOR];
|
||||
}
|
||||
|
||||
const std::string& Env::remote_addr() const {
|
||||
return m_cgi_env[CGIVars::REMOTE_ADDR];
|
||||
}
|
||||
|
||||
const std::string& Env::remote_host() const {
|
||||
return m_cgi_env[CGIVars::REMOTE_HOST];
|
||||
}
|
||||
|
||||
const std::string& Env::remote_ident() const {
|
||||
return m_cgi_env[CGIVars::REMOTE_IDENT];
|
||||
}
|
||||
|
||||
const std::string& Env::remote_user() const {
|
||||
return m_cgi_env[CGIVars::REMOTE_USER];
|
||||
}
|
||||
|
||||
RequestMethodType Env::request_method() const {
|
||||
return m_request_method_type;
|
||||
}
|
||||
|
||||
const std::string& Env::script_name() const {
|
||||
return m_cgi_env[CGIVars::SCRIPT_NAME];
|
||||
}
|
||||
|
||||
const std::string& Env::server_name() const {
|
||||
return m_cgi_env[CGIVars::SERVER_NAME];
|
||||
}
|
||||
|
||||
bool Env::https() const {
|
||||
const std::string& val = m_cgi_env[CGIVars::HTTPS];
|
||||
return val.size() == 2 and (
|
||||
val == "on" or val == "ON" or val == "oN" or val == "On"
|
||||
);
|
||||
}
|
||||
|
||||
uint16_t Env::server_port() const {
|
||||
using dhandy::lexical_cast;
|
||||
const std::string& value = m_cgi_env[CGIVars::SERVER_PORT];
|
||||
return (value.empty() ? 0U : lexical_cast<uint16_t>(value));
|
||||
}
|
||||
|
||||
auto Env::server_protocol() const -> boost::optional<VersionInfo> {
|
||||
return split_version(m_cgi_env[CGIVars::SERVER_PROTOCOL]);
|
||||
}
|
||||
|
||||
const std::string& Env::server_software() const {
|
||||
return m_cgi_env[CGIVars::SERVER_SOFTWARE];
|
||||
}
|
||||
|
||||
Env::GetMapType Env::query_string_split() const {
|
||||
GetMapType retval;
|
||||
const auto urlencoded_values = split_env_vars(m_cgi_env[CGIVars::QUERY_STRING]);
|
||||
retval.reserve(urlencoded_values.size());
|
||||
for (auto& itm : urlencoded_values) {
|
||||
retval[m_houdini.unescape_url(itm.first)] = m_houdini.unescape_url(itm.second);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
const SplitMime& Env::content_type_split() const {
|
||||
return m_split_mime;
|
||||
}
|
||||
|
||||
std::ostream& Env::print_all (std::ostream& parStream, const char* parNewline) const {
|
||||
for (std::size_t z = 0; z < m_cgi_env.size(); ++z) {
|
||||
parStream << CGIVars::_from_integral(z) <<
|
||||
" = \"" << m_cgi_env[z] << '"' << parNewline;
|
||||
}
|
||||
return parStream;
|
||||
}
|
||||
|
||||
} //namespace cgi
|
||||
} //namespace tawashi
|
83
src/tawashi/cgi_env.hpp
Normal file
83
src/tawashi/cgi_env.hpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "split_get_vars.hpp"
|
||||
#include "duckhandy/compatibility.h"
|
||||
#include "escapist.hpp"
|
||||
#include "kakoune/safe_ptr.hh"
|
||||
#include "request_method_type.hpp"
|
||||
#include "mime_split.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
namespace cgi {
|
||||
class Env : public Kakoune::SafeCountable {
|
||||
public:
|
||||
struct VersionInfo {
|
||||
boost::string_ref name;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
};
|
||||
|
||||
typedef boost::container::flat_map<std::string, std::string> GetMapType;
|
||||
|
||||
Env (const char* const* parEnvList, const boost::string_ref& parBasePath);
|
||||
~Env() noexcept;
|
||||
|
||||
const std::string& auth_type() const;
|
||||
std::size_t content_length() const;
|
||||
const std::string& content_type() const;
|
||||
boost::optional<VersionInfo> gateway_interface() const a_pure;
|
||||
boost::string_ref path_info() const;
|
||||
const std::string& path_translated() const;
|
||||
const std::string& query_string() const;
|
||||
const std::string& http_client_ip() const;
|
||||
const std::string& http_x_forwarded_for() const;
|
||||
const std::string& remote_addr() const;
|
||||
const std::string& remote_host() const;
|
||||
const std::string& remote_ident() const;
|
||||
const std::string& remote_user() const;
|
||||
RequestMethodType request_method() const;
|
||||
const std::string& script_name() const;
|
||||
const std::string& server_name() const;
|
||||
bool https() const;
|
||||
uint16_t server_port() const a_pure;
|
||||
boost::optional<VersionInfo> server_protocol() const a_pure;
|
||||
const std::string& server_software() const;
|
||||
|
||||
GetMapType query_string_split() const a_pure;
|
||||
const SplitMime& content_type_split() const a_pure;
|
||||
|
||||
std::ostream& print_all (std::ostream& parStream, const char* parNewline) const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_cgi_env;
|
||||
Escapist m_houdini;
|
||||
std::size_t m_skip_path_info;
|
||||
RequestMethodType m_request_method_type;
|
||||
SplitMime m_split_mime;
|
||||
};
|
||||
} //namespace cgi
|
||||
} //namespace tawashi
|
91
src/tawashi/cgi_environment_vars.cpp
Normal file
91
src/tawashi/cgi_environment_vars.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cgi_environment_vars.hpp"
|
||||
#include "sanitized_utf8.hpp"
|
||||
#include "string_lengths.hpp"
|
||||
#include <utility>
|
||||
#include <unordered_map>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <cstddef>
|
||||
#if !defined(NDEBUG)
|
||||
# include <cstring>
|
||||
#endif
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<boost::string_ref> {
|
||||
std::size_t operator() (const boost::string_ref& parStr) const {
|
||||
return boost::hash_range(parStr.begin(), parStr.end());
|
||||
}
|
||||
};
|
||||
} //namespace std
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
std::unordered_map<boost::string_ref, boost::string_ref> get_unrefined_env_vars (const char* const* parEnvList) {
|
||||
using boost::string_ref;
|
||||
|
||||
assert(parEnvList);
|
||||
std::size_t count = 0;
|
||||
while (*(parEnvList + count)) {
|
||||
++count;
|
||||
}
|
||||
|
||||
std::unordered_map<string_ref, string_ref> retval;
|
||||
retval.reserve(count);
|
||||
for (std::size_t z = 0; z < count; ++z) {
|
||||
const char* const equal_sign = std::strchr(parEnvList[z], '=');
|
||||
assert('=' == *equal_sign);
|
||||
assert(equal_sign >= parEnvList[z]);
|
||||
const std::size_t key_length = static_cast<std::size_t>(equal_sign - parEnvList[z]);
|
||||
const std::size_t whole_length = std::strlen(parEnvList[z] + key_length) + key_length;
|
||||
assert(std::strlen(parEnvList[z]) == whole_length);
|
||||
assert(whole_length >= key_length + 1);
|
||||
retval[string_ref(parEnvList[z], key_length)] = string_ref(parEnvList[z] + key_length + 1, whole_length - key_length - 1);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
std::vector<std::string> cgi_environment_vars (const char* const* parEnvList) {
|
||||
using boost::string_ref;
|
||||
|
||||
std::vector<std::string> retlist;
|
||||
retlist.reserve(CGIVars::_size());
|
||||
|
||||
auto unrefined_env_vars = get_unrefined_env_vars(parEnvList);
|
||||
auto enum_str_lengths = string_lengths<CGIVars>();
|
||||
|
||||
std::size_t z = 0;
|
||||
for (CGIVars var : CGIVars::_values()) {
|
||||
#if !defined(NDEBUG)
|
||||
assert(std::strlen(var._to_string()) == enum_str_lengths[z]);
|
||||
#endif
|
||||
auto it_found = unrefined_env_vars.find(boost::string_ref(var._to_string(), enum_str_lengths[z]));
|
||||
if (unrefined_env_vars.cend() != it_found)
|
||||
retlist.push_back(sanitized_utf8(it_found->second));
|
||||
else
|
||||
retlist.push_back(std::string());
|
||||
++z;
|
||||
}
|
||||
return retlist;
|
||||
}
|
||||
} //namespace tawashi
|
59
src/tawashi/cgi_environment_vars.hpp
Normal file
59
src/tawashi/cgi_environment_vars.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "enum.h"
|
||||
|
||||
namespace tawashi {
|
||||
SLOW_ENUM(CGIVars, std::size_t,
|
||||
AUTH_TYPE = 0,
|
||||
CONTENT_LENGTH,
|
||||
CONTENT_TYPE,
|
||||
DOCUMENT_ROOT, //The root directory of your server
|
||||
GATEWAY_INTERFACE,
|
||||
HTTP_CLIENT_IP,
|
||||
HTTP_COOKIE, //The visitor's cookie, if one is set
|
||||
HTTP_HOST, //The hostname of your server
|
||||
HTTP_REFERER, //The URL of the page that called your script
|
||||
HTTP_X_FORWARDED_FOR,
|
||||
HTTPS, //"on" if the script is being called through a secure server
|
||||
HTTP_USER_AGENT, //The browser type of your visitor
|
||||
PATH, //The system path your server is running under
|
||||
PATH_INFO,
|
||||
PATH_TRANSLATED,
|
||||
QUERY_STRING, //The query string (see GET, below)
|
||||
REMOTE_ADDR, //The IP address of the visitor
|
||||
REMOTE_HOST, //The hostname of the visitor (if your server has reverse-name-lookups on; otherwise this is the IP address again)
|
||||
REMOTE_IDENT,
|
||||
REMOTE_PORT, //The port the visitor is connected to on the web server
|
||||
REMOTE_USER, //The visitor's user name (for .htaccess-protected pages)
|
||||
REQUEST_METHOD, //GET or POST
|
||||
REQUEST_URI, //The interpreted pathname of the requested document or CGI (relative to the document root)
|
||||
SCRIPT_FILENAME, //The full pathname of the current CGI
|
||||
SCRIPT_NAME, //The interpreted pathname of the current CGI (relative to the document root)
|
||||
SERVER_ADMIN, //The email address for your server's webmaster
|
||||
SERVER_NAME, //Your server's fully qualified domain name (eg: www.example.com)
|
||||
SERVER_PORT, //The port number your server is listening on
|
||||
SERVER_PROTOCOL,
|
||||
SERVER_SOFTWARE //The server software you're using (such as Apache 1.3)
|
||||
);
|
||||
|
||||
std::vector<std::string> cgi_environment_vars (const char* const* parEnvList);
|
||||
} //namespace tawashi
|
94
src/tawashi/cgi_post.cpp
Normal file
94
src/tawashi/cgi_post.cpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cgi_post.hpp"
|
||||
#include "cgi_env.hpp"
|
||||
#include "split_get_vars.hpp"
|
||||
#include "escapist.hpp"
|
||||
#include "sanitized_utf8.hpp"
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <ciso646>
|
||||
|
||||
namespace tawashi {
|
||||
UnsupportedContentTypeException::UnsupportedContentTypeException (const boost::string_ref& parMessage) :
|
||||
TawashiException(ErrorReasons::UnsupportedContentType, parMessage)
|
||||
{
|
||||
}
|
||||
|
||||
namespace cgi {
|
||||
namespace {
|
||||
bool valid_content_type (const Env& parEnv) {
|
||||
if (parEnv.content_type_split().type != "application" or
|
||||
parEnv.content_type_split().subtype !=
|
||||
"x-www-form-urlencoded") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string read_n (std::istream& parSrc, std::size_t parSize) {
|
||||
if (0 == parSize)
|
||||
return std::string();
|
||||
|
||||
std::string original_data;
|
||||
original_data.reserve(parSize);
|
||||
std::copy_n(
|
||||
std::istream_iterator<char>(parSrc),
|
||||
parSize,
|
||||
std::back_inserter(original_data)
|
||||
);
|
||||
return sanitized_utf8(original_data);
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
const PostMapType& read_post (std::istream& parSrc, const Env& parEnv) {
|
||||
return read_post(parSrc, parEnv, parEnv.content_length());
|
||||
}
|
||||
|
||||
const PostMapType& read_post (std::istream& parSrc, const Env& parEnv, std::size_t parMaxLen) {
|
||||
static bool already_read = false;
|
||||
static PostMapType map;
|
||||
static std::string original_data;
|
||||
|
||||
if (not already_read) {
|
||||
assert(original_data.empty());
|
||||
assert(map.empty());
|
||||
|
||||
if (not valid_content_type(parEnv)) {
|
||||
throw UnsupportedContentTypeException(parEnv.content_type());
|
||||
}
|
||||
|
||||
const auto input_len = std::min(parMaxLen, parEnv.content_length());
|
||||
original_data = read_n(parSrc, input_len);
|
||||
Escapist houdini;
|
||||
for (auto& itm : split_env_vars(original_data)) {
|
||||
std::string key(houdini.unescape_url(itm.first));
|
||||
std::string val(houdini.unescape_url(itm.second));
|
||||
map[std::move(key)] = std::move(val);
|
||||
}
|
||||
|
||||
already_read = true;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
} //namespace cgi
|
||||
} //namespace tawashi
|
40
src/tawashi/cgi_post.hpp
Normal file
40
src/tawashi/cgi_post.hpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "tawashi_exception.hpp"
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <string>
|
||||
#include <istream>
|
||||
#include <cstddef>
|
||||
|
||||
namespace tawashi {
|
||||
class UnsupportedContentTypeException : public TawashiException {
|
||||
public:
|
||||
explicit UnsupportedContentTypeException (const boost::string_ref& parMessage);
|
||||
};
|
||||
|
||||
namespace cgi {
|
||||
class Env;
|
||||
|
||||
typedef boost::container::flat_map<std::string, std::string> PostMapType;
|
||||
|
||||
const PostMapType& read_post (std::istream& parSrc, const Env& parEnv);
|
||||
const PostMapType& read_post (std::istream& parSrc, const Env& parEnv, std::size_t parMaxLen);
|
||||
} //namespace cgi
|
||||
} //namespace tawashi
|
34
src/tawashi/error_reasons.hpp
Normal file
34
src/tawashi/error_reasons.hpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "enum.h"
|
||||
|
||||
namespace tawashi {
|
||||
BETTER_ENUM(ErrorReasons, int,
|
||||
PostLengthNotInRange,
|
||||
PastieNotSaved,
|
||||
UserFlooding,
|
||||
UnkownReason,
|
||||
RedisDisconnected,
|
||||
MissingPostVariable,
|
||||
PastieNotFound,
|
||||
InvalidContentType,
|
||||
UnsupportedContentType
|
||||
)
|
||||
} //namespace tawashi
|
69
src/tawashi/error_response.cpp
Normal file
69
src/tawashi/error_response.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "error_response.hpp"
|
||||
#include "error_reasons.hpp"
|
||||
#include "cgi_env.hpp"
|
||||
#include "sprout/array/array.hpp"
|
||||
#include "string_lengths.hpp"
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <ciso646>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
namespace tawashi {
|
||||
ErrorResponse::ErrorResponse (
|
||||
const Kakoune::SafePtr<SettingsBag>& parSettings,
|
||||
std::ostream* parStreamOut,
|
||||
const Kakoune::SafePtr<cgi::Env>& parCgiEnv
|
||||
) :
|
||||
Response(parSettings, parStreamOut, parCgiEnv, false)
|
||||
{
|
||||
}
|
||||
|
||||
void ErrorResponse::on_mustache_prepare (mstch::map& parContext) {
|
||||
auto get = cgi_env().query_string_split();
|
||||
const int reason_int = boost::lexical_cast<int>(get["reason"]);
|
||||
ErrorReasons reason_code(ErrorReasons::UnkownReason);
|
||||
if (reason_int >= 0 and reason_int < ErrorReasons::_size())
|
||||
reason_code = ErrorReasons::_from_integral(reason_int);
|
||||
|
||||
constexpr const sprout::array<const char*, ErrorReasons::_size()> err_descs {
|
||||
"Submitted pastie is either too short or too long and was rejected.",
|
||||
"Submitted pastie couldn't be saved.",
|
||||
"The pastie was not saved because the client is submitting too many pasties too quickly. Please wait a bit longer and try again.",
|
||||
"An unknown error was raised.",
|
||||
"Unable to connect to Redis.",
|
||||
"Request is missing a POST variable.",
|
||||
"Pastie not found.",
|
||||
"Invalid CONTENT_TYPE.",
|
||||
"Unsupported CONTENT_TYPE."
|
||||
};
|
||||
constexpr const auto lengths = string_lengths(err_descs);
|
||||
static_assert(err_descs.static_size == lengths.static_size, "Mismatching array sizes between strings and their lengths");
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
for (std::size_t z = 0; z < err_descs.size(); ++z) {
|
||||
assert(std::strlen(err_descs[z]) == lengths[z]);
|
||||
}
|
||||
#endif
|
||||
|
||||
parContext["error_message"] = std::string(err_descs[reason_code], lengths[reason_code]);
|
||||
parContext["error_id"] = std::to_string(reason_code);
|
||||
}
|
||||
} //namespace tawashi
|
39
src/tawashi/error_response.hpp
Normal file
39
src/tawashi/error_response.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "response.hpp"
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
class ErrorResponse : public Response {
|
||||
public:
|
||||
ErrorResponse (
|
||||
const Kakoune::SafePtr<SettingsBag>& parSettings,
|
||||
std::ostream* parStreamOut,
|
||||
const Kakoune::SafePtr<cgi::Env>& parCgiEnv
|
||||
);
|
||||
|
||||
protected:
|
||||
virtual boost::string_ref page_basename() const override { return boost::string_ref("error"); }
|
||||
|
||||
private:
|
||||
virtual void on_mustache_prepare (mstch::map& parContext) override;
|
||||
};
|
||||
} //namespace tawashi
|
||||
|
92
src/tawashi/escapist.cpp
Normal file
92
src/tawashi/escapist.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "escapist.hpp"
|
||||
#include "houdini.h"
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
|
||||
namespace tawashi {
|
||||
Escapist::Escapist() :
|
||||
m_gh_buf(new(&m_gh_buf_mem) gh_buf GH_BUF_INIT)
|
||||
{
|
||||
assert(reinterpret_cast<uintptr_t>(&m_gh_buf_mem) == reinterpret_cast<uintptr_t>(m_gh_buf));
|
||||
static_assert(sizeof(implem::DummyGHBuf) == sizeof(gh_buf), "Dummy struct has the wrong size");
|
||||
static_assert(sizeof(gh_buf) == sizeof(m_gh_buf_mem), "Static memory for gh_buf has the wrong size");
|
||||
static_assert(alignof(gh_buf) == alignof(m_gh_buf_mem), "Static memory for gh_buf has the wrong alignment");
|
||||
}
|
||||
|
||||
Escapist::~Escapist() noexcept {
|
||||
gh_buf_free(static_cast<gh_buf*>(m_gh_buf));
|
||||
static_cast<gh_buf*>(m_gh_buf)->~gh_buf();
|
||||
}
|
||||
|
||||
std::string Escapist::unescape_url (const boost::string_ref& parURL) const {
|
||||
if (parURL.empty())
|
||||
return std::string();
|
||||
|
||||
assert(m_gh_buf);
|
||||
gh_buf* const buf = static_cast<gh_buf*>(m_gh_buf);
|
||||
|
||||
const int escaped = houdini_unescape_url(
|
||||
buf,
|
||||
reinterpret_cast<const uint8_t*>(parURL.data()),
|
||||
parURL.size()
|
||||
);
|
||||
if (0 == escaped)
|
||||
return std::string(parURL.data(), parURL.size());
|
||||
else
|
||||
return std::string(buf->ptr, buf->size);
|
||||
}
|
||||
|
||||
std::string Escapist::escape_url (const boost::string_ref& parURL) const {
|
||||
if (parURL.empty())
|
||||
return std::string();
|
||||
|
||||
assert(m_gh_buf);
|
||||
gh_buf* const buf = static_cast<gh_buf*>(m_gh_buf);
|
||||
|
||||
const int escaped = houdini_escape_url(
|
||||
buf,
|
||||
reinterpret_cast<const uint8_t*>(parURL.data()),
|
||||
parURL.size()
|
||||
);
|
||||
if (0 == escaped)
|
||||
return std::string(parURL.data(), parURL.size());
|
||||
else
|
||||
return std::string(buf->ptr, buf->size);
|
||||
}
|
||||
|
||||
std::string Escapist::escape_html (const boost::string_ref& parHtml) const {
|
||||
if (parHtml.empty())
|
||||
return std::string();
|
||||
|
||||
assert(m_gh_buf);
|
||||
gh_buf* const buf = static_cast<gh_buf*>(m_gh_buf);
|
||||
|
||||
const int escaped = houdini_escape_html0(
|
||||
buf,
|
||||
reinterpret_cast<const uint8_t*>(parHtml.data()),
|
||||
parHtml.size(),
|
||||
1
|
||||
);
|
||||
if (0 == escaped)
|
||||
return std::string(parHtml.data(), parHtml.size());
|
||||
else
|
||||
return std::string(buf->ptr, buf->size);
|
||||
}
|
||||
} //namespace tawashi
|
47
src/tawashi/escapist.hpp
Normal file
47
src/tawashi/escapist.hpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace tawashi {
|
||||
namespace implem {
|
||||
//not actually used, only needed to get the size of the actual gh_buf
|
||||
//without including its full header file
|
||||
struct DummyGHBuf{
|
||||
char *ptr;
|
||||
size_t asize, size;
|
||||
};
|
||||
} //namespace implem
|
||||
|
||||
class Escapist {
|
||||
public:
|
||||
Escapist();
|
||||
~Escapist() noexcept;
|
||||
|
||||
std::string unescape_url (const boost::string_ref& parURL) const;
|
||||
std::string escape_url (const boost::string_ref& parURL) const;
|
||||
std::string escape_html (const boost::string_ref& parHtml) const;
|
||||
|
||||
private:
|
||||
std::aligned_storage<sizeof(implem::DummyGHBuf), alignof(implem::DummyGHBuf)>::type m_gh_buf_mem;
|
||||
void* m_gh_buf;
|
||||
};
|
||||
} //namespace tawashi
|
137
src/tawashi/http_header.cpp
Normal file
137
src/tawashi/http_header.cpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "http_header.hpp"
|
||||
#include "duckhandy/lexical_cast.hpp"
|
||||
#include "duckhandy/sequence_bt.hpp"
|
||||
#include "sprout/array/array.hpp"
|
||||
#include <utility>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <ciso646>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
constexpr const char* get_status_code_desc (HttpStatusCodes parCode) {
|
||||
switch (parCode) {
|
||||
case HttpStatusCodes::Code301_MovedPermanently: return "Moved Permanently";
|
||||
case HttpStatusCodes::Code302_Found: return "Found";
|
||||
case HttpStatusCodes::Code303_SeeOther: return "See Other";
|
||||
case HttpStatusCodes::Code400_BadRequest: return "Bad Request";
|
||||
case HttpStatusCodes::Code403_Forbidden: return "Forbidden";
|
||||
case HttpStatusCodes::Code404_NotFound: return "Not Found";
|
||||
case HttpStatusCodes::Code413_PayloadTooLarge: return "Payload Too Large";
|
||||
case HttpStatusCodes::Code429_TooManyRequests: return "Too Many Requests";
|
||||
case HttpStatusCodes::Code431_RequestHeaderFieldsTooLarge: return "Request Header Fields Too Large";
|
||||
case HttpStatusCodes::Code500_InternalServerError: return "Internal Server Error";
|
||||
case HttpStatusCodes::Code501_NotImplemented: return "Not Implemented";
|
||||
case HttpStatusCodes::Code503_ServiceUnavailable: return "Service Unavailable";
|
||||
}
|
||||
return "INVALID STATUS CODE";
|
||||
}
|
||||
|
||||
constexpr auto g_status_code_descriptions = ::better_enums::make_map(get_status_code_desc);
|
||||
} //unnamed namespace
|
||||
|
||||
HttpHeader::HttpHeader() :
|
||||
m_mime {"text", "html", {}},
|
||||
m_status_code(HttpStatusCodes::CodeNone),
|
||||
m_header_type(ContentType)
|
||||
{
|
||||
}
|
||||
|
||||
HttpHeader::HttpHeader (Types parType, HttpStatusCodes parCode, SplitMime&& parMime) :
|
||||
m_mime(std::move(parMime)),
|
||||
m_status_code(parCode),
|
||||
m_header_type(parType)
|
||||
{
|
||||
}
|
||||
|
||||
HttpHeader::HttpHeader (HttpStatusCodes parCode, std::string&& parRedirectLocation) :
|
||||
m_redirect_location(std::move(parRedirectLocation)),
|
||||
m_status_code(parCode),
|
||||
m_header_type(Location)
|
||||
{
|
||||
}
|
||||
|
||||
void HttpHeader::set_status (HttpStatusCodes parCode) {
|
||||
m_status_code = parCode;
|
||||
}
|
||||
|
||||
void HttpHeader::unset_status() {
|
||||
m_status_code = HttpStatusCodes::CodeNone;
|
||||
}
|
||||
|
||||
void HttpHeader::set_type (Types parType, SplitMime&& parParameter) {
|
||||
m_header_type = parType;
|
||||
m_mime = std::move(parParameter);
|
||||
}
|
||||
|
||||
bool HttpHeader::body_required() const {
|
||||
return type() == ContentType;
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& parStream, const HttpHeader& parHeader) {
|
||||
const HttpStatusCodes code_none = HttpStatusCodes::CodeNone;
|
||||
if (parHeader.status_code() != code_none) {
|
||||
parStream <<
|
||||
"Status: " <<
|
||||
parHeader.status_code()._to_integral() <<
|
||||
' ' <<
|
||||
g_status_code_descriptions[parHeader.status_code()] <<
|
||||
'\n'
|
||||
;
|
||||
}
|
||||
switch (parHeader.type()) {
|
||||
case HttpHeader::ContentType:
|
||||
SPDLOG_TRACE(spdlog::get("statuslog"), "Response is a Content-type (data)");
|
||||
parStream << "Content-type: " << mime_to_string(parHeader) << '\n';
|
||||
break;
|
||||
case HttpHeader::Location:
|
||||
SPDLOG_TRACE(spdlog::get("statuslog"), "Response is a Location (redirect)");
|
||||
parStream << "Location: " << parHeader.redirect_location() << '\n';
|
||||
break;
|
||||
}
|
||||
parStream << '\n';
|
||||
return parStream;
|
||||
}
|
||||
|
||||
HttpHeader make_header_type_html() {
|
||||
return HttpHeader(
|
||||
HttpHeader::ContentType,
|
||||
HttpStatusCodes::CodeNone,
|
||||
SplitMime { "text", "html", {}}
|
||||
);
|
||||
}
|
||||
|
||||
HttpHeader make_header_type_text_utf8() {
|
||||
return HttpHeader(
|
||||
HttpHeader::ContentType,
|
||||
HttpStatusCodes::CodeNone,
|
||||
SplitMime {"text", "plain", MimeParametersMapType {{"charset", "utf-8"}}}
|
||||
);
|
||||
}
|
||||
|
||||
std::string mime_to_string (const HttpHeader& parHeader) {
|
||||
bool write_ok;
|
||||
std::string retval = mime_to_string(parHeader.mime(), write_ok);
|
||||
if (not write_ok) {
|
||||
assert(false);
|
||||
return std::string();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
} //namespace tawashi
|
78
src/tawashi/http_header.hpp
Normal file
78
src/tawashi/http_header.hpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "enum.h"
|
||||
#include "mime_split.hpp"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
|
||||
namespace tawashi {
|
||||
BETTER_ENUM(HttpStatusCodes, uint16_t,
|
||||
Code301_MovedPermanently = 301,
|
||||
Code302_Found = 302,
|
||||
Code303_SeeOther = 303,
|
||||
Code400_BadRequest = 400,
|
||||
Code403_Forbidden = 403,
|
||||
Code404_NotFound = 404,
|
||||
Code413_PayloadTooLarge = 413,
|
||||
Code429_TooManyRequests = 429,
|
||||
Code431_RequestHeaderFieldsTooLarge = 431,
|
||||
Code500_InternalServerError = 500,
|
||||
Code501_NotImplemented = 501,
|
||||
Code503_ServiceUnavailable = 503,
|
||||
CodeNone = 0
|
||||
)
|
||||
class HttpHeader {
|
||||
public:
|
||||
enum Types : uint8_t {
|
||||
ContentType,
|
||||
Location,
|
||||
Status
|
||||
};
|
||||
|
||||
HttpHeader();
|
||||
HttpHeader (const HttpHeader&) = default;
|
||||
HttpHeader (HttpHeader&&) = default;
|
||||
HttpHeader (Types parType, HttpStatusCodes parCode, SplitMime&& parMime);
|
||||
HttpHeader (HttpStatusCodes parCode, std::string&& parRedirectLocation);
|
||||
~HttpHeader() noexcept = default;
|
||||
|
||||
Types type() const { return m_header_type; }
|
||||
HttpStatusCodes status_code() const { return m_status_code; }
|
||||
const std::string& redirect_location() const { return m_redirect_location; }
|
||||
const SplitMime& mime() const { return m_mime; }
|
||||
bool body_required() const;
|
||||
|
||||
void set_status (HttpStatusCodes parCode);
|
||||
void unset_status();
|
||||
void set_type (Types parType, SplitMime&& parParameter);
|
||||
|
||||
private:
|
||||
SplitMime m_mime;
|
||||
std::string m_redirect_location;
|
||||
HttpStatusCodes m_status_code;
|
||||
Types m_header_type;
|
||||
};
|
||||
|
||||
std::ostream& operator<< (std::ostream& parStream, const HttpHeader& parHeader);
|
||||
HttpHeader make_header_type_html();
|
||||
HttpHeader make_header_type_text_utf8();
|
||||
[[gnu::pure]] std::string mime_to_string (const HttpHeader& parHeader);
|
||||
} //namespace tawashi
|
31
src/tawashi/index_response.cpp
Normal file
31
src/tawashi/index_response.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "index_response.hpp"
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
IndexResponse::IndexResponse (
|
||||
const Kakoune::SafePtr<SettingsBag>& parSettings,
|
||||
std::ostream* parStreamOut,
|
||||
const Kakoune::SafePtr<cgi::Env>& parCgiEnv
|
||||
) :
|
||||
Response(parSettings, parStreamOut, parCgiEnv, false)
|
||||
{
|
||||
}
|
||||
} //namespace tawashi
|
||||
|
37
src/tawashi/index_response.hpp
Normal file
37
src/tawashi/index_response.hpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "response.hpp"
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
class IndexResponse : public Response {
|
||||
public:
|
||||
IndexResponse (
|
||||
const Kakoune::SafePtr<SettingsBag>& parSettings,
|
||||
std::ostream* parStreamOut,
|
||||
const Kakoune::SafePtr<cgi::Env>& parCgiEnv
|
||||
);
|
||||
|
||||
protected:
|
||||
virtual boost::string_ref page_basename() const override { return boost::string_ref("index"); }
|
||||
|
||||
private:
|
||||
};
|
||||
} //namespace tawashi
|
147
src/tawashi/ini_file.cpp
Normal file
147
src/tawashi/ini_file.cpp
Normal file
|
@ -0,0 +1,147 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ini_file.hpp"
|
||||
#include <utility>
|
||||
#include <boost/spirit/include/qi_core.hpp>
|
||||
#include <boost/spirit/include/qi_sequence.hpp>
|
||||
#include <boost/spirit/include/qi_plus.hpp>
|
||||
#include <boost/spirit/include/qi_difference.hpp>
|
||||
#include <boost/spirit/include/qi_raw.hpp>
|
||||
#include <boost/spirit/include/qi_lit.hpp>
|
||||
#include <boost/spirit/include/qi_kleene.hpp>
|
||||
#include <boost/spirit/include/qi_rule.hpp>
|
||||
#include <boost/spirit/include/qi_eol.hpp>
|
||||
#include <boost/spirit/include/qi_grammar.hpp>
|
||||
#include <boost/spirit/include/qi_hold.hpp>
|
||||
#include <boost/spirit/include/qi_char_class.hpp>
|
||||
#include <boost/spirit/include/qi_list.hpp>
|
||||
#include <boost/spirit/include/qi_optional.hpp>
|
||||
#include <boost/spirit/include/phoenix_stl.hpp>
|
||||
#include <boost/spirit/include/phoenix_operator.hpp>
|
||||
#include <boost/spirit/include/phoenix_bind.hpp>
|
||||
#include <boost/phoenix/object/construct.hpp>
|
||||
#include <boost/phoenix/bind/bind_member_function.hpp>
|
||||
#include <boost/phoenix/bind/bind_member_variable.hpp>
|
||||
#include <boost/fusion/adapted/std_pair.hpp>
|
||||
#include <type_traits>
|
||||
#include <iterator>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
typedef boost::string_ref string_type;
|
||||
|
||||
template <typename Iterator, typename Skipper>
|
||||
struct IniGrammar : boost::spirit::qi::grammar<Iterator, IniFile::IniMapType(), Skipper> {
|
||||
explicit IniGrammar (const std::string* parString);
|
||||
boost::spirit::qi::rule<Iterator, IniFile::IniMapType(), Skipper> start;
|
||||
boost::spirit::qi::rule<Iterator, string_type(), Skipper> section;
|
||||
boost::spirit::qi::rule<Iterator, string_type(), Skipper> key;
|
||||
boost::spirit::qi::rule<Iterator, IniFile::KeyValueMapType::value_type(), Skipper> key_value;
|
||||
boost::spirit::qi::rule<Iterator, IniFile::KeyValueMapType(), Skipper> key_values;
|
||||
const std::string* m_master_string;
|
||||
Iterator m_begin;
|
||||
};
|
||||
|
||||
template <typename Iterator, typename Skipper>
|
||||
IniGrammar<Iterator, Skipper>::IniGrammar (const std::string* parString) :
|
||||
IniGrammar::base_type(start),
|
||||
m_master_string(parString),
|
||||
m_begin(m_master_string->cbegin())
|
||||
{
|
||||
assert(m_master_string);
|
||||
namespace px = boost::phoenix;
|
||||
using boost::spirit::qi::_val;
|
||||
using boost::spirit::_1;
|
||||
using boost::spirit::qi::eol;
|
||||
using boost::spirit::qi::raw;
|
||||
using boost::string_ref;
|
||||
using boost::spirit::qi::hold;
|
||||
using boost::spirit::qi::graph;
|
||||
using boost::spirit::qi::blank;
|
||||
typedef IniFile::KeyValueMapType::value_type refpair;
|
||||
|
||||
section = '[' >> raw[+(graph - ']') >> *(hold[+blank >> +(graph - ']')])]
|
||||
[_val = px::bind(
|
||||
&string_ref::substr,
|
||||
px::construct<string_ref>(px::ref(*m_master_string)),
|
||||
px::begin(_1) - px::ref(m_begin), px::size(_1)
|
||||
)] >> ']';
|
||||
key = raw[(graph - '[' - '=') >> *(graph - '=') >> *(hold[+blank >> +(graph - '=')])][_val = px::bind(
|
||||
&string_ref::substr,
|
||||
px::construct<string_ref>(px::ref(*m_master_string)),
|
||||
px::begin(_1) - px::ref(m_begin), px::size(_1)
|
||||
)];
|
||||
key_value = key[px::bind(&refpair::first, _val) = _1] >> '=' >>
|
||||
raw[*(graph - eol) >> *(hold[+blank >> +(graph - eol)])][px::bind(&refpair::second, _val) = px::bind(
|
||||
&string_ref::substr,
|
||||
px::construct<string_ref>(px::ref(*m_master_string)),
|
||||
px::begin(_1) - px::ref(m_begin), px::size(_1)
|
||||
)];
|
||||
key_values = -(key_value % (+eol));
|
||||
start = *(*eol >> section >> +eol >> key_values >> *eol);
|
||||
}
|
||||
|
||||
IniFile::IniMapType parse_ini (const std::string* parIni, bool& parParseOk, int& parParsedCharCount) {
|
||||
using boost::spirit::qi::blank;
|
||||
using boost::spirit::qi::blank_type;
|
||||
|
||||
IniGrammar<std::string::const_iterator, blank_type> gramm(parIni);
|
||||
IniFile::IniMapType result;
|
||||
|
||||
parParseOk = false;
|
||||
parParsedCharCount = 0;
|
||||
|
||||
std::string::const_iterator start_it = parIni->cbegin();
|
||||
//TODO: make a skipper that also skips comments eg: blank | lit("//") >> *(char_ - eol)
|
||||
const bool parse_ok = boost::spirit::qi::phrase_parse(
|
||||
start_it,
|
||||
parIni->cend(),
|
||||
gramm,
|
||||
blank,
|
||||
result
|
||||
);
|
||||
|
||||
parParseOk = parse_ok and (parIni->cend() == start_it);
|
||||
parParsedCharCount = std::distance(parIni->cbegin(), start_it);
|
||||
assert(parParsedCharCount >= 0);
|
||||
return result;
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
IniFile::IniFile (std::istream_iterator<char> parInputFrom, std::istream_iterator<char> parInputEnd) :
|
||||
IniFile(std::string(parInputFrom, parInputEnd))
|
||||
{
|
||||
}
|
||||
|
||||
IniFile::IniFile (std::string&& parIniData) :
|
||||
m_raw_ini(std::move(parIniData)),
|
||||
m_map(parse_ini(&m_raw_ini, m_parse_ok, m_parsed_chars))
|
||||
{
|
||||
}
|
||||
|
||||
IniFile::IniFile (IniFile&& parOther) {
|
||||
auto* const old_data_ptr = parOther.m_raw_ini.data();
|
||||
m_raw_ini = std::move(parOther.m_raw_ini);
|
||||
if (m_raw_ini.data() == old_data_ptr)
|
||||
m_map = std::move(parOther.m_map);
|
||||
else
|
||||
m_map = parse_ini(&m_raw_ini, m_parse_ok, m_parsed_chars);
|
||||
}
|
||||
|
||||
IniFile::~IniFile() noexcept = default;
|
||||
} //namespace tawashi
|
58
src/tawashi/ini_file.hpp
Normal file
58
src/tawashi/ini_file.hpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kakoune/safe_ptr.hh"
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <iterator>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
namespace tawashi {
|
||||
class IniFile : public Kakoune::SafeCountable {
|
||||
public:
|
||||
typedef boost::container::flat_map<boost::string_ref, boost::string_ref> KeyValueMapType;
|
||||
typedef boost::container::flat_map<boost::string_ref, KeyValueMapType> IniMapType;
|
||||
|
||||
IniFile (std::istream_iterator<char> parInputFrom, std::istream_iterator<char> parInputEnd);
|
||||
explicit IniFile (std::string&& parIniData);
|
||||
IniFile (IniFile&& parOther);
|
||||
IniFile (const IniFile& parOther) = delete;
|
||||
~IniFile() noexcept;
|
||||
|
||||
IniFile& operator== (IniFile&&) = delete;
|
||||
IniFile& operator== (const IniFile&) = delete;
|
||||
|
||||
bool parse_success() const { return m_parse_ok; }
|
||||
int parsed_characters() const { return m_parsed_chars; }
|
||||
|
||||
const IniMapType& parsed() const;
|
||||
|
||||
private:
|
||||
std::string m_raw_ini;
|
||||
IniMapType m_map;
|
||||
int m_parsed_chars;
|
||||
bool m_parse_ok;
|
||||
};
|
||||
|
||||
inline const IniFile::IniMapType& IniFile::parsed() const {
|
||||
assert(parse_success());
|
||||
return m_map;
|
||||
}
|
||||
} //namespace tawashi
|
83
src/tawashi/ip_utils.cpp
Normal file
83
src/tawashi/ip_utils.cpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ip_utils.hpp"
|
||||
#include "duckhandy/lexical_cast.hpp"
|
||||
#include "duckhandy/int_to_string_ary.hpp"
|
||||
#include "cgi_env.hpp"
|
||||
#include "tawashi_config.h"
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <ciso646>
|
||||
|
||||
#if !defined(TAWASHI_WITH_IP_LOGGING)
|
||||
extern "C" void tiger (const char* parStr, uint64_t parLength, uint64_t parHash[3], char parPadding);
|
||||
#endif
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
std::string hash_if_configured (const std::string& parIP) a_always_inline;
|
||||
|
||||
#if !defined(TAWASHI_WITH_IP_LOGGING)
|
||||
std::string hashed_ip (const std::string& parIP) {
|
||||
using dhandy::tags::hex;
|
||||
|
||||
uint64_t hash[3];
|
||||
tiger(parIP.data(), parIP.size(), hash, 0x80);
|
||||
|
||||
auto h1 = dhandy::int_to_string_ary<char, hex>(hash[0]);
|
||||
auto h2 = dhandy::int_to_string_ary<char, hex>(hash[1]);
|
||||
auto h3 = dhandy::int_to_string_ary<char, hex>(hash[2]);
|
||||
|
||||
std::string retval(2 * sizeof(uint64_t) * 3, '0');
|
||||
assert(h1.size() <= 2 * sizeof(uint64_t));
|
||||
std::copy(h1.begin(), h1.end(), retval.begin() + 2 * sizeof(uint64_t) * 0 + 2 * sizeof(uint64_t) - h1.size());
|
||||
assert(h2.size() <= 2 * sizeof(uint64_t));
|
||||
std::copy(h2.begin(), h2.end(), retval.begin() + 2 * sizeof(uint64_t) * 1 + 2 * sizeof(uint64_t) - h2.size());
|
||||
assert(h3.size() <= 2 * sizeof(uint64_t));
|
||||
std::copy(h3.begin(), h3.end(), retval.begin() + 2 * sizeof(uint64_t) * 2 + 2 * sizeof(uint64_t) - h3.size());
|
||||
|
||||
SPDLOG_DEBUG(spdlog::get("statuslog"), "IP \"{}\" hashed -> \"{}\"", parIP, retval);
|
||||
assert(retval.size() == 16 * 3);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline std::string hash_if_configured (const std::string& parIP) {
|
||||
#if defined(TAWASHI_WITH_IP_LOGGING)
|
||||
return parIP;
|
||||
#else
|
||||
return hashed_ip(parIP);
|
||||
#endif
|
||||
}
|
||||
|
||||
} //unnamed namespace
|
||||
|
||||
//see: https://stackoverflow.com/questions/18799808/how-do-i-count-unique-visitors-to-my-site
|
||||
std::string guess_real_remote_ip (const cgi::Env& parCgiEnv) {
|
||||
if (not parCgiEnv.http_client_ip().empty()) {
|
||||
return hash_if_configured(parCgiEnv.http_client_ip());
|
||||
}
|
||||
else if (not parCgiEnv.http_x_forwarded_for().empty()) {
|
||||
return hash_if_configured(parCgiEnv.http_x_forwarded_for());
|
||||
}
|
||||
else {
|
||||
return hash_if_configured(parCgiEnv.remote_addr());
|
||||
}
|
||||
}
|
||||
} //namespace tawashi
|
29
src/tawashi/ip_utils.hpp
Normal file
29
src/tawashi/ip_utils.hpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "duckhandy/compatibility.h"
|
||||
#include <string>
|
||||
|
||||
namespace tawashi {
|
||||
namespace cgi {
|
||||
class Env;
|
||||
} //namespace cgi
|
||||
|
||||
std::string guess_real_remote_ip (const cgi::Env& parCgiEnv) a_pure;
|
||||
} //namespace tawashi
|
34
src/tawashi/list_highlight_langs.cpp
Normal file
34
src/tawashi/list_highlight_langs.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "list_highlight_langs.hpp"
|
||||
#include "settings_bag.hpp"
|
||||
#include <srchilite/langmap.h>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
HighlightLangList list_highlight_langs (const SettingsBag& parSettings) {
|
||||
srchilite::LangMap lang_map(parSettings.as<std::string>("langmap_dir"), "lang.map");
|
||||
lang_map.open();
|
||||
|
||||
const auto lang_range = boost::make_iterator_range(lang_map.begin(), lang_map.end());
|
||||
return boost::copy_range<HighlightLangList>(lang_range | boost::adaptors::map_keys);
|
||||
}
|
||||
} //namespace tawashi
|
||||
|
28
src/tawashi/list_highlight_langs.hpp
Normal file
28
src/tawashi/list_highlight_langs.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace tawashi {
|
||||
class SettingsBag;
|
||||
typedef std::vector<std::string> HighlightLangList;
|
||||
|
||||
HighlightLangList list_highlight_langs (const SettingsBag& parSettings);
|
||||
} //namespace tawashi
|
52
src/tawashi/logger.hpp
Normal file
52
src/tawashi/logger.hpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <ostream>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <cassert>
|
||||
#include <ciso646>
|
||||
|
||||
namespace tawashi {
|
||||
class Logger {
|
||||
public:
|
||||
explicit Logger (std::ostream* parStream);
|
||||
~Logger() noexcept;
|
||||
|
||||
template <typename... Args>
|
||||
void log (int parLevel, const boost::string_ref& parFormat, Args&&... parArgs);
|
||||
|
||||
private:
|
||||
static const constexpr int LogLevels = 3;
|
||||
|
||||
std::array<std::ostream*, LogLevels> m_outs;
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
void Logger::log (int parLevel, const boost::string_ref& parFormat, Args&&... parArgs) {
|
||||
assert(parLevel >= 0 and parLevel < LogLevels);
|
||||
if (nullptr == m_outs[parLevel])
|
||||
return;
|
||||
|
||||
bool percentage_seq = false;
|
||||
for (auto chara : parFormat) {
|
||||
if (percentage_seq) {
|
||||
}
|
||||
else {
|
||||
}
|
||||
}
|
||||
}
|
||||
} //namespace tawashi
|
33
src/tawashi/logging_levels.hpp
Normal file
33
src/tawashi/logging_levels.hpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "enum.h"
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace tawashi {
|
||||
BETTER_ENUM(LoggingLevels, int,
|
||||
trace = spdlog::level::trace,
|
||||
debug = spdlog::level::debug,
|
||||
info = spdlog::level::info,
|
||||
warn = spdlog::level::warn,
|
||||
err = spdlog::level::err,
|
||||
critical = spdlog::level::critical,
|
||||
off = spdlog::level::off
|
||||
);
|
||||
} //namespace tawashi
|
|
@ -1,183 +0,0 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tawashiConfig.h"
|
||||
#include "submit_paste_response.hpp"
|
||||
#include "quick_submit_paste_response.hpp"
|
||||
#include "pastie_response.hpp"
|
||||
#include "index_response.hpp"
|
||||
#include "error_response.hpp"
|
||||
#include "response_factory.hpp"
|
||||
#include "cgi_env.hpp"
|
||||
#include "ini_file.hpp"
|
||||
#include "safe_stack_object.hpp"
|
||||
#include "pathname/pathname.hpp"
|
||||
#include "duckhandy/compatibility.h"
|
||||
#include "settings_bag.hpp"
|
||||
#include "logging_levels.hpp"
|
||||
#include "request_method_type.hpp"
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <ciso646>
|
||||
#include <iostream>
|
||||
|
||||
//www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4150.pdf
|
||||
|
||||
namespace {
|
||||
std::string config_file_path() a_pure;
|
||||
|
||||
std::string config_file_path() {
|
||||
mchlib::PathName config_path(TAWASHI_CONFIG_PATH);
|
||||
mchlib::PathName full_path("");
|
||||
if (config_path.is_absolute()) {
|
||||
full_path = std::move(config_path);
|
||||
}
|
||||
else {
|
||||
full_path = mchlib::PathName(TAWASHI_PATH_PREFIX);
|
||||
full_path.join(config_path);
|
||||
}
|
||||
full_path.join(TAWASHI_CONFIG_FILE);
|
||||
return full_path.path();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::unique_ptr<tawashi::Response> make_response (
|
||||
const Kakoune::SafePtr<tawashi::SettingsBag>& parSettings,
|
||||
const Kakoune::SafePtr<tawashi::cgi::Env>& parCgiEnv
|
||||
) {
|
||||
return static_cast<std::unique_ptr<tawashi::Response>>(
|
||||
std::make_unique<T>(parSettings, &std::cout, parCgiEnv)
|
||||
);
|
||||
}
|
||||
|
||||
void fill_defaults (tawashi::SettingsBag& parSettings) {
|
||||
parSettings.add_default("redis_server", "127.0.0.1");
|
||||
parSettings.add_default("redis_port", "6379");
|
||||
parSettings.add_default("redis_mode", "sock");
|
||||
parSettings.add_default("redis_sock", "/tmp/redis.sock");
|
||||
parSettings.add_default("redis_db", "0");
|
||||
parSettings.add_default("host_name", "127.0.0.1");
|
||||
parSettings.add_default("host_port", "");
|
||||
parSettings.add_default("host_path", "/");
|
||||
parSettings.add_default("website_root", "");
|
||||
parSettings.add_default("langmap_dir", "/usr/share/source-highlight");
|
||||
parSettings.add_default("min_pastie_size", "10");
|
||||
parSettings.add_default("max_pastie_size", "10000");
|
||||
parSettings.add_default("truncate_long_pasties", "false");
|
||||
parSettings.add_default("logging_level", "err");
|
||||
parSettings.add_default("resubmit_wait", "10");
|
||||
parSettings.add_default("log_file", "-");
|
||||
parSettings.add_default("highlight_css", "sh_darkness.css");
|
||||
parSettings.add_default("max_post_size", "1048576");
|
||||
}
|
||||
|
||||
void print_buildtime_info() {
|
||||
std::cout << "NDEBUG defined: ";
|
||||
#if defined(NDEBUG)
|
||||
std::cout << "yes (Release build)";
|
||||
#else
|
||||
std::cout << "no (Debug build)";
|
||||
#endif
|
||||
std::cout << '\n';
|
||||
std::cout << "TAWASHI_CONFIG_FILE: \"" << TAWASHI_CONFIG_FILE << "\"\n";
|
||||
std::cout << "TAWASHI_CONFIG_PATH: \"" << TAWASHI_CONFIG_PATH << "\"\n";
|
||||
std::cout << "TAWASHI_PATH_PREFIX: \"" << TAWASHI_PATH_PREFIX << "\"\n";
|
||||
std::cout << "VERSION_MAJOR: " << VERSION_MAJOR << '\n';
|
||||
std::cout << "VERSION_MINOR: " << VERSION_MINOR << '\n';
|
||||
std::cout << "VERSION_PATCH: " << VERSION_PATCH << '\n';
|
||||
std::cout << "config_file_path(): \"" << config_file_path() << "\"\n";
|
||||
}
|
||||
|
||||
curry::SafeStackObject<tawashi::IniFile> load_ini() {
|
||||
using curry::SafeStackObject;
|
||||
using tawashi::IniFile;
|
||||
using std::istream_iterator;
|
||||
|
||||
std::ifstream conf(config_file_path());
|
||||
conf >> std::noskipws;
|
||||
return SafeStackObject<IniFile>(istream_iterator<char>(conf), istream_iterator<char>());
|
||||
}
|
||||
|
||||
std::shared_ptr<spdlog::logger> setup_logging (const tawashi::SettingsBag& parSettings) {
|
||||
//Prepare the logger
|
||||
spdlog::set_pattern("[%Y-%m-%d %T %z] - %v");
|
||||
spdlog::set_level(spdlog::level::trace); //set to maximum possible here
|
||||
boost::string_ref log_path = parSettings["log_file"];
|
||||
const bool log_to_stderr = (log_path == boost::string_ref("-"));
|
||||
auto statuslog = (log_to_stderr ?
|
||||
spdlog::stderr_logger_st("statuslog") :
|
||||
spdlog::basic_logger_st("statuslog", std::string(log_path.begin(), log_path.end()), false)
|
||||
);
|
||||
|
||||
auto logging_level = tawashi::LoggingLevels::_from_string_nocase(parSettings.as<std::string>("logging_level").c_str());
|
||||
spdlog::set_level(static_cast<decltype(spdlog::level::trace)>(logging_level._to_integral()));
|
||||
return statuslog;
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
int main (int parArgc, char* parArgv[], char* parEnvp[]) {
|
||||
using curry::SafeStackObject;
|
||||
using tawashi::IndexResponse;
|
||||
using tawashi::SubmitPasteResponse;
|
||||
using tawashi::QuickSubmitPasteResponse;
|
||||
using tawashi::PastieResponse;
|
||||
using tawashi::ErrorResponse;
|
||||
using tawashi::Response;
|
||||
using tawashi::RequestMethodType;
|
||||
|
||||
if (2 == parArgc and boost::string_ref(parArgv[1]) == "--show-paths") {
|
||||
print_buildtime_info();
|
||||
return 0;
|
||||
}
|
||||
|
||||
SafeStackObject<tawashi::IniFile> ini = load_ini();
|
||||
auto settings = SafeStackObject<tawashi::SettingsBag>(ini);
|
||||
fill_defaults(*settings);
|
||||
|
||||
auto statuslog = setup_logging(*settings);
|
||||
SPDLOG_DEBUG(statuslog, "tawashi started");
|
||||
int retval = 0;
|
||||
try {
|
||||
statuslog->info("Loaded config: \"{}\"", config_file_path());
|
||||
|
||||
auto cgi_env = SafeStackObject<tawashi::cgi::Env>(parEnvp, settings->at("host_path"));
|
||||
tawashi::ResponseFactory resp_factory(settings, cgi_env);
|
||||
SPDLOG_TRACE(statuslog, "Registering makers in the response factory");
|
||||
resp_factory.register_maker("index.cgi", RequestMethodType::GET, &make_response<IndexResponse>);
|
||||
resp_factory.register_maker("", RequestMethodType::GET, &make_response<IndexResponse>);
|
||||
resp_factory.register_maker("", RequestMethodType::POST, &make_response<QuickSubmitPasteResponse>);
|
||||
resp_factory.register_maker("paste.cgi", RequestMethodType::POST, &make_response<SubmitPasteResponse>);
|
||||
resp_factory.register_maker("error.cgi", RequestMethodType::GET, &make_response<ErrorResponse>);
|
||||
resp_factory.register_jolly_maker(&make_response<PastieResponse>, RequestMethodType::GET);
|
||||
|
||||
std::unique_ptr<Response> response = resp_factory.make_response(
|
||||
cgi_env->path_info(),
|
||||
cgi_env->request_method()
|
||||
);
|
||||
if (response)
|
||||
response->send();
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
statuslog->critical("Uncaught exception in main(): \"{}\"", e.what());
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
SPDLOG_DEBUG(statuslog, "tawashi done, quitting with {}", retval);
|
||||
return retval;
|
||||
}
|
225
src/tawashi/mime_split.cpp
Normal file
225
src/tawashi/mime_split.cpp
Normal file
|
@ -0,0 +1,225 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "mime_split.hpp"
|
||||
#include <boost/spirit/include/qi_core.hpp>
|
||||
#include <boost/spirit/include/qi_parse.hpp>
|
||||
#include <boost/spirit/include/qi_plus.hpp>
|
||||
#include <boost/spirit/include/qi_lit.hpp>
|
||||
#include <boost/spirit/include/qi_char_.hpp>
|
||||
#include <boost/spirit/include/qi_raw.hpp>
|
||||
#include <boost/spirit/include/qi_grammar.hpp>
|
||||
#include <boost/spirit/include/qi_lexeme.hpp>
|
||||
#include <boost/spirit/include/qi_char_.hpp>
|
||||
#include <boost/spirit/include/qi_char_class.hpp>
|
||||
#include <boost/spirit/include/qi_kleene.hpp>
|
||||
#include <boost/spirit/include/qi_alternative.hpp>
|
||||
#include <boost/spirit/include/qi_difference.hpp>
|
||||
|
||||
#include <boost/spirit/include/karma_char.hpp>
|
||||
#include <boost/spirit/include/karma_generate.hpp>
|
||||
#include <boost/spirit/include/karma_operator.hpp>
|
||||
#include <boost/spirit/include/karma_kleene.hpp>
|
||||
#include <boost/spirit/include/karma_stream.hpp>
|
||||
#include <boost/spirit/include/karma_string.hpp>
|
||||
#include <boost/spirit/include/karma_alternative.hpp>
|
||||
#include <boost/spirit/include/karma_rule.hpp>
|
||||
#include <boost/spirit/include/karma_eps.hpp>
|
||||
|
||||
#include <boost/fusion/include/std_pair.hpp>
|
||||
#include <boost/fusion/include/adapt_struct.hpp>
|
||||
|
||||
#include <boost/phoenix/function/lazy_prelude.hpp>
|
||||
#include <boost/phoenix/core.hpp>
|
||||
#include <boost/phoenix/object/construct.hpp>
|
||||
#include <boost/phoenix/stl/container.hpp>
|
||||
#include <boost/phoenix/bind/bind_member_function.hpp>
|
||||
#include <boost/phoenix/operator/arithmetic.hpp>
|
||||
#include <boost/phoenix/operator/self.hpp>
|
||||
#include <boost/phoenix/stl/algorithm/transformation.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
// The Internet Media Type [9 <#ref-9>] of the attached entity. The syntax is
|
||||
// the same as the HTTP Content-Type header.
|
||||
//
|
||||
// CONTENT_TYPE = "" | media-type
|
||||
// media-type = type "/" subtype *( ";" parameter)
|
||||
// type = token
|
||||
// subtype = token
|
||||
// parameter = attribute "=" value
|
||||
// attribute = token
|
||||
// value = token | quoted-string
|
||||
//
|
||||
// The type, subtype and parameter attribute names are not
|
||||
// case-sensitive. Parameter values may be case sensitive. Media
|
||||
// types and their use in HTTP are described section 3.6 <#section-3.6> of the
|
||||
// HTTP/1.0 specification [3 <#ref-3>]. Example:
|
||||
//
|
||||
// application/x-www-form-urlencoded
|
||||
//
|
||||
// There is no default value for this variable. If and only if it is
|
||||
// unset, then the script may attempt to determine the media type
|
||||
// from the data received. If the type remains unknown, then
|
||||
// application/octet-stream should be assumed.
|
||||
|
||||
BOOST_FUSION_ADAPT_STRUCT(
|
||||
tawashi::SplitMime,
|
||||
(boost::string_ref, type)
|
||||
(boost::string_ref, subtype)
|
||||
(tawashi::MimeParametersMapType, parameters)
|
||||
);
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
template <typename Iterator, typename Skipper>
|
||||
struct MimeGrammar : boost::spirit::qi::grammar<Iterator, tawashi::SplitMime(), Skipper> {
|
||||
explicit MimeGrammar (const std::string* parString);
|
||||
|
||||
boost::spirit::qi::rule<Iterator, SplitMime(), Skipper> content_type;
|
||||
boost::spirit::qi::rule<Iterator, SplitMime(), Skipper> media_type;
|
||||
boost::spirit::qi::rule<Iterator, boost::string_ref(), Skipper> type;
|
||||
boost::spirit::qi::rule<Iterator, boost::string_ref(), Skipper> subtype;
|
||||
boost::spirit::qi::rule<Iterator, MimeParametersMapType::value_type(), Skipper> parameter;
|
||||
boost::spirit::qi::rule<Iterator, boost::string_ref(), Skipper> attribute;
|
||||
boost::spirit::qi::rule<Iterator, boost::string_ref(), Skipper> value;
|
||||
boost::spirit::qi::rule<Iterator, boost::string_ref(), Skipper> quoted_string;
|
||||
boost::spirit::qi::rule<Iterator, boost::string_ref(), Skipper> token;
|
||||
const std::string* m_master_string;
|
||||
Iterator m_begin;
|
||||
};
|
||||
|
||||
template <typename Iterator, typename Skipper>
|
||||
MimeGrammar<Iterator, Skipper>::MimeGrammar (const std::string* parString) :
|
||||
MimeGrammar::base_type(content_type),
|
||||
m_master_string(parString),
|
||||
m_begin(m_master_string->cbegin())
|
||||
{
|
||||
namespace px = boost::phoenix;
|
||||
using boost::spirit::ascii::space;
|
||||
using boost::spirit::qi::char_;
|
||||
using boost::spirit::qi::lit;
|
||||
using boost::spirit::qi::alnum;
|
||||
using boost::spirit::qi::raw;
|
||||
using boost::spirit::qi::_val;
|
||||
using boost::spirit::qi::lexeme;
|
||||
using boost::string_ref;
|
||||
using boost::spirit::_1;
|
||||
|
||||
content_type = -media_type;
|
||||
media_type = type >> "/" >> subtype >> *(lit(";") >> parameter);
|
||||
type = token.alias();
|
||||
subtype = token.alias();
|
||||
parameter = attribute >> "=" >> value;
|
||||
attribute = token.alias();
|
||||
value = token | quoted_string;
|
||||
|
||||
token = raw[+(alnum | char_("_.-"))][
|
||||
_val = px::bind(
|
||||
&string_ref::substr, px::construct<string_ref>(px::ref(*m_master_string)),
|
||||
px::begin(_1) - px::ref(m_begin),
|
||||
px::size(_1)
|
||||
)
|
||||
];
|
||||
quoted_string = raw[
|
||||
lexeme[
|
||||
lit('"') >>
|
||||
*(char_ - '"') >>
|
||||
'"'
|
||||
]
|
||||
][_val = px::bind(
|
||||
&string_ref::substr, px::construct<string_ref>(px::ref(*m_master_string)),
|
||||
px::begin(_1) + 1 - px::ref(m_begin),
|
||||
px::size(_1) - 2
|
||||
)];
|
||||
}
|
||||
|
||||
struct simple_token_checker {
|
||||
typedef bool result_type;
|
||||
|
||||
template <typename V>
|
||||
bool operator() (const V& parIn) const {
|
||||
return std::find(std::begin(parIn), std::end(parIn), ' ') == std::end(parIn) and
|
||||
std::find(std::begin(parIn), std::end(parIn), '\t') == std::end(parIn);
|
||||
}
|
||||
};
|
||||
} //unnamed namespace
|
||||
|
||||
SplitMime string_to_mime (const std::string* parMime, bool& parParseOk, int& parParsedCharCount) {
|
||||
using boost::spirit::qi::blank;
|
||||
using boost::spirit::qi::blank_type;
|
||||
|
||||
MimeGrammar<std::string::const_iterator, blank_type> gramm(parMime);
|
||||
SplitMime result;
|
||||
|
||||
parParseOk = false;
|
||||
parParsedCharCount = 0;
|
||||
|
||||
std::string::const_iterator start_it = parMime->cbegin();
|
||||
const bool parse_ok = boost::spirit::qi::phrase_parse(
|
||||
start_it,
|
||||
parMime->cend(),
|
||||
gramm,
|
||||
blank,
|
||||
result
|
||||
);
|
||||
|
||||
parParseOk = parse_ok and (parMime->cend() == start_it);
|
||||
parParsedCharCount = std::distance(parMime->cbegin(), start_it);
|
||||
assert(parParsedCharCount >= 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string mime_to_string (const SplitMime& parMime, bool& parWriteOk) {
|
||||
namespace px = boost::phoenix;
|
||||
using boost::string_ref;
|
||||
using boost::spirit::karma::generate;
|
||||
using boost::spirit::karma::char_;
|
||||
using boost::spirit::karma::string;
|
||||
using boost::spirit::karma::rule;
|
||||
using boost::spirit::karma::alnum;
|
||||
using boost::spirit::karma::eps;
|
||||
using boost::spirit::_val;
|
||||
|
||||
if (parMime.type.empty() or parMime.subtype.empty()) {
|
||||
parWriteOk = false;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
px::function<simple_token_checker> is_simple_token;
|
||||
std::string retval;
|
||||
std::back_insert_iterator<std::string> out_iter(retval);
|
||||
rule<std::back_insert_iterator<std::string>, string_ref()> token;
|
||||
rule<std::back_insert_iterator<std::string>, string_ref()> quoted_string;
|
||||
rule<std::back_insert_iterator<std::string>, string_ref()> param_value;
|
||||
|
||||
token %= eps(is_simple_token(_val)) << *(alnum | char_("._-"));
|
||||
quoted_string %= '"' << string << '"';
|
||||
param_value %= token | quoted_string;
|
||||
|
||||
parWriteOk = generate(
|
||||
out_iter,
|
||||
string << "/" << string << *(
|
||||
"; " << string << "=" << param_value
|
||||
),
|
||||
parMime
|
||||
);
|
||||
return retval;
|
||||
}
|
||||
} //namespace tawashi
|
35
src/tawashi/mime_split.hpp
Normal file
35
src/tawashi/mime_split.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace tawashi {
|
||||
typedef boost::container::flat_map<boost::string_ref, boost::string_ref> MimeParametersMapType;
|
||||
|
||||
struct SplitMime {
|
||||
boost::string_ref type;
|
||||
boost::string_ref subtype;
|
||||
MimeParametersMapType parameters;
|
||||
};
|
||||
|
||||
SplitMime string_to_mime (const std::string* parMime, bool& parParseOk, int& parParsedCharCount);
|
||||
std::string mime_to_string (const SplitMime& parMime, bool& parWriteOk);
|
||||
} //namespace tawashi
|
34
src/tawashi/num_conv.hpp
Normal file
34
src/tawashi/num_conv.hpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ciso646>
|
||||
#include <duckhandy/lexical_cast.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
template <typename T>
|
||||
inline bool seems_valid_number (const boost::string_ref& parValue) {
|
||||
const std::size_t skip_sign = (sprout::is_signed<T>::value and not parValue.empty() and parValue[0] == '-' ? 1 : 0);
|
||||
for (std::size_t z = skip_sign; z < parValue.size(); ++z) {
|
||||
const char c = parValue[z];
|
||||
if (c < '0' or c > '9')
|
||||
return false;
|
||||
}
|
||||
return parValue.size() - skip_sign <= dhandy::tags::dec<T>::count_digits_bt(sprout::numeric_limits<T>::max());
|
||||
}
|
||||
} //namespace tawashi
|
64
src/tawashi/num_to_token.cpp
Normal file
64
src/tawashi/num_to_token.cpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "num_to_token.hpp"
|
||||
#include <cassert>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
//const int g_any_min = 0;
|
||||
//const int g_any_max = g_any_min + 'z' - 'a' - 1;
|
||||
//const int g_vowel_min = g_any_max + 1;
|
||||
//const int g_vowel_max = g_vowel_min + 5 - 1;
|
||||
//const int g_consonant_min = g_vowel_max + 1;
|
||||
//const int g_consonant_max = g_consonant_min + ('z' - 'a') - (g_vowel_max - g_vowel_min) - 1;
|
||||
|
||||
//char code_to_char (int parCode) {
|
||||
// const char vowels[] = {'a', 'i', 'u', 'e', 'o'};
|
||||
// const char consonants[] = {
|
||||
// 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p',
|
||||
// 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z'
|
||||
// };
|
||||
|
||||
// static_assert(sizeof(vowels) == g_vowel_max - g_vowel_min + 1, "Wrong vowels count");
|
||||
// static_assert(sizeof(consonants) == g_consonant_max - g_consonant_min + 1, "Wrong consonants count");
|
||||
|
||||
// if (parCode <= g_any_max)
|
||||
// return static_cast<char>('a' + parCode - g_any_min);
|
||||
// else if (parCode <= g_vowel_max)
|
||||
// return vowels[parCode - g_vowel_min];
|
||||
// else if (parCode <= g_consonant_max)
|
||||
// return consonants[parCode - g_consonant_min];
|
||||
|
||||
// assert(false);
|
||||
// return 'X';
|
||||
//}
|
||||
} //unnamed namespace
|
||||
|
||||
std::string num_to_token (int64_t parNum) {
|
||||
assert(0 < parNum);
|
||||
std::string retval;
|
||||
|
||||
do {
|
||||
const auto remainder = parNum % ('z' - 'a' + 1);
|
||||
retval.push_back(static_cast<char>('a' + remainder));
|
||||
parNum /= ('z' - 'a' + 1);
|
||||
} while (parNum);
|
||||
|
||||
return retval;
|
||||
}
|
||||
} //namespace tawashi
|
26
src/tawashi/num_to_token.hpp
Normal file
26
src/tawashi/num_to_token.hpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "duckhandy/compatibility.h"
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace tawashi {
|
||||
std::string num_to_token (int64_t parNum) a_pure;
|
||||
} //namespace tawashi
|
134
src/tawashi/pastie_response.cpp
Normal file
134
src/tawashi/pastie_response.cpp
Normal file
|
@ -0,0 +1,134 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pastie_response.hpp"
|
||||
#include "incredis/incredis.hpp"
|
||||
#include "settings_bag.hpp"
|
||||
#include "escapist.hpp"
|
||||
#include "cgi_env.hpp"
|
||||
#include <ciso646>
|
||||
#include <srchilite/sourcehighlight.h>
|
||||
#include <srchilite/langmap.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
const char g_nolang_token[] = "colourless";
|
||||
|
||||
std::string highlight_css_path (const SettingsBag& parSettings) {
|
||||
//TODO: make sure the file exists or throw or do something
|
||||
return parSettings.as<std::string>("highlight_css");
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
PastieResponse::PastieResponse (
|
||||
const Kakoune::SafePtr<SettingsBag>& parSettings,
|
||||
std::ostream* parStreamOut,
|
||||
const Kakoune::SafePtr<cgi::Env>& parCgiEnv
|
||||
) :
|
||||
Response(parSettings, parStreamOut, parCgiEnv, true),
|
||||
m_langmap_dir(parSettings->as<std::string>("langmap_dir")),
|
||||
m_plain_text(false),
|
||||
m_syntax_highlight(true),
|
||||
m_pastie_not_found(false)
|
||||
{
|
||||
}
|
||||
|
||||
HttpHeader PastieResponse::on_process() {
|
||||
if (m_pastie_not_found) {
|
||||
return make_error_redirect(ErrorReasons::PastieNotFound);
|
||||
}
|
||||
|
||||
auto get = cgi_env().query_string_split();
|
||||
const std::string& query_str(cgi_env().query_string());
|
||||
if (get["m"] == "plain" or query_str.empty()) {
|
||||
m_plain_text = true;
|
||||
return make_header_type_text_utf8();
|
||||
}
|
||||
else if (query_str == g_nolang_token) {
|
||||
m_syntax_highlight = false;
|
||||
}
|
||||
else {
|
||||
srchilite::LangMap lang_map(m_langmap_dir, "lang.map");
|
||||
lang_map.open();
|
||||
m_lang_file.clear();
|
||||
if (not query_str.empty())
|
||||
m_lang_file = lang_map.getFileName(query_str);
|
||||
if (m_lang_file.empty())
|
||||
m_lang_file = "default.lang";
|
||||
}
|
||||
return make_header_type_html();
|
||||
}
|
||||
|
||||
void PastieResponse::on_mustache_prepare (mstch::map& parContext) {
|
||||
using opt_string = redis::IncRedis::opt_string;
|
||||
using opt_string_list = redis::IncRedis::opt_string_list;
|
||||
|
||||
boost::string_ref token = cgi_env().path_info();
|
||||
auto& redis = this->redis();
|
||||
opt_string_list pastie_reply = redis.hmget(token, "pastie");
|
||||
opt_string pastie = (pastie_reply and not pastie_reply->empty() ? (*pastie_reply)[0] : opt_string());
|
||||
|
||||
if (not pastie) {
|
||||
m_pastie_not_found = true;
|
||||
return;
|
||||
}
|
||||
|
||||
srchilite::SourceHighlight highlighter;
|
||||
highlighter.setDataDir(settings().as<std::string>("langmap_dir"));
|
||||
highlighter.setGenerateEntireDoc(false);
|
||||
highlighter.setGenerateLineNumbers(true);
|
||||
#if defined(NDEBUG)
|
||||
highlighter.setOptimize(true);
|
||||
#else
|
||||
highlighter.setOptimize(false);
|
||||
#endif
|
||||
highlighter.setCanUseStdOut(false);
|
||||
highlighter.setTabSpaces(4);
|
||||
highlighter.setStyleCssFile(highlight_css_path(settings()));
|
||||
highlighter.setGenerateLineNumbers(false);
|
||||
|
||||
std::string processed_pastie;
|
||||
if (m_syntax_highlight) {
|
||||
//TODO: redirect to "pastie not found" if !pastie
|
||||
processed_pastie = std::move(*pastie);
|
||||
}
|
||||
else {
|
||||
Escapist houdini;
|
||||
std::ostringstream oss;
|
||||
oss << R"(<pre><tt><font color="#EDEDED">)";
|
||||
oss << houdini.escape_html(*pastie) << "</font></tt></pre>\n";
|
||||
processed_pastie = oss.str();
|
||||
}
|
||||
|
||||
if (not m_plain_text and m_syntax_highlight) {
|
||||
std::istringstream iss(std::move(processed_pastie));
|
||||
std::ostringstream oss;
|
||||
highlighter.highlight(iss, oss, m_lang_file);
|
||||
processed_pastie = oss.str();
|
||||
}
|
||||
|
||||
parContext["pastie"] = std::move(processed_pastie);
|
||||
}
|
||||
|
||||
std::string PastieResponse::on_mustache_retrieve() {
|
||||
if (m_plain_text)
|
||||
return "{{pastie}}";
|
||||
else
|
||||
return load_mustache();
|
||||
}
|
||||
} //namespace tawashi
|
47
src/tawashi/pastie_response.hpp
Normal file
47
src/tawashi/pastie_response.hpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "response.hpp"
|
||||
#include <string>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
class PastieResponse : public Response {
|
||||
public:
|
||||
PastieResponse (
|
||||
const Kakoune::SafePtr<SettingsBag>& parSettings,
|
||||
std::ostream* parStreamOut,
|
||||
const Kakoune::SafePtr<cgi::Env>& parCgiEnv
|
||||
);
|
||||
|
||||
protected:
|
||||
virtual boost::string_ref page_basename() const override { return boost::string_ref("pastie"); }
|
||||
|
||||
private:
|
||||
virtual HttpHeader on_process() override;
|
||||
virtual void on_mustache_prepare (mstch::map& parContext) override;
|
||||
virtual std::string on_mustache_retrieve() override;
|
||||
|
||||
std::string m_lang_file;
|
||||
std::string m_langmap_dir;
|
||||
bool m_plain_text;
|
||||
bool m_syntax_highlight;
|
||||
bool m_pastie_not_found;
|
||||
};
|
||||
} //namespace tawashi
|
254
src/tawashi/pathname/pathname.cpp
Normal file
254
src/tawashi/pathname/pathname.cpp
Normal file
|
@ -0,0 +1,254 @@
|
|||
/* Copyright 2015, 2016, Michele Santullo
|
||||
* This file is part of "dindexer".
|
||||
*
|
||||
* "dindexer" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "dindexer" 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 "dindexer". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pathname.hpp"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <ciso646>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
namespace mchlib {
|
||||
const std::string PathName::m_empty_str("");
|
||||
|
||||
namespace {
|
||||
std::string get_joint_atoms ( const StringPool<char>& parPool, bool parAbs, std::size_t parSkipRight=0 );
|
||||
std::size_t calc_join_size ( const StringPool<char>& parPool, bool parAbs, std::size_t parSkipRight=0 );
|
||||
std::size_t get_adjusted_atom_count ( const StringPool<char>& parPool, std::size_t parSkipRight );
|
||||
|
||||
std::size_t get_adjusted_atom_count (const StringPool<char>& parPool, std::size_t parSkipRight) {
|
||||
const auto orig_atom_count = parPool.size();
|
||||
const auto atom_count = (parSkipRight >= orig_atom_count ? 0 : orig_atom_count - parSkipRight);
|
||||
return atom_count;
|
||||
}
|
||||
|
||||
std::size_t calc_join_size (const StringPool<char>& parPool, bool parAbs, std::size_t parSkipRight) {
|
||||
const auto atom_count = get_adjusted_atom_count(parPool, parSkipRight);
|
||||
if (not atom_count) {
|
||||
if (parPool.empty() and parAbs) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t reserve = (parAbs ? 1 : 0);
|
||||
for (std::size_t z = 0; z < atom_count; ++z) {
|
||||
reserve += parPool[z].size();
|
||||
}
|
||||
reserve += atom_count - 1;
|
||||
return reserve;
|
||||
}
|
||||
|
||||
std::size_t count_grouped (boost::string_ref parIn, char parDelim) {
|
||||
std::size_t retval = 0;
|
||||
char prev = '\0';
|
||||
for (auto c : parIn) {
|
||||
retval += (parDelim == c and prev != parDelim ? 1 : 0);
|
||||
prev = c;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void split_path (std::vector<boost::string_ref>* parOut, boost::string_ref parPath) {
|
||||
auto from = parPath.begin();
|
||||
boost::string_ref::const_iterator next;
|
||||
const auto end = parPath.end();
|
||||
const auto beg = parPath.begin();
|
||||
while (end != (next = std::find(from, end, '/'))) {
|
||||
if (next != from) {
|
||||
parOut->push_back(parPath.substr(from - beg, next - from));
|
||||
from = next;
|
||||
}
|
||||
++from;
|
||||
}
|
||||
if (next != from) {
|
||||
parOut->push_back(parPath.substr(from - beg, next - from));
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_joint_atoms (const StringPool<char>& parPool, bool parAbs, std::size_t parSkipRight) {
|
||||
const auto reserve = calc_join_size(parPool, parAbs, parSkipRight);
|
||||
switch (reserve) {
|
||||
case 0:
|
||||
//reserve 0 means the resulting string is empty
|
||||
return std::string("");
|
||||
case 1:
|
||||
//when reserve is 1 and we're talking about an absolute path,
|
||||
//the resulting string can only be "/"
|
||||
if (parAbs) {
|
||||
return std::string("/");
|
||||
}
|
||||
};
|
||||
|
||||
std::string out;
|
||||
out.reserve(reserve);
|
||||
const char* slash = (parAbs ? "/" : "");
|
||||
const auto atom_count = get_adjusted_atom_count(parPool, parSkipRight);
|
||||
for (std::size_t z = 0; z < atom_count; ++z) {
|
||||
out += slash;
|
||||
const auto& curr_itm = parPool[z];
|
||||
out.insert(out.end(), curr_itm.begin(), curr_itm.end());
|
||||
slash = "/";
|
||||
}
|
||||
assert(reserve == out.size());
|
||||
return out;
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
PathName::PathName (boost::string_ref parPath) {
|
||||
if (not parPath.empty()) {
|
||||
m_absolute = ('/' == parPath.front());
|
||||
std::string path(parPath.begin(), parPath.end());
|
||||
|
||||
const auto count = count_grouped(path, '/');
|
||||
const std::size_t trailing = (path.back() == '/' ? 1 : 0);
|
||||
const std::size_t absolute = (m_absolute ? 1 : 0);
|
||||
const auto res = count + 1 - trailing - absolute;
|
||||
std::vector<boost::string_ref> atoms;
|
||||
atoms.reserve(res);
|
||||
split_path(&atoms, path);
|
||||
m_pool.insert(atoms, &path);
|
||||
}
|
||||
else {
|
||||
m_original_path = nullptr;
|
||||
m_absolute = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string PathName::path() const {
|
||||
return get_joint_atoms(m_pool, m_absolute);
|
||||
}
|
||||
|
||||
void PathName::join (const PathName& parOther) {
|
||||
m_pool.update(parOther.m_pool);
|
||||
}
|
||||
|
||||
const boost::string_ref PathName::operator[] (std::size_t parIndex) const {
|
||||
return *(m_pool.begin() + parIndex);
|
||||
}
|
||||
|
||||
std::size_t PathName::atom_count ( void ) const {
|
||||
return m_pool.size();
|
||||
}
|
||||
|
||||
void PathName::join (const char* parOther) {
|
||||
const std::string src(parOther);
|
||||
const boost::string_ref ref(src);
|
||||
m_pool.insert(ref, &src);
|
||||
}
|
||||
|
||||
void PathName::join (boost::string_ref parOther, const std::string* parSource) {
|
||||
m_pool.insert(parOther, parSource);
|
||||
}
|
||||
|
||||
PathName make_relative_path (const PathName& parBasePath, const PathName& parOtherPath) {
|
||||
if (not parBasePath.is_absolute() and parOtherPath.is_absolute()) {
|
||||
return parOtherPath;
|
||||
}
|
||||
|
||||
std::size_t common_atoms = 0;
|
||||
{
|
||||
const std::size_t shortest = std::min(parOtherPath.atom_count(), parBasePath.atom_count());
|
||||
for (std::size_t z = 0; z < shortest; ++z) {
|
||||
if (parOtherPath[z] == parBasePath[z]) {
|
||||
++common_atoms;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PathName retval("");
|
||||
const auto ellipses_count = parBasePath.atom_count() - common_atoms;
|
||||
for (std::size_t z = 0; z < ellipses_count; ++z) {
|
||||
retval.join("..");
|
||||
}
|
||||
|
||||
const auto remaining_atoms = parOtherPath.atom_count() - common_atoms;
|
||||
for (std::size_t z = 0; z < remaining_atoms; ++z) {
|
||||
retval.join(parOtherPath[z + common_atoms], parOtherPath.get_stringref_source(z + common_atoms));
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
const std::string* PathName::get_stringref_source (std::size_t parIndex) const {
|
||||
return m_pool.get_stringref_source(parIndex);
|
||||
}
|
||||
|
||||
std::string PathName::dirname() const {
|
||||
if (this->atom_count() == 0)
|
||||
return std::string();
|
||||
|
||||
return get_joint_atoms(m_pool, m_absolute, 1);
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& parStream, const PathName& parPath) {
|
||||
parStream << parPath.path();
|
||||
return parStream;
|
||||
}
|
||||
|
||||
const boost::string_ref basename (const PathName& parPath) {
|
||||
static const char* const empty = "";
|
||||
const auto sz = parPath.atom_count();
|
||||
if (not sz) {
|
||||
return boost::string_ref(empty);
|
||||
}
|
||||
|
||||
assert(sz > 0);
|
||||
return parPath[sz - 1];
|
||||
}
|
||||
|
||||
PathName& PathName::pop_right() {
|
||||
m_pool.pop();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool PathName::operator!= (const PathName& parOther) const {
|
||||
const auto count = atom_count();
|
||||
if (count != parOther.atom_count()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (std::size_t z = 0; z < count; ++z) {
|
||||
if ((*this)[z] != parOther[z]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PathName::operator== (const PathName& parOther) const {
|
||||
const auto count = atom_count();
|
||||
if (count != parOther.atom_count()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t z = 0; z < count; ++z) {
|
||||
if ((*this)[z] != parOther[z]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t PathName::str_path_size() const {
|
||||
return calc_join_size(m_pool, is_absolute());
|
||||
}
|
||||
} //namespace mchlib
|
67
src/tawashi/pathname/pathname.hpp
Normal file
67
src/tawashi/pathname/pathname.hpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* Copyright 2015, 2016, Michele Santullo
|
||||
* This file is part of "dindexer".
|
||||
*
|
||||
* "dindexer" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "dindexer" 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 "dindexer". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef id279E04E31E2C4D98B8C902781A3CE018
|
||||
#define id279E04E31E2C4D98B8C902781A3CE018
|
||||
|
||||
#include "stringpool.hpp"
|
||||
#include "kakoune/safe_ptr.hh"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
namespace mchlib {
|
||||
class PathName : public Kakoune::SafeCountable {
|
||||
public:
|
||||
PathName ( PathName&& ) = default;
|
||||
PathName ( const PathName& ) = default;
|
||||
explicit PathName ( boost::string_ref parPath );
|
||||
~PathName ( void ) noexcept = default;
|
||||
|
||||
PathName& operator= ( PathName&& ) = default;
|
||||
|
||||
bool is_absolute ( void ) const { return m_absolute; }
|
||||
std::string path ( void ) const;
|
||||
std::size_t str_path_size ( void ) const;
|
||||
const std::string& original_path ( void ) const { return (m_original_path ? *m_original_path : m_empty_str); }
|
||||
std::size_t atom_count ( void ) const;
|
||||
const boost::string_ref operator[] ( std::size_t parIndex ) const;
|
||||
void join ( const PathName& parOther );
|
||||
void join ( const char* parOther );
|
||||
void join ( boost::string_ref parOther, const std::string* parSource );
|
||||
const std::string* get_stringref_source ( std::size_t parIndex ) const;
|
||||
std::string dirname ( void ) const;
|
||||
PathName& pop_right ( void );
|
||||
bool operator!= ( const PathName& parOther ) const;
|
||||
bool operator== ( const PathName& parOther ) const;
|
||||
|
||||
private:
|
||||
static const std::string m_empty_str;
|
||||
|
||||
StringPool<char> m_pool;
|
||||
const std::string* m_original_path;
|
||||
bool m_absolute;
|
||||
};
|
||||
|
||||
PathName make_relative_path ( const PathName& parBasePath, const PathName& parOtherPath );
|
||||
std::ostream& operator<< ( std::ostream& parStream, const PathName& parPath );
|
||||
const boost::string_ref basename ( const PathName& parPath );
|
||||
} //namespace mchlib
|
||||
|
||||
#endif
|
70
src/tawashi/pathname/stringpool.hpp
Normal file
70
src/tawashi/pathname/stringpool.hpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/* Copyright 2015, 2016, Michele Santullo
|
||||
* This file is part of "dindexer".
|
||||
*
|
||||
* "dindexer" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "dindexer" 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 "dindexer". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef id9CF5E6FA7E334DF09559C2968C494CB9
|
||||
#define id9CF5E6FA7E334DF09559C2968C494CB9
|
||||
|
||||
#include <string>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <ciso646>
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
|
||||
namespace mchlib {
|
||||
template <typename C, typename Str=std::basic_string<C>, typename StrRef=boost::basic_string_ref<C>>
|
||||
class StringPool {
|
||||
typedef std::pair<StrRef, const Str*> StringListPair;
|
||||
typedef std::vector<std::pair<Str, std::size_t>> PoolType;
|
||||
typedef std::vector<StringListPair> StringListType;
|
||||
typedef std::function<StrRef(const StringListPair&)> FuncGetFirst;
|
||||
|
||||
public:
|
||||
typedef C char_type;
|
||||
typedef Str string_type;
|
||||
typedef StrRef stringref_type;
|
||||
typedef boost::transform_iterator<FuncGetFirst, typename StringListType::const_iterator> const_iterator;
|
||||
|
||||
StringPool ( void ) = default;
|
||||
~StringPool ( void ) noexcept = default;
|
||||
|
||||
template <typename ItR>
|
||||
void update ( ItR parDataBeg, ItR parDataEnd );
|
||||
void update ( const StringPool& parOther );
|
||||
void insert ( const std::vector<stringref_type>& parStrings, const string_type* parBaseString );
|
||||
void insert ( stringref_type parString, const string_type* parBaseString );
|
||||
const string_type* ptr_to_literal ( const char* parLiteral );
|
||||
std::size_t size ( void ) const { return m_strings.size(); }
|
||||
bool empty ( void ) const { return m_strings.empty(); }
|
||||
const_iterator begin ( void ) const;
|
||||
const_iterator end ( void ) const;
|
||||
const string_type* get_stringref_source ( std::size_t parIndex ) const;
|
||||
const stringref_type& operator[] ( std::size_t parIndex ) const;
|
||||
void pop ( void );
|
||||
|
||||
private:
|
||||
PoolType m_pool;
|
||||
StringListType m_strings;
|
||||
};
|
||||
} //namespace mchlib
|
||||
|
||||
#include "stringpool.inl"
|
||||
|
||||
#endif
|
140
src/tawashi/pathname/stringpool.inl
Normal file
140
src/tawashi/pathname/stringpool.inl
Normal file
|
@ -0,0 +1,140 @@
|
|||
/* Copyright 2015, 2016, Michele Santullo
|
||||
* This file is part of "dindexer".
|
||||
*
|
||||
* "dindexer" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "dindexer" 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 "dindexer". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace mchlib {
|
||||
namespace implem {
|
||||
template <typename StrRef>
|
||||
std::pair<StrRef, bool> clone_ifp (const StrRef& parClone, StrRef parSource) {
|
||||
const auto offset = parSource.find(parClone);
|
||||
if (parSource.npos != offset) {
|
||||
return std::make_pair(parSource.substr(offset, parClone.size()), true);
|
||||
}
|
||||
else {
|
||||
return std::make_pair(parClone, false);
|
||||
}
|
||||
}
|
||||
} //namespace implem
|
||||
|
||||
template <typename C, typename Str, typename StrRef>
|
||||
auto StringPool<C, Str, StrRef>::ptr_to_literal (const char* parLiteral) -> const string_type* {
|
||||
if (not parLiteral)
|
||||
return nullptr;
|
||||
|
||||
for (const auto& p : m_pool) {
|
||||
if (m_pool.first == parLiteral) {
|
||||
return &m_pool.first;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename C, typename Str, typename StrRef>
|
||||
template <typename ItR>
|
||||
void StringPool<C, Str, StrRef>::update (ItR parDataBeg, ItR parDataEnd) {
|
||||
typedef std::pair<string_type, std::size_t> PoolPair;
|
||||
|
||||
while (parDataBeg != parDataEnd) {
|
||||
const auto& remote_str = parDataBeg->first;
|
||||
const auto* remote_source_str = parDataBeg->second;
|
||||
bool cloned = false;
|
||||
|
||||
for (auto& local_src : m_pool) {
|
||||
const string_type& local_str = local_src.first;
|
||||
auto& local_ref_count = local_src.second;
|
||||
|
||||
auto cloned_result = implem::clone_ifp<StrRef>(remote_str, local_str);
|
||||
cloned = cloned_result.second;
|
||||
const auto& cloned_str = cloned_result.first;
|
||||
if (cloned) {
|
||||
++local_ref_count;
|
||||
m_strings.push_back(StringListPair(cloned_str, &local_str));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (not cloned) {
|
||||
m_pool.push_back(PoolPair(*remote_source_str, static_cast<std::size_t>(1)));
|
||||
const auto offset = remote_str.data() - remote_source_str->data();
|
||||
m_strings.push_back(StringListPair(stringref_type(m_pool.back().first).substr(offset, remote_str.size()), &m_pool.back().first));
|
||||
}
|
||||
++parDataBeg;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename C, typename Str, typename StrRef>
|
||||
void StringPool<C, Str, StrRef>::update (const StringPool& parOther) {
|
||||
this->update(parOther.m_strings.begin(), parOther.m_strings.end());
|
||||
}
|
||||
|
||||
template <typename C, typename Str, typename StrRef>
|
||||
auto StringPool<C, Str, StrRef>::begin() const -> const_iterator {
|
||||
return const_iterator(m_strings.cbegin(), [](const StringListPair& parItm) { return parItm.first; });
|
||||
}
|
||||
|
||||
template <typename C, typename Str, typename StrRef>
|
||||
auto StringPool<C, Str, StrRef>::end() const -> const_iterator {
|
||||
return const_iterator(m_strings.cend(), [](const StringListPair& parItm) { return parItm.first; });
|
||||
}
|
||||
|
||||
template <typename C, typename Str, typename StrRef>
|
||||
void StringPool<C, Str, StrRef>::insert (const std::vector<stringref_type>& parStrings, const string_type* parBaseString) {
|
||||
StringListType dummy;
|
||||
dummy.reserve(parStrings.size());
|
||||
for (const auto& itm : parStrings) {
|
||||
dummy.push_back(StringListPair(itm, parBaseString));
|
||||
}
|
||||
this->update(dummy.begin(), dummy.end());
|
||||
}
|
||||
|
||||
template <typename C, typename Str, typename StrRef>
|
||||
void StringPool<C, Str, StrRef>::insert (stringref_type parString, const string_type* parBaseString) {
|
||||
StringListType dummy;
|
||||
dummy.reserve(1);
|
||||
dummy.push_back(StringListPair(parString, parBaseString));
|
||||
this->update(dummy.begin(), dummy.end());
|
||||
}
|
||||
|
||||
template <typename C, typename Str, typename StrRef>
|
||||
auto StringPool<C, Str, StrRef>::get_stringref_source (std::size_t parIndex) const -> const string_type* {
|
||||
return m_strings[parIndex].second;
|
||||
}
|
||||
|
||||
template <typename C, typename Str, typename StrRef>
|
||||
auto StringPool<C, Str, StrRef>::operator[] (std::size_t parIndex) const -> const stringref_type& {
|
||||
return m_strings[parIndex].first;
|
||||
}
|
||||
|
||||
template <typename C, typename Str, typename StrRef>
|
||||
void StringPool<C, Str, StrRef>::pop() {
|
||||
if (m_strings.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto z = m_pool.size(); z > 0; --z) {
|
||||
auto& pool_itm = m_pool[z - 1];
|
||||
if (&pool_itm.first == m_strings.back().second) {
|
||||
m_strings.resize(m_strings.size() - 1);
|
||||
--pool_itm.second;
|
||||
if (0 == pool_itm.second) {
|
||||
m_pool.erase(m_pool.begin() + (z - 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
} //namespace mchlib
|
42
src/tawashi/quick_submit_paste_response.cpp
Normal file
42
src/tawashi/quick_submit_paste_response.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "quick_submit_paste_response.hpp"
|
||||
|
||||
namespace tawashi {
|
||||
QuickSubmitPasteResponse::QuickSubmitPasteResponse (
|
||||
const Kakoune::SafePtr<SettingsBag>& parSettings,
|
||||
std::ostream* parStreamOut,
|
||||
const Kakoune::SafePtr<cgi::Env>& parCgiEnv
|
||||
) :
|
||||
SubmitPasteResponse(parSettings, parStreamOut, parCgiEnv)
|
||||
{
|
||||
}
|
||||
|
||||
void QuickSubmitPasteResponse::on_mustache_prepare (mstch::map& parContext) {
|
||||
parContext["redirect_to_address"] = m_redirect_to;
|
||||
}
|
||||
|
||||
std::string QuickSubmitPasteResponse::on_mustache_retrieve() {
|
||||
return "{{base_uri}}/{{redirect_to_address}}\n";
|
||||
}
|
||||
|
||||
HttpHeader QuickSubmitPasteResponse::make_success_response (std::string&& parPastieParam) {
|
||||
m_redirect_to = std::move(parPastieParam);
|
||||
return HttpHeader();
|
||||
}
|
||||
} //namespace tawashi
|
44
src/tawashi/quick_submit_paste_response.hpp
Normal file
44
src/tawashi/quick_submit_paste_response.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "submit_paste_response.hpp"
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <cassert>
|
||||
|
||||
namespace tawashi {
|
||||
class QuickSubmitPasteResponse : public SubmitPasteResponse {
|
||||
public:
|
||||
QuickSubmitPasteResponse (
|
||||
const Kakoune::SafePtr<SettingsBag>& parSettings,
|
||||
std::ostream* parStreamOut,
|
||||
const Kakoune::SafePtr<cgi::Env>& parCgiEnv
|
||||
);
|
||||
|
||||
protected:
|
||||
virtual boost::string_ref page_basename() const override { assert(false); return boost::string_ref(""); }
|
||||
virtual HttpHeader make_success_response (std::string&& parPastieParam) override;
|
||||
|
||||
private:
|
||||
virtual void on_mustache_prepare (mstch::map& parContext) override;
|
||||
virtual std::string on_mustache_retrieve() override;
|
||||
|
||||
std::string m_redirect_to;
|
||||
};
|
||||
} //namespace tawashi
|
27
src/tawashi/request_method_type.hpp
Normal file
27
src/tawashi/request_method_type.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "enum.h"
|
||||
|
||||
namespace tawashi {
|
||||
BETTER_ENUM(RequestMethodType, int,
|
||||
GET,
|
||||
POST
|
||||
)
|
||||
} //namespace tawashi
|
281
src/tawashi/response.cpp
Normal file
281
src/tawashi/response.cpp
Normal file
|
@ -0,0 +1,281 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "response.hpp"
|
||||
#include "incredis/incredis.hpp"
|
||||
#include "settings_bag.hpp"
|
||||
#include "tawashi_config.h"
|
||||
#include "duckhandy/stringize.h"
|
||||
#include "duckhandy/lexical_cast.hpp"
|
||||
#include "pathname/pathname.hpp"
|
||||
#include "list_highlight_langs.hpp"
|
||||
#include "cgi_env.hpp"
|
||||
#include "num_conv.hpp"
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <functional>
|
||||
#include <boost/optional.hpp>
|
||||
#include <cstdint>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
//boost::string_ref fetch_page_basename (const cgi::Env& parEnv) {
|
||||
// const boost::string_ref& path = parEnv.path_info();
|
||||
|
||||
// const std::size_t last_slash = path.rfind('/');
|
||||
// const std::size_t last_dot = path.rfind('.');
|
||||
// const std::size_t start_index = (path.npos == last_slash ? 0 : last_slash + 1);
|
||||
// const std::size_t substr_len = (path.size() - start_index - (last_dot == path.npos ? 0 : path.size() - last_dot));
|
||||
// assert(start_index <= path.size());
|
||||
// assert(substr_len < path.size() and substr_len - path.size() - start_index);
|
||||
// return path.substr(start_index, substr_len);
|
||||
//}
|
||||
|
||||
std::string to_string (const boost::string_ref& parStr) {
|
||||
return std::string(parStr.data(), parStr.size());
|
||||
}
|
||||
|
||||
std::string make_root_path (const SettingsBag& parSettings) {
|
||||
auto retval = parSettings["website_root"];
|
||||
if (retval.empty()) {
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
return mchlib::PathName(retval).path() + '/';
|
||||
}
|
||||
}
|
||||
|
||||
redis::IncRedis make_incredis (const tawashi::SettingsBag& parSettings) {
|
||||
using redis::IncRedis;
|
||||
|
||||
if (parSettings["redis_mode"] == "inet") {
|
||||
return IncRedis(
|
||||
parSettings.as<std::string>("redis_server"),
|
||||
parSettings.as<uint16_t>("redis_port")
|
||||
);
|
||||
}
|
||||
else if (parSettings["redis_mode"] == "sock") {
|
||||
return IncRedis(parSettings.as<std::string>("redis_sock"));
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Unknown setting for \"redis_mode\", valid settings are \"inet\" or \"sock\"");
|
||||
}
|
||||
}
|
||||
|
||||
boost::optional<std::string> load_whole_file (const std::string& parWebsiteRoot, const char* parSuffix, const boost::string_ref& parName, bool parThrow) {
|
||||
std::ostringstream oss;
|
||||
oss << parWebsiteRoot << parName << parSuffix;
|
||||
spdlog::get("statuslog")->info("Trying to load \"{}\"", oss.str());
|
||||
std::ifstream if_mstch(oss.str(), std::ios::binary | std::ios::in);
|
||||
|
||||
if (not if_mstch) {
|
||||
spdlog::get("statuslog")->warn("Couldn't open file \"{}\"", oss.str());
|
||||
if (parThrow)
|
||||
throw std::runtime_error(std::string("File \"") + oss.str() + "\" not found");
|
||||
else
|
||||
return boost::optional<std::string>();
|
||||
}
|
||||
|
||||
std::ostringstream buffer;
|
||||
buffer << if_mstch.rdbuf();
|
||||
return boost::make_optional(buffer.str());
|
||||
}
|
||||
|
||||
mstch::array make_mstch_langmap (const SettingsBag& parSettings) {
|
||||
mstch::array retval;
|
||||
|
||||
for (auto&& lang : list_highlight_langs(parSettings)) {
|
||||
retval.push_back(mstch::map{{"language_name", std::move(lang)}});
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string disable_mstch_escaping (const std::string& parStr) {
|
||||
return parStr;
|
||||
};
|
||||
|
||||
boost::string_ref make_host_path (const SettingsBag& parSettings) {
|
||||
boost::string_ref host_path = parSettings.at("host_path");
|
||||
if (not host_path.empty() and host_path[host_path.size() - 1] == '/')
|
||||
host_path = host_path.substr(0, host_path.size() - 1);
|
||||
return host_path;
|
||||
}
|
||||
|
||||
std::string make_base_uri (const Kakoune::SafePtr<SettingsBag>& parSettings, const Kakoune::SafePtr<cgi::Env>& parCgiEnv) {
|
||||
assert(parSettings);
|
||||
assert(parCgiEnv);
|
||||
|
||||
std::ostringstream oss;
|
||||
if (parCgiEnv->https())
|
||||
oss << "https://";
|
||||
else
|
||||
oss << "http://";
|
||||
oss << parSettings->at("host_name");
|
||||
boost::string_ref host_port = parSettings->at("host_port");
|
||||
if (not host_port.empty()) {
|
||||
if (host_port == "from_downstream") {
|
||||
const uint16_t port = parCgiEnv->server_port();
|
||||
if ((80 != port and not parCgiEnv->https()) or 443 != port and parCgiEnv->https()) {
|
||||
oss << ':' << port;
|
||||
}
|
||||
}
|
||||
else if (not host_port.empty() and seems_valid_number<uint16_t>(host_port)) {
|
||||
oss << ':' << host_port;
|
||||
}
|
||||
}
|
||||
|
||||
oss << make_host_path(*parSettings);
|
||||
return oss.str();
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
Response::Response (
|
||||
const Kakoune::SafePtr<SettingsBag>& parSettings,
|
||||
std::ostream* parStreamOut,
|
||||
const Kakoune::SafePtr<cgi::Env>& parCgiEnv,
|
||||
bool parWantRedis
|
||||
) :
|
||||
//m_page_basename(fetch_page_basename(m_cgi_env)),
|
||||
m_cgi_env(parCgiEnv),
|
||||
m_settings(parSettings),
|
||||
m_website_root(make_root_path(*parSettings)),
|
||||
m_base_uri(make_base_uri(m_settings, m_cgi_env)),
|
||||
m_stream_out(parStreamOut)
|
||||
{
|
||||
assert(m_cgi_env);
|
||||
assert(m_stream_out);
|
||||
|
||||
if (parWantRedis) {
|
||||
m_redis = std::make_unique<redis::IncRedis>(make_incredis(*parSettings));
|
||||
m_redis->connect();
|
||||
}
|
||||
|
||||
mstch::config::escape = &disable_mstch_escaping;
|
||||
|
||||
auto statuslog = spdlog::get("statuslog");
|
||||
assert(statuslog);
|
||||
statuslog->info("Preparing response for {} request; query_string=\"{}\"; size={}",
|
||||
cgi_env().request_method()._to_string(),
|
||||
cgi_env().query_string(),
|
||||
cgi_env().content_length()
|
||||
);
|
||||
}
|
||||
|
||||
Response::~Response() noexcept = default;
|
||||
|
||||
HttpHeader Response::on_process() {
|
||||
return HttpHeader();
|
||||
}
|
||||
|
||||
void Response::on_mustache_prepare (mstch::map&) {
|
||||
}
|
||||
|
||||
void Response::send() {
|
||||
auto statuslog = spdlog::get("statuslog");
|
||||
assert(statuslog);
|
||||
|
||||
statuslog->info("Sending response");
|
||||
SPDLOG_TRACE(statuslog, "Preparing mustache dictionary");
|
||||
mstch::map mustache_context {
|
||||
{"version", std::string{STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) "." STRINGIZE(VERSION_PATCH)}},
|
||||
{"base_uri", std::string(base_uri())},
|
||||
{"host_path", to_string(make_host_path(this->settings()))},
|
||||
{"languages", make_mstch_langmap(*m_settings)}
|
||||
};
|
||||
|
||||
if (m_redis) {
|
||||
SPDLOG_TRACE(statuslog, "Finalizing redis connection");
|
||||
m_redis->wait_for_connect();
|
||||
auto batch = m_redis->make_batch();
|
||||
batch.select(m_settings->as<uint32_t>("redis_db"));
|
||||
batch.client_setname("tawashi_v" STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) "." STRINGIZE(VERSION_PATCH));
|
||||
batch.throw_if_failed();
|
||||
}
|
||||
|
||||
SPDLOG_TRACE(statuslog, "Raising event on_process");
|
||||
HttpHeader http_header = this->on_process();
|
||||
*m_stream_out << http_header;
|
||||
|
||||
if (http_header.body_required()) {
|
||||
SPDLOG_TRACE(statuslog, "Raising event on_mustache_prepare");
|
||||
this->on_mustache_prepare(mustache_context);
|
||||
|
||||
SPDLOG_TRACE(statuslog, "Rendering in mustache");
|
||||
*m_stream_out << mstch::render(
|
||||
on_mustache_retrieve(),
|
||||
mustache_context,
|
||||
std::bind(
|
||||
&load_whole_file,
|
||||
std::cref(m_website_root),
|
||||
".mustache",
|
||||
std::placeholders::_1,
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
SPDLOG_TRACE(statuslog, "Flushing output");
|
||||
m_stream_out->flush();
|
||||
}
|
||||
|
||||
std::string Response::on_mustache_retrieve() {
|
||||
return load_mustache();
|
||||
}
|
||||
|
||||
const cgi::Env& Response::cgi_env() const {
|
||||
return *m_cgi_env;
|
||||
}
|
||||
|
||||
const std::string& Response::base_uri() const {
|
||||
return m_base_uri;
|
||||
}
|
||||
|
||||
std::string Response::load_mustache() const {
|
||||
boost::optional<std::string> content = load_whole_file(m_website_root, ".html.mstch", page_basename(), true);
|
||||
return *content;
|
||||
}
|
||||
|
||||
redis::IncRedis& Response::redis() const {
|
||||
assert(m_redis);
|
||||
return *m_redis;
|
||||
}
|
||||
|
||||
const SettingsBag& Response::settings() const {
|
||||
assert(m_settings);
|
||||
return *m_settings;
|
||||
}
|
||||
|
||||
HttpHeader Response::make_redirect (HttpStatusCodes parCode, const std::string& parLocation) {
|
||||
std::ostringstream oss;
|
||||
oss << base_uri() << '/' << parLocation;
|
||||
return HttpHeader(parCode, oss.str());
|
||||
}
|
||||
|
||||
HttpHeader Response::make_error_redirect (ErrorReasons parReason) {
|
||||
auto statuslog = spdlog::get("statuslog");
|
||||
assert(statuslog);
|
||||
const HttpStatusCodes redir_code = HttpStatusCodes::Code302_Found;
|
||||
statuslog->info("Redirecting to error page, code={} reason={}", redir_code, parReason);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "error.cgi?reason=" << parReason._to_integral();
|
||||
return make_redirect(redir_code, oss.str());
|
||||
}
|
||||
} //namespace tawashi
|
75
src/tawashi/response.hpp
Normal file
75
src/tawashi/response.hpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mstch/mstch.hpp"
|
||||
#include "kakoune/safe_ptr.hh"
|
||||
#include "http_header.hpp"
|
||||
#include "error_reasons.hpp"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace redis {
|
||||
class IncRedis;
|
||||
} //namespace redis
|
||||
|
||||
namespace tawashi {
|
||||
class SettingsBag;
|
||||
|
||||
namespace cgi {
|
||||
class Env;
|
||||
} //namespace cgi
|
||||
|
||||
class Response {
|
||||
public:
|
||||
virtual ~Response() noexcept;
|
||||
|
||||
void send();
|
||||
|
||||
protected:
|
||||
Response (
|
||||
const Kakoune::SafePtr<SettingsBag>& parSettings,
|
||||
std::ostream* parStreamOut,
|
||||
const Kakoune::SafePtr<cgi::Env>& parCgiEnv,
|
||||
bool parWantRedis
|
||||
);
|
||||
|
||||
const cgi::Env& cgi_env() const;
|
||||
const std::string& base_uri() const;
|
||||
virtual boost::string_ref page_basename() const = 0;
|
||||
redis::IncRedis& redis() const;
|
||||
const SettingsBag& settings() const;
|
||||
virtual std::string load_mustache() const;
|
||||
HttpHeader make_redirect (HttpStatusCodes parCode, const std::string& parLocation);
|
||||
HttpHeader make_error_redirect (ErrorReasons parReason);
|
||||
|
||||
private:
|
||||
virtual HttpHeader on_process();
|
||||
virtual void on_mustache_prepare (mstch::map& parContext);
|
||||
virtual std::string on_mustache_retrieve();
|
||||
|
||||
Kakoune::SafePtr<cgi::Env> m_cgi_env;
|
||||
Kakoune::SafePtr<SettingsBag> m_settings;
|
||||
std::string m_website_root;
|
||||
std::string m_base_uri;
|
||||
std::unique_ptr<redis::IncRedis> m_redis;
|
||||
std::ostream* m_stream_out;
|
||||
};
|
||||
} //namespace tawashi
|
91
src/tawashi/response_factory.cpp
Normal file
91
src/tawashi/response_factory.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "response_factory.hpp"
|
||||
#include "settings_bag.hpp"
|
||||
#include "cgi_env.hpp"
|
||||
#include <functional>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
} //unnamed namespace
|
||||
|
||||
struct ResponseFactory::LocalData {
|
||||
Kakoune::SafePtr<SettingsBag> settings;
|
||||
boost::container::flat_map<std::string, ResponseMakerFunc> makers_get;
|
||||
boost::container::flat_map<std::string, ResponseMakerFunc> makers_post;
|
||||
std::array<ResponseMakerFunc, RequestMethodType::_size()> jolly_makers;
|
||||
Kakoune::SafePtr<cgi::Env> cgi_env;
|
||||
};
|
||||
|
||||
ResponseFactory::ResponseFactory (const Kakoune::SafePtr<SettingsBag>& parSettings, const Kakoune::SafePtr<cgi::Env>& parCgiEnv) :
|
||||
m_local_data(std::make_unique<LocalData>())
|
||||
{
|
||||
m_local_data->settings = parSettings;
|
||||
m_local_data->cgi_env = parCgiEnv;
|
||||
std::fill(m_local_data->jolly_makers.begin(), m_local_data->jolly_makers.end(), nullptr);
|
||||
}
|
||||
|
||||
ResponseFactory::~ResponseFactory() noexcept = default;
|
||||
|
||||
std::unique_ptr<Response> ResponseFactory::make_response (const boost::string_ref& parName, RequestMethodType parReqType) {
|
||||
std::string name(parName.data(), parName.size());
|
||||
spdlog::get("statuslog")->info(
|
||||
"making response object for \"{}\" method {}",
|
||||
name,
|
||||
parReqType._to_string()
|
||||
);
|
||||
|
||||
const auto& makers = (static_cast<RequestMethodType>(RequestMethodType::POST) == parReqType ? m_local_data->makers_post : m_local_data->makers_get);
|
||||
auto maker_it = makers.find(name);
|
||||
if (makers.end() != maker_it) {
|
||||
return maker_it->second(m_local_data->settings, m_local_data->cgi_env);
|
||||
}
|
||||
else if (m_local_data->jolly_makers[parReqType]) {
|
||||
spdlog::get("statuslog")->info("no exact match found for \"{}\", assuming it's a pastie's token", name);
|
||||
return m_local_data->jolly_makers[parReqType](m_local_data->settings, m_local_data->cgi_env);
|
||||
}
|
||||
else {
|
||||
spdlog::get("statuslog")->critical("no exact match found for \"{}\" with method {} and no jolly maker given, this should not happen", name, parReqType._to_string());
|
||||
return std::unique_ptr<Response>();
|
||||
}
|
||||
}
|
||||
|
||||
void ResponseFactory::register_maker (std::string&& parName, ResponseMakerFunc parMaker) {
|
||||
m_local_data->makers_get[parName] = parMaker;
|
||||
m_local_data->makers_post[std::move(parName)] = parMaker;
|
||||
}
|
||||
|
||||
void ResponseFactory::register_maker (std::string&& parName, RequestMethodType parReqType, ResponseMakerFunc parMaker) {
|
||||
switch (parReqType) {
|
||||
case RequestMethodType::GET:
|
||||
m_local_data->makers_get[std::move(parName)] = parMaker;
|
||||
break;
|
||||
case RequestMethodType::POST:
|
||||
m_local_data->makers_post[std::move(parName)] = parMaker;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void ResponseFactory::register_jolly_maker (ResponseMakerFunc parMaker, RequestMethodType parReqType) {
|
||||
m_local_data->jolly_makers[parReqType] = parMaker;
|
||||
}
|
||||
} //namespace tawashi
|
49
src/tawashi/response_factory.hpp
Normal file
49
src/tawashi/response_factory.hpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "response.hpp"
|
||||
#include "kakoune/safe_ptr.hh"
|
||||
#include "request_method_type.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace tawashi {
|
||||
class SettingsBag;
|
||||
|
||||
namespace cgi {
|
||||
class Env;
|
||||
} //namespace cgi
|
||||
|
||||
class ResponseFactory {
|
||||
public:
|
||||
typedef std::function<std::unique_ptr<Response>(const Kakoune::SafePtr<SettingsBag>&, const Kakoune::SafePtr<cgi::Env>& parCgiEnv)> ResponseMakerFunc;
|
||||
|
||||
explicit ResponseFactory (const Kakoune::SafePtr<SettingsBag>& parSettings, const Kakoune::SafePtr<cgi::Env>& parCgiEnv);
|
||||
~ResponseFactory() noexcept;
|
||||
|
||||
std::unique_ptr<Response> make_response(const boost::string_ref& parName, RequestMethodType parReqType);
|
||||
void register_maker (std::string&& parName, ResponseMakerFunc parMaker);
|
||||
void register_maker (std::string&& parName, RequestMethodType parReqType, ResponseMakerFunc parMaker);
|
||||
void register_jolly_maker (ResponseMakerFunc parMaker, RequestMethodType parReqType);
|
||||
|
||||
private:
|
||||
struct LocalData;
|
||||
|
||||
std::unique_ptr<LocalData> m_local_data;
|
||||
};
|
||||
} //namespace tawashi
|
104
src/tawashi/safe_stack_object.hpp
Normal file
104
src/tawashi/safe_stack_object.hpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
Copyright 2016, 2017 Michele "King_DuckZ" Santullo
|
||||
|
||||
This file is part of MyCurry.
|
||||
|
||||
MyCurry 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, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
MyCurry 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 MyCurry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kakoune/safe_ptr.hh"
|
||||
#include <utility>
|
||||
|
||||
namespace curry {
|
||||
template <typename T>
|
||||
class SafeStackObject {
|
||||
public:
|
||||
typedef Kakoune::SafePtr<T> safe_ptr;
|
||||
|
||||
SafeStackObject();
|
||||
SafeStackObject (SafeStackObject&& parOther);
|
||||
SafeStackObject (const SafeStackObject& parOther) = delete;
|
||||
template <typename... Args> explicit SafeStackObject (Args&&... parArgs);
|
||||
~SafeStackObject() noexcept = default;
|
||||
|
||||
SafeStackObject& operator= (SafeStackObject&& parOther) = delete;
|
||||
SafeStackObject& operator= (const SafeStackObject& parOther) = delete;
|
||||
|
||||
operator Kakoune::SafePtr<T>&();
|
||||
template <typename U>
|
||||
operator Kakoune::SafePtr<U>();
|
||||
T& operator*();
|
||||
safe_ptr& operator->();
|
||||
|
||||
private:
|
||||
T m_obj;
|
||||
safe_ptr m_obj_ptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
SafeStackObject<T>::SafeStackObject() :
|
||||
m_obj(),
|
||||
m_obj_ptr(&m_obj)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeStackObject<T>::SafeStackObject (SafeStackObject&& parOther) :
|
||||
m_obj(std::move(parOther.m_obj)),
|
||||
m_obj_ptr(&m_obj)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename... Args>
|
||||
SafeStackObject<T>::SafeStackObject (Args&&... parArgs) :
|
||||
m_obj(std::forward<Args>(parArgs)...),
|
||||
m_obj_ptr(&m_obj)
|
||||
{
|
||||
}
|
||||
|
||||
//template <typename T>
|
||||
//SafeStackObject& SafeStackObject<T>::operator= (SafeStackObject&& parOther) {
|
||||
// m_obj = std::move(parOther.m_obj);
|
||||
// m_obj_ptr = std::move(parOther.m_obj_ptr);
|
||||
// m_ob
|
||||
//}
|
||||
|
||||
//template <typename T>
|
||||
//SafeStackObject& SafeStackObject<T>::operator= (const SafeStackObject& parOther) {
|
||||
//}
|
||||
|
||||
template <typename T>
|
||||
SafeStackObject<T>::operator Kakoune::SafePtr<T>&() {
|
||||
return m_obj_ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
SafeStackObject<T>::operator Kakoune::SafePtr<U>() {
|
||||
return Kakoune::SafePtr<U>(&m_obj);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& SafeStackObject<T>::operator*() {
|
||||
return *m_obj_ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto SafeStackObject<T>::operator->() -> safe_ptr& {
|
||||
return m_obj_ptr;
|
||||
}
|
||||
} //namespace curry
|
62
src/tawashi/sanitized_utf8.cpp
Normal file
62
src/tawashi/sanitized_utf8.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sanitized_utf8.hpp"
|
||||
#include <iterator>
|
||||
|
||||
#define SANITIZE_WITH_UTFCPP
|
||||
|
||||
#if defined(SANITIZE_WITH_UTFCPP)
|
||||
# include "utf8.h"
|
||||
# include <algorithm>
|
||||
#else
|
||||
# include <glib.h>
|
||||
# include <cassert>
|
||||
# include <array>
|
||||
#endif
|
||||
|
||||
namespace tawashi {
|
||||
std::string sanitized_utf8 (const boost::string_ref& parStr) {
|
||||
std::string sanitized;
|
||||
sanitized.reserve(parStr.size());
|
||||
#if defined(SANITIZE_WITH_UTFCPP)
|
||||
utf8::replace_invalid(parStr.begin(), parStr.end(), std::back_inserter(sanitized), 0xFFFD);
|
||||
std::replace(sanitized.begin(), sanitized.end(), '\0', '#');
|
||||
#else
|
||||
# error "untested code, don't enable in final builds"
|
||||
std::array<char, 6> replacement;
|
||||
const int replacement_len = g_unichar_to_utf8(0xFFFD, replacement.data());
|
||||
|
||||
std::size_t beg_offset = 0;
|
||||
const char* end;
|
||||
while (not g_utf8_validate(parStr.data() + beg_offset, parStr.size() - beg_offset, &end)) {
|
||||
assert(beg_offset < parStr.size());
|
||||
const std::size_t valid_chunk_size = end - (parStr.data() + beg_offset);
|
||||
sanitized.append(parStr.data() + beg_offset, end);
|
||||
if (*end)
|
||||
sanitized.append(replacement.data(), replacement_len);
|
||||
else
|
||||
sanitized.append({ '#' });
|
||||
beg_offset += valid_chunk_size + 1;
|
||||
assert(beg_offset <= parStr.size());
|
||||
}
|
||||
sanitized.append(parStr.data() + beg_offset, end);
|
||||
assert(g_utf8_validate(sanitized.data(), sanitized.size(), nullptr));
|
||||
#endif
|
||||
return sanitized;
|
||||
}
|
||||
} //namespace tawashi
|
25
src/tawashi/sanitized_utf8.hpp
Normal file
25
src/tawashi/sanitized_utf8.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace tawashi {
|
||||
std::string sanitized_utf8 (const boost::string_ref& parStr);
|
||||
} //namespace tawashi
|
99
src/tawashi/settings_bag.cpp
Normal file
99
src/tawashi/settings_bag.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "settings_bag.hpp"
|
||||
#include "duckhandy/lexical_cast.hpp"
|
||||
#include <ciso646>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
const IniFile::KeyValueMapType* get_tawashi_node (const IniFile& parIni, boost::string_ref parSectionName) {
|
||||
auto it_found = parIni.parsed().find(parSectionName);
|
||||
if (parIni.parsed().end() != it_found) {
|
||||
return &it_found->second;
|
||||
}
|
||||
else {
|
||||
std::cerr << "Couldn't find section [" << parSectionName << "] in the settings file\n";
|
||||
static const IniFile::KeyValueMapType empty_key_values;
|
||||
return &empty_key_values;
|
||||
}
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
SettingsBag::SettingsBag (const Kakoune::SafePtr<IniFile>& parIni, boost::string_ref parSectionName) :
|
||||
m_ini(parIni),
|
||||
m_values(get_tawashi_node(*parIni, parSectionName))
|
||||
{
|
||||
assert(m_values);
|
||||
}
|
||||
|
||||
SettingsBag::~SettingsBag() noexcept = default;
|
||||
|
||||
const boost::string_ref& SettingsBag::operator[] (boost::string_ref parIndex) const {
|
||||
auto it_found = m_values->find(parIndex);
|
||||
if (m_values->end() != it_found)
|
||||
return it_found->second;
|
||||
else
|
||||
return m_defaults.at(parIndex);
|
||||
}
|
||||
|
||||
void SettingsBag::add_default (boost::string_ref parKey, boost::string_ref parValue) {
|
||||
assert(m_defaults.find(parKey) == m_defaults.end());
|
||||
m_defaults[parKey] = parValue;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string SettingsBag::as (boost::string_ref parIndex) const {
|
||||
auto& setting = this->at(parIndex);
|
||||
return std::string(setting.data(), setting.size());
|
||||
}
|
||||
|
||||
template <>
|
||||
bool SettingsBag::as (boost::string_ref parIndex) const {
|
||||
auto& setting = this->at(parIndex);
|
||||
if (setting == "true" or setting == "yes" or setting == "1" or setting == "on") {
|
||||
return true;
|
||||
}
|
||||
else if (setting == "false" or setting == "no" or setting == "0" or setting == "off") {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
std::ostringstream oss;
|
||||
oss << "Bad conversion: can't convert \"" << setting << "\" to bool";
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
uint16_t SettingsBag::as (boost::string_ref parIndex) const {
|
||||
return dhandy::lexical_cast<uint16_t>(this->at(parIndex));
|
||||
}
|
||||
|
||||
template <>
|
||||
uint32_t SettingsBag::as (boost::string_ref parIndex) const {
|
||||
return dhandy::lexical_cast<uint32_t>(this->at(parIndex));
|
||||
}
|
||||
|
||||
template std::string SettingsBag::as<std::string> (boost::string_ref parIndex) const;
|
||||
template bool SettingsBag::as<bool> (boost::string_ref parIndex) const;
|
||||
template uint16_t SettingsBag::as<uint16_t> (boost::string_ref parIndex) const;
|
||||
template uint32_t SettingsBag::as<uint32_t> (boost::string_ref parIndex) const;
|
||||
} //namespace tawashi
|
59
src/tawashi/settings_bag.hpp
Normal file
59
src/tawashi/settings_bag.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ini_file.hpp"
|
||||
#include "kakoune/safe_ptr.hh"
|
||||
#include <map>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#if defined(SPDLOG_DEBUG_ON)
|
||||
# include <spdlog/spdlog.h>
|
||||
#endif
|
||||
|
||||
namespace tawashi {
|
||||
class SettingsBag : public Kakoune::SafeCountable {
|
||||
typedef std::map<boost::string_ref, boost::string_ref> MapType;
|
||||
public:
|
||||
SettingsBag (const Kakoune::SafePtr<IniFile>& parIni, boost::string_ref parSectionName);
|
||||
~SettingsBag() noexcept;
|
||||
|
||||
const boost::string_ref& operator[] (boost::string_ref parIndex) const;
|
||||
const boost::string_ref& at (boost::string_ref parIndex) const;
|
||||
template <typename T> T as (boost::string_ref parIndex) const;
|
||||
void add_default (boost::string_ref parKey, boost::string_ref parValue);
|
||||
|
||||
private:
|
||||
MapType m_defaults;
|
||||
Kakoune::SafePtr<IniFile> m_ini;
|
||||
const IniFile::KeyValueMapType* m_values;
|
||||
};
|
||||
|
||||
template <>
|
||||
inline boost::string_ref SettingsBag::as (boost::string_ref parIndex) const {
|
||||
return (*this)[parIndex];
|
||||
}
|
||||
|
||||
inline const boost::string_ref& SettingsBag::at (boost::string_ref parIndex) const {
|
||||
#if defined(SPDLOG_DEBUG_ON)
|
||||
SPDLOG_DEBUG(spdlog::get("statuslog"), "Retrieving setting \"{}\"", std::string(parIndex.data(), parIndex.size()));
|
||||
#endif
|
||||
return (*this)[parIndex];
|
||||
}
|
||||
} //namespace tawashi
|
28
src/tawashi/spdlog.hpp
Normal file
28
src/tawashi/spdlog.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
namespace spdlog {
|
||||
template <typename OStream>
|
||||
inline OStream& operator<< (OStream& parOS, const boost::string_ref& parStr) {
|
||||
return parOS << parStr;
|
||||
}
|
||||
} //namespace spdlog
|
60
src/tawashi/split_get_vars.cpp
Normal file
60
src/tawashi/split_get_vars.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "split_get_vars.hpp"
|
||||
#include <boost/algorithm/string/finder.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <boost/range/adaptor/filtered.hpp>
|
||||
#include <ciso646>
|
||||
#include <boost/algorithm/string/find_iterator.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/algorithm/find.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
RawKeyValueList split_env_vars (const std::string& parList) {
|
||||
using MatchRange = boost::iterator_range<std::string::const_iterator>;
|
||||
using boost::token_finder;
|
||||
using boost::adaptors::transformed;
|
||||
using boost::adaptors::filtered;
|
||||
using boost::string_ref;
|
||||
using boost::split_iterator;
|
||||
using boost::make_iterator_range;
|
||||
using boost::range::find;
|
||||
|
||||
//See:
|
||||
//https://stackoverflow.com/questions/27999941/how-to-use-boostsplit-with-booststring-ref-in-boost-1-55
|
||||
//http://www.boost.org/doc/libs/1_60_0/doc/html/boost/algorithm/token_finder.html
|
||||
//https://stackoverflow.com/questions/20781090/difference-between-boostsplit-vs-boostiter-split
|
||||
return boost::copy_range<RawKeyValueList>(
|
||||
make_iterator_range(
|
||||
split_iterator<std::string::const_iterator>(parList, token_finder([](char c){return '&'==c;})),
|
||||
split_iterator<std::string::const_iterator>()
|
||||
) |
|
||||
filtered([](const MatchRange& r){ return not r.empty(); }) |
|
||||
transformed([](const MatchRange& r){
|
||||
auto eq = find(r, '=');
|
||||
if (r.empty())
|
||||
return std::pair<string_ref, string_ref>();
|
||||
if (r.end() == eq)
|
||||
return std::make_pair(string_ref(&*r.begin(), r.size()), string_ref());
|
||||
else
|
||||
return std::make_pair(string_ref(&*r.begin(), eq - r.begin()), string_ref(&*(eq + 1), r.size() - (eq - r.begin() + 1)));
|
||||
})
|
||||
);
|
||||
}
|
||||
} //namespace tawashi
|
29
src/tawashi/split_get_vars.hpp
Normal file
29
src/tawashi/split_get_vars.hpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "duckhandy/compatibility.h"
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace tawashi {
|
||||
typedef std::vector<std::pair<boost::string_ref, boost::string_ref>> RawKeyValueList;
|
||||
|
||||
RawKeyValueList split_env_vars ( const std::string& parCommaSeparatedList ) a_pure;
|
||||
} //namespace tawashi
|
59
src/tawashi/string_lengths.hpp
Normal file
59
src/tawashi/string_lengths.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sprout/array/array.hpp"
|
||||
#include "sprout/cstring/strlen.hpp"
|
||||
#include "duckhandy/sequence_bt.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace tawashi {
|
||||
typedef uint16_t string_length_type;
|
||||
|
||||
namespace implem {
|
||||
template <std::size_t I, std::size_t S>
|
||||
inline constexpr string_length_type string_length_at_index (const sprout::array<const char*, S>& parStrings) {
|
||||
return static_cast<string_length_type>(sprout::strlen(parStrings[I]));
|
||||
}
|
||||
|
||||
template <std::size_t... Indices>
|
||||
inline constexpr sprout::array<string_length_type, sizeof...(Indices)> string_lengths (const sprout::array<const char*, sizeof...(Indices)>& parStrings, dhandy::bt::index_seq<Indices...>) {
|
||||
return sprout::array<string_length_type, sizeof...(Indices)> {
|
||||
string_length_at_index<Indices>(parStrings)...
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Enum, std::size_t... Indices>
|
||||
inline constexpr sprout::array<string_length_type, Enum::_size()> string_lengths (const typename Enum::_name_iterable& parEnumIterable, dhandy::bt::index_seq<Indices...>) {
|
||||
return sprout::array<string_length_type, Enum::_size()> {
|
||||
static_cast<string_length_type>(sprout::strlen(parEnumIterable[Indices]))...
|
||||
};
|
||||
}
|
||||
} //namespace implem
|
||||
|
||||
template <std::size_t S>
|
||||
inline constexpr sprout::array<string_length_type, S> string_lengths (const sprout::array<const char*, S>& parStrings) {
|
||||
return implem::string_lengths(parStrings, dhandy::bt::index_range<0, S>());
|
||||
}
|
||||
|
||||
template <typename Enum>
|
||||
inline constexpr sprout::array<string_length_type, Enum::_size()> string_lengths() {
|
||||
return implem::string_lengths<Enum>(Enum::_names(), dhandy::bt::index_range<0, Enum::_size()>());
|
||||
}
|
||||
} //namespace tawashi
|
183
src/tawashi/submit_paste_response.cpp
Normal file
183
src/tawashi/submit_paste_response.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "submit_paste_response.hpp"
|
||||
#include "incredis/incredis.hpp"
|
||||
#include "cgi_post.hpp"
|
||||
#include "num_to_token.hpp"
|
||||
#include "settings_bag.hpp"
|
||||
#include "duckhandy/compatibility.h"
|
||||
#include "duckhandy/lexical_cast.hpp"
|
||||
#include "tawashi_exception.hpp"
|
||||
#include "ip_utils.hpp"
|
||||
#include <ciso646>
|
||||
#include <algorithm>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <cstdint>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
const char g_post_key[] = "pastie";
|
||||
const char g_language_key[] = "lang";
|
||||
const char g_duration_key[] = "ttl";
|
||||
|
||||
class MissingPostVarError : public TawashiException {
|
||||
public:
|
||||
explicit MissingPostVarError(const boost::string_ref& parKey) :
|
||||
TawashiException(
|
||||
ErrorReasons::MissingPostVariable,
|
||||
"Error retrieving POST variable \"" + std::string(parKey.begin(), parKey.end()) + "\""
|
||||
)
|
||||
{}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
inline boost::string_ref make_string_ref (const char (&parStr)[N]) a_always_inline;
|
||||
|
||||
template <std::size_t N>
|
||||
boost::string_ref make_string_ref (const char (&parStr)[N]) {
|
||||
static_assert(N > 0, "wat?");
|
||||
return boost::string_ref(parStr, N - 1);
|
||||
}
|
||||
|
||||
boost::string_ref get_value_from_post (const cgi::PostMapType& parPost, boost::string_ref parKey) {
|
||||
std::string key(parKey.data(), parKey.size());
|
||||
auto post_data_it = parPost.find(key);
|
||||
if (parPost.end() == post_data_it)
|
||||
throw MissingPostVarError(parKey);
|
||||
return post_data_it->second;
|
||||
}
|
||||
|
||||
boost::string_ref get_value_from_post_log_failure (const cgi::PostMapType& parPost, boost::string_ref parKey) {
|
||||
try {
|
||||
return get_value_from_post(parPost, parKey);
|
||||
}
|
||||
catch (const MissingPostVarError& e) {
|
||||
spdlog::get("statuslog")->info(e.what());
|
||||
return boost::string_ref();
|
||||
}
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
SubmitPasteResponse::SubmitPasteResponse (
|
||||
const Kakoune::SafePtr<SettingsBag>& parSettings,
|
||||
std::ostream* parStreamOut,
|
||||
const Kakoune::SafePtr<cgi::Env>& parCgiEnv
|
||||
) :
|
||||
Response(parSettings, parStreamOut, parCgiEnv, true)
|
||||
{
|
||||
}
|
||||
|
||||
HttpHeader SubmitPasteResponse::on_process() {
|
||||
boost::string_ref pastie;
|
||||
boost::string_ref lang;
|
||||
boost::string_ref duration;
|
||||
|
||||
auto statuslog = spdlog::get("statuslog");
|
||||
assert(statuslog);
|
||||
|
||||
const SettingsBag& settings = this->settings();
|
||||
try {
|
||||
auto post = cgi::read_post(std::cin, cgi_env(), settings.as<uint32_t>("max_post_size"));
|
||||
pastie = get_value_from_post(post, make_string_ref(g_post_key));
|
||||
lang = get_value_from_post_log_failure(post, make_string_ref(g_language_key));
|
||||
duration = get_value_from_post_log_failure(post, make_string_ref(g_duration_key));
|
||||
}
|
||||
catch (const UnsupportedContentTypeException& err) {
|
||||
statuslog->info(
|
||||
"Unsupported content type exception: \"{}\"",
|
||||
err.what()
|
||||
);
|
||||
return make_error_redirect(ErrorReasons::UnsupportedContentType);
|
||||
}
|
||||
catch (const TawashiException& e) {
|
||||
statuslog->error(e.what());
|
||||
return make_error_redirect(e.reason());
|
||||
}
|
||||
|
||||
const auto max_sz = settings.as<uint32_t>("max_pastie_size");
|
||||
if (pastie.size() < settings.as<uint32_t>("min_pastie_size")) {
|
||||
return make_error_redirect(ErrorReasons::PostLengthNotInRange);
|
||||
}
|
||||
if (max_sz and pastie.size() > max_sz) {
|
||||
if (settings.as<bool>("truncate_long_pasties")) {
|
||||
pastie = pastie.substr(0, max_sz);
|
||||
}
|
||||
else {
|
||||
return make_error_redirect(ErrorReasons::PostLengthNotInRange);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: replace boost's lexical_cast with mine when I have some checks
|
||||
//over invalid inputs
|
||||
const uint32_t duration_int = std::max(std::min((duration.empty() ? 86400U : boost::lexical_cast<uint32_t>(duration)), 2628000U), 1U);
|
||||
StringOrHeader submit_result = submit_to_redis(pastie, duration_int, lang);
|
||||
const auto& token = submit_result.first;
|
||||
|
||||
if (token) {
|
||||
std::ostringstream oss;
|
||||
oss << *token;
|
||||
statuslog->info("Pastie token=\"{}\" redirect=\"{}\"", *token, oss.str());
|
||||
if (not lang.empty())
|
||||
oss << '?' << lang;
|
||||
|
||||
return this->make_success_response(oss.str());
|
||||
}
|
||||
else {
|
||||
statuslog->info("Empty pastie token (possibly due to a previous failure)");
|
||||
return submit_result.second;
|
||||
}
|
||||
}
|
||||
|
||||
auto SubmitPasteResponse::submit_to_redis (
|
||||
const boost::string_ref& parText,
|
||||
uint32_t parExpiry,
|
||||
const boost::string_ref& parLang
|
||||
) -> StringOrHeader {
|
||||
auto& redis = this->redis();
|
||||
if (not redis.is_connected()) {
|
||||
return std::make_pair(boost::optional<std::string>(), make_error_redirect(ErrorReasons::RedisDisconnected));
|
||||
}
|
||||
|
||||
std::string remote_ip = guess_real_remote_ip(cgi_env());
|
||||
if (redis.get(remote_ip)) {
|
||||
//please wait and submit again
|
||||
return std::make_pair(boost::optional<std::string>(), make_error_redirect(ErrorReasons::UserFlooding));
|
||||
}
|
||||
|
||||
const auto next_id = redis.incr("paste_counter");
|
||||
const std::string token = num_to_token(next_id);
|
||||
assert(not token.empty());
|
||||
if (redis.hmset(token,
|
||||
"pastie", parText,
|
||||
"max_ttl", dhandy::lexical_cast<std::string>(parExpiry),
|
||||
"lang", parLang)
|
||||
) {
|
||||
redis.set(remote_ip, "");
|
||||
redis.expire(remote_ip, settings().as<uint32_t>("resubmit_wait"));
|
||||
if (redis.expire(token, parExpiry))
|
||||
return std::make_pair(boost::make_optional(token), HttpHeader());
|
||||
}
|
||||
|
||||
return std::make_pair(boost::optional<std::string>(), make_error_redirect(ErrorReasons::PastieNotSaved));
|
||||
}
|
||||
|
||||
HttpHeader SubmitPasteResponse::make_success_response (std::string&& parPastieParam) {
|
||||
return this->make_redirect(HttpStatusCodes::Code303_SeeOther, std::move(parPastieParam));
|
||||
}
|
||||
} //namespace tawashi
|
46
src/tawashi/submit_paste_response.hpp
Normal file
46
src/tawashi/submit_paste_response.hpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "response.hpp"
|
||||
#include <string>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
namespace tawashi {
|
||||
class SubmitPasteResponse : public Response {
|
||||
public:
|
||||
SubmitPasteResponse (
|
||||
const Kakoune::SafePtr<SettingsBag>& parSettings,
|
||||
std::ostream* parStreamOut,
|
||||
const Kakoune::SafePtr<cgi::Env>& parCgiEnv
|
||||
);
|
||||
|
||||
protected:
|
||||
virtual boost::string_ref page_basename() const override { assert(false); return boost::string_ref(""); }
|
||||
virtual HttpHeader make_success_response (std::string&& parPastieParam);
|
||||
|
||||
private:
|
||||
typedef std::pair<boost::optional<std::string>, HttpHeader> StringOrHeader;
|
||||
|
||||
virtual HttpHeader on_process() override;
|
||||
StringOrHeader submit_to_redis (const boost::string_ref& parText, uint32_t parExpiry, const boost::string_ref& parLang);
|
||||
};
|
||||
} //namespace tawashi
|
23
src/tawashi/tawashi_config.h.in
Normal file
23
src/tawashi/tawashi_config.h.in
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define VERSION_MAJOR @PROJECT_VERSION_MAJOR@
|
||||
#define VERSION_MINOR @PROJECT_VERSION_MINOR@
|
||||
#define VERSION_PATCH @PROJECT_VERSION_PATCH@
|
||||
#cmakedefine TAWASHI_WITH_IP_LOGGING
|
37
src/tawashi/tawashi_exception.cpp
Normal file
37
src/tawashi/tawashi_exception.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tawashi_exception.hpp"
|
||||
#include <sstream>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
std::string compose_err_message (ErrorReasons parReason, const boost::string_ref& parMessage) {
|
||||
std::ostringstream oss;
|
||||
oss << "Exception with reason " << parReason << ": " << parMessage;
|
||||
return oss.str();
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
TawashiException::TawashiException (ErrorReasons parReason, const boost::string_ref& parMessage) :
|
||||
std::runtime_error(compose_err_message(parReason, parMessage)),
|
||||
m_reason(parReason)
|
||||
{
|
||||
}
|
||||
|
||||
TawashiException::~TawashiException() noexcept = default;
|
||||
} //namespace tawashi
|
35
src/tawashi/tawashi_exception.hpp
Normal file
35
src/tawashi/tawashi_exception.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error_reasons.hpp"
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
class TawashiException : public std::runtime_error {
|
||||
public:
|
||||
TawashiException (ErrorReasons parReason, const boost::string_ref& parMessage);
|
||||
~TawashiException() noexcept;
|
||||
|
||||
ErrorReasons reason() const { return m_reason; }
|
||||
|
||||
private:
|
||||
ErrorReasons m_reason;
|
||||
};
|
||||
} //namespace tawashi
|
1347
src/tawashi/tiger.c
Normal file
1347
src/tawashi/tiger.c
Normal file
File diff suppressed because it is too large
Load diff
125
src/tawashi/tiger.h
Normal file
125
src/tawashi/tiger.h
Normal file
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
* Copyright (c) 2012 Francisco Blas Izquierdo Riera (klondike)
|
||||
* The Tiger algorithm was written by Eli Biham and Ross Anderson and is
|
||||
* available on the official Tiger algorithm page.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* the algorithm authorsip notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
* 4. If this license is not appropriate for you please write me at
|
||||
* klondike ( a t ) klondike ( d o t ) es to negotiate another license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**/
|
||||
|
||||
/**
|
||||
* These are some implementations of tiger made without looking at the original
|
||||
* reference code to ensure the resulting code can be published under a free
|
||||
* license. The paper was looked though to know how did tiger work.
|
||||
*/
|
||||
|
||||
/** Implementation details:
|
||||
* * Here we assume char and unsigned char have size 1. If thats not the case in
|
||||
* your compiler you may want to replace them by a type that does
|
||||
*/
|
||||
|
||||
#ifndef TIGER_H
|
||||
#define TIGER_H 1
|
||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
|
||||
#include <stdint.h>
|
||||
#else
|
||||
|
||||
typedef __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
#endif
|
||||
|
||||
#if _M_IX86_FP >= 2
|
||||
#define __SSE2__
|
||||
#endif
|
||||
|
||||
#ifdef __linux
|
||||
#include <endian.h>
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define IS_LITTLE_ENDIAN
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define USE_BIG_ENDIAN
|
||||
#elif __BYTE_ORDER == __PDP_ENDIAN
|
||||
#error "If you feel like writting code for PDP endianess go ahead, I'm not doing that"
|
||||
#else
|
||||
#error "Unknown endianess"
|
||||
#endif
|
||||
#else
|
||||
//Assume little endian if you know how to detect endianism well on other compilers state it.
|
||||
#define IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64) || defined(__x86_64__) || defined(__amd64__)
|
||||
#define HASX64
|
||||
#endif
|
||||
|
||||
|
||||
/** A word in the tiger hash, 64 bits **/
|
||||
typedef uint64_t t_word;
|
||||
|
||||
/** This one is provided as a commodity for people wanting an easy way to declare result variables **/
|
||||
typedef t_word t_res[3];
|
||||
|
||||
/** Partial calculation as used by tigerp1 and tigerp2 **/
|
||||
typedef struct {
|
||||
t_res h; // Hash status
|
||||
char r[128]; // SALT
|
||||
t_word n; // Number of characters of r used
|
||||
t_word hs; // Amount of total data hashed
|
||||
} t_pres;
|
||||
|
||||
/** This one is provided as a commodity for people wanting an easy way to declare block variables **/
|
||||
typedef t_word t_block[8];
|
||||
|
||||
/** Standard tiger calculation, put your string in str and the string length on length and get the result on res **/
|
||||
void tiger(const char *str, t_word length, t_res res, char pad);
|
||||
/** Similar to tiger but interleaving accesses to both equally sized strings to reduce overhead and pipeline stalls you get the result of str1 on res1 and the one of str2 on res2 **/
|
||||
void tiger_2(const char *str1, const char *str2, t_word length, t_res res1, t_res res2, char pad);
|
||||
#ifdef __SSE2__
|
||||
/** This is equivalent to tiger_2 but uses SSE2 for the key schduling making it faster **/
|
||||
void tiger_sse2(const char *str1, const char *str2, t_word length, t_res res1, t_res res2, char pad);
|
||||
#endif
|
||||
/** This function is optimized for use on TTHs just send the two concatenated hashes and you will get back the hash with a prepended 0x01 **/
|
||||
void tiger_49(const char *str, t_res res);
|
||||
/** This function is optimized for use on TTHs just send the 1024 sized block and you will get back the hash with a prepended 0x00 **/
|
||||
void tiger_1025(const char *str, t_res res);
|
||||
/** Interleaved version of tiger_49 you insert two hashes and get back two results **/
|
||||
void tiger_2_49(const char *str1, const char *str2, t_res res1, t_res res2);
|
||||
/** Interleaved version of tiger_1025 you insert two hashes and get back two results **/
|
||||
void tiger_2_1025(const char *str1, const char *str2, t_res res1, t_res res2);
|
||||
#ifdef __SSE2__
|
||||
/** SSE2 version of tiger_49 you insert two hashes and get back two results **/
|
||||
void tiger_sse2_49(const char *str1, const char *str2, t_res res1, t_res res2);
|
||||
/** SSE2 version of tiger_1025 you insert two hashes and get back two results **/
|
||||
void tiger_sse2_1025(const char *str1, const char *str2, t_res res1, t_res res2);
|
||||
#endif
|
||||
/** First stage of partial tiger calculation to improve password security during storage **/
|
||||
void tigerp1(const char *password, t_word length, const char *salt, t_pres *pres);
|
||||
/** Second stage of partial tiger calculation **/
|
||||
void tigerp2(const t_pres *pres, const char *salt, t_word length, t_res res);
|
||||
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue