mirror of
https://github.com/KingDuckZ/kamokan.git
synced 2025-10-06 15:09:59 +00:00
Split tawashi into lib+executable to enable unit testing
This commit is contained in:
parent
bcb800ffef
commit
e1687c96ff
45 changed files with 175 additions and 78 deletions
57
src/tawashi_implem/CMakeLists.txt
Normal file
57
src/tawashi_implem/CMakeLists.txt
Normal file
|
@ -0,0 +1,57 @@
|
|||
project(tawashi_implem LANGUAGES CXX)
|
||||
|
||||
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_library(${PROJECT_NAME} STATIC
|
||||
split_get_vars.cpp
|
||||
response.cpp
|
||||
submit_paste_response.cpp
|
||||
get_env.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
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PRIVATE ${TAWASHI_GEN_INCLUDE_DIR}
|
||||
PUBLIC ${TAWASHI_SOURCE_ROOT}/lib/kakoune
|
||||
PUBLIC ${TAWASHI_SOURCE_ROOT}/lib/mstch/include
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
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
|
||||
)
|
182
src/tawashi_implem/cgi_env.cpp
Normal file
182
src/tawashi_implem/cgi_env.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
/* 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 <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>
|
||||
|
||||
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>();
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
Env::Env() :
|
||||
m_cgi_env(cgi_environment_vars())
|
||||
{
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
const std::string& Env::path_info() const {
|
||||
return m_cgi_env[CGIVars::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::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];
|
||||
}
|
||||
|
||||
const std::string& Env::request_method() const {
|
||||
return m_cgi_env[CGIVars::REQUEST_METHOD];
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
73
src/tawashi_implem/cgi_env.hpp
Normal file
73
src/tawashi_implem/cgi_env.hpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
/* 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 <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:
|
||||
struct VersionInfo {
|
||||
boost::string_ref name;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
};
|
||||
|
||||
typedef boost::container::flat_map<std::string, std::string> GetMapType;
|
||||
|
||||
Env();
|
||||
~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;
|
||||
const std::string& path_info() const;
|
||||
const std::string& path_translated() const;
|
||||
const std::string& query_string() 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;
|
||||
const std::string& request_method() const;
|
||||
const std::string& script_name() const;
|
||||
const std::string& server_name() 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;
|
||||
|
||||
std::ostream& print_all (std::ostream& parStream, const char* parNewline) const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_cgi_env;
|
||||
Escapist m_houdini;
|
||||
};
|
||||
} //namespace cgi
|
||||
} //namespace tawashi
|
35
src/tawashi_implem/cgi_environment_vars.cpp
Normal file
35
src/tawashi_implem/cgi_environment_vars.cpp
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/>.
|
||||
*/
|
||||
|
||||
#include "cgi_environment_vars.hpp"
|
||||
#include "get_env.hpp"
|
||||
#include <utility>
|
||||
|
||||
namespace tawashi {
|
||||
std::vector<std::string> cgi_environment_vars() {
|
||||
using boost::string_ref;
|
||||
|
||||
std::vector<std::string> retlist;
|
||||
retlist.reserve(CGIVars::_size());
|
||||
|
||||
for (CGIVars var : CGIVars::_values()) {
|
||||
auto value = get_env_as<std::string>(var._to_string(), "");
|
||||
retlist.push_back(std::move(value));
|
||||
}
|
||||
return retlist;
|
||||
}
|
||||
} //namespace tawashi
|
47
src/tawashi_implem/cgi_environment_vars.hpp
Normal file
47
src/tawashi_implem/cgi_environment_vars.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 <vector>
|
||||
#include <string>
|
||||
#include "enum.h"
|
||||
|
||||
namespace tawashi {
|
||||
BETTER_ENUM(CGIVars, std::size_t,
|
||||
AUTH_TYPE = 0,
|
||||
HTTP_USER_AGENT,
|
||||
CONTENT_LENGTH,
|
||||
CONTENT_TYPE,
|
||||
GATEWAY_INTERFACE,
|
||||
PATH_INFO,
|
||||
PATH_TRANSLATED,
|
||||
QUERY_STRING,
|
||||
REMOTE_ADDR,
|
||||
REMOTE_HOST,
|
||||
REMOTE_IDENT,
|
||||
REMOTE_USER,
|
||||
REQUEST_METHOD,
|
||||
SCRIPT_NAME,
|
||||
SERVER_NAME,
|
||||
SERVER_PORT,
|
||||
SERVER_PROTOCOL,
|
||||
SERVER_SOFTWARE
|
||||
);
|
||||
|
||||
std::vector<std::string> cgi_environment_vars();
|
||||
} //namespace tawashi
|
68
src/tawashi_implem/cgi_post.cpp
Normal file
68
src/tawashi_implem/cgi_post.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* 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 {
|
||||
namespace cgi {
|
||||
namespace {
|
||||
} //unnamed namespace
|
||||
|
||||
const PostMapType& read_post (const Env& parEnv) {
|
||||
static bool already_read = false;
|
||||
static PostMapType map;
|
||||
static std::string original_data;
|
||||
|
||||
if (not already_read) {
|
||||
assert(original_data.empty());
|
||||
assert(map.empty());
|
||||
|
||||
const auto input_len = parEnv.content_length();
|
||||
if (input_len > 0) {
|
||||
original_data.reserve(input_len);
|
||||
std::copy_n(
|
||||
std::istream_iterator<char>(std::cin),
|
||||
input_len,
|
||||
std::back_inserter(original_data)
|
||||
);
|
||||
original_data = sanitized_utf8(original_data);
|
||||
|
||||
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
|
32
src/tawashi_implem/cgi_post.hpp
Normal file
32
src/tawashi_implem/cgi_post.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* 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/container/flat_map.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace tawashi {
|
||||
|
||||
namespace cgi {
|
||||
class Env;
|
||||
|
||||
typedef boost::container::flat_map<std::string, std::string> PostMapType;
|
||||
|
||||
const PostMapType& read_post (const Env& parEnv);
|
||||
} //namespace cgi
|
||||
} //namespace tawashi
|
74
src/tawashi_implem/escapist.cpp
Normal file
74
src/tawashi_implem/escapist.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* 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_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
|
46
src/tawashi_implem/escapist.hpp
Normal file
46
src/tawashi_implem/escapist.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 <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_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
|
48
src/tawashi_implem/get_env.cpp
Normal file
48
src/tawashi_implem/get_env.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* 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 "get_env.hpp"
|
||||
#include "duckhandy/lexical_cast.hpp"
|
||||
#include "sanitized_utf8.hpp"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace tawashi {
|
||||
boost::optional<std::string> get_env (const char* parName) {
|
||||
using boost::string_ref;
|
||||
using boost::make_optional;
|
||||
using boost::optional;
|
||||
|
||||
const char* const raw_getvar = secure_getenv(parName);
|
||||
if (raw_getvar)
|
||||
return sanitized_utf8(boost::string_ref(raw_getvar));
|
||||
else
|
||||
return optional<std::string>();
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string get_env_as (const char* parName, const std::string& parDefault) {
|
||||
auto var = get_env(parName);
|
||||
return (var ? *var : parDefault);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::size_t get_env_as (const char* parName, const std::size_t& parDefault) {
|
||||
using dhandy::lexical_cast;
|
||||
auto var = get_env(parName);
|
||||
return (var ? lexical_cast<std::size_t>(*var) : parDefault);
|
||||
}
|
||||
} //namespace tawashi
|
39
src/tawashi_implem/get_env.hpp
Normal file
39
src/tawashi_implem/get_env.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 <boost/utility/string_ref.hpp>
|
||||
#include <string>
|
||||
#if !defined(_GNU_SOURCE)
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
boost::optional<std::string> get_env (const char* parName);
|
||||
|
||||
template <typename A>
|
||||
A get_env_as (const char* parName, const A& parDefault);
|
||||
|
||||
template <>
|
||||
std::string get_env_as (const char* parName, const std::string& parDefault);
|
||||
template <>
|
||||
std::size_t get_env_as (const char* parName, const std::size_t& parDefault);
|
||||
} //namespace tawashi
|
27
src/tawashi_implem/index_response.cpp
Normal file
27
src/tawashi_implem/index_response.cpp
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/>.
|
||||
*/
|
||||
|
||||
#include "index_response.hpp"
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
IndexResponse::IndexResponse (const Kakoune::SafePtr<SettingsBag>& parSettings) :
|
||||
Response(Response::ContentType, "text/html", "index", parSettings, false)
|
||||
{
|
||||
}
|
||||
} //namespace tawashi
|
||||
|
30
src/tawashi_implem/index_response.hpp
Normal file
30
src/tawashi_implem/index_response.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* 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:
|
||||
explicit IndexResponse (const Kakoune::SafePtr<SettingsBag>& parSettings);
|
||||
|
||||
private:
|
||||
};
|
||||
} //namespace tawashi
|
135
src/tawashi_implem/ini_file.cpp
Normal file
135
src/tawashi_implem/ini_file.cpp
Normal file
|
@ -0,0 +1,135 @@
|
|||
/* 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_plus.hpp>
|
||||
#include <boost/spirit/include/qi_raw.hpp>
|
||||
#include <boost/spirit/include/qi_lit.hpp>
|
||||
#include <boost/spirit/include/qi_char_.hpp>
|
||||
#include <boost/spirit/include/qi_kleene.hpp>
|
||||
#include <boost/spirit/include/qi_rule.hpp>
|
||||
#include <boost/spirit/include/qi_as_string.hpp>
|
||||
#include <boost/spirit/include/qi_eol.hpp>
|
||||
#include <boost/spirit/include/qi_grammar.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>
|
||||
|
||||
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_head;
|
||||
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::ascii::space;
|
||||
using boost::spirit::qi::_val;
|
||||
using boost::spirit::_1;
|
||||
using boost::spirit::qi::char_;
|
||||
using boost::spirit::qi::eol;
|
||||
using boost::spirit::qi::raw;
|
||||
using boost::string_ref;
|
||||
typedef IniFile::KeyValueMapType::value_type refpair;
|
||||
|
||||
section_head = '[' >> raw[+(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)
|
||||
)] >> ']' >> eol;
|
||||
key = raw[+(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)
|
||||
)];
|
||||
key_value = key[px::bind(&refpair::first, _val) = _1] >> '=' >>
|
||||
raw[*(char_ - 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)
|
||||
)] >> eol;
|
||||
key_values = *key_value;
|
||||
start = *(section_head >> key_values);
|
||||
}
|
||||
|
||||
IniFile::IniMapType parse_ini (const std::string* parIni) {
|
||||
using boost::spirit::qi::blank;
|
||||
using boost::spirit::qi::blank_type;
|
||||
|
||||
IniGrammar<std::string::const_iterator, blank_type> gramm(parIni);
|
||||
IniFile::IniMapType result;
|
||||
|
||||
std::string::const_iterator start_it = parIni->cbegin();
|
||||
/*const bool parse_ok =*/ boost::spirit::qi::phrase_parse(
|
||||
start_it,
|
||||
parIni->cend(),
|
||||
gramm,
|
||||
blank,
|
||||
result
|
||||
);
|
||||
|
||||
//assert(parse_ok and (parIni->cend() == start_it));
|
||||
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))
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
IniFile::~IniFile() noexcept {
|
||||
}
|
||||
} //namespace tawashi
|
47
src/tawashi_implem/ini_file.hpp
Normal file
47
src/tawashi_implem/ini_file.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 "kakoune/safe_ptr.hh"
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <iterator>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <string>
|
||||
|
||||
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;
|
||||
|
||||
const IniMapType& parsed() const { return m_map; }
|
||||
|
||||
private:
|
||||
std::string m_raw_ini;
|
||||
IniMapType m_map;
|
||||
};
|
||||
} //namespace tawashi
|
34
src/tawashi_implem/list_highlight_langs.cpp
Normal file
34
src/tawashi_implem/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_implem/list_highlight_langs.hpp
Normal file
28
src/tawashi_implem/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_implem/logger.hpp
Normal file
52
src/tawashi_implem/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_implem/logging_levels.hpp
Normal file
33
src/tawashi_implem/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
|
64
src/tawashi_implem/num_to_token.cpp
Normal file
64
src/tawashi_implem/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_implem/num_to_token.hpp
Normal file
26
src/tawashi_implem/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
|
100
src/tawashi_implem/pastie_response.cpp
Normal file
100
src/tawashi_implem/pastie_response.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
/* 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 <ciso646>
|
||||
#include <srchilite/sourcehighlight.h>
|
||||
#include <srchilite/langmap.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
const char g_nolang_token[] = "plaintext";
|
||||
} //unnamed namespace
|
||||
|
||||
PastieResponse::PastieResponse (const Kakoune::SafePtr<SettingsBag>& parSettings) :
|
||||
Response(Response::ContentType, "text/html", "text", parSettings, true),
|
||||
m_langmap_dir(parSettings->as<std::string>("langmap_dir")),
|
||||
m_plain_text(false),
|
||||
m_syntax_highlight(true)
|
||||
{
|
||||
}
|
||||
|
||||
void PastieResponse::on_process() {
|
||||
auto env = cgi_env().query_string_split();
|
||||
const std::string& query_str(cgi_env().query_string());
|
||||
if (env["m"] == "plain" or query_str.empty()) {
|
||||
this->change_type(Response::ContentType, "text/plain; charset=utf-8");
|
||||
m_plain_text = true;
|
||||
}
|
||||
else if (query_str == g_nolang_token) {
|
||||
m_syntax_highlight = false;
|
||||
}
|
||||
else {
|
||||
srchilite::LangMap lang_map(m_langmap_dir, "lang.map");
|
||||
lang_map.open();
|
||||
if (not query_str.empty())
|
||||
m_lang_file = lang_map.getFileName(query_str);
|
||||
else
|
||||
m_lang_file = "default.lang";
|
||||
}
|
||||
}
|
||||
|
||||
void PastieResponse::on_mustache_prepare (mstch::map& parContext) {
|
||||
using opt_string = redis::IncRedis::opt_string;
|
||||
using opt_string_list = redis::IncRedis::opt_string_list;
|
||||
|
||||
auto token = boost::string_ref(cgi_env().path_info()).substr(1);
|
||||
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());
|
||||
|
||||
srchilite::SourceHighlight highlighter;
|
||||
highlighter.setDataDir(settings().as<std::string>("langmap_dir"));
|
||||
highlighter.setGenerateEntireDoc(false);
|
||||
highlighter.setGenerateLineNumbers(true);
|
||||
const auto lang = m_lang_file;
|
||||
|
||||
std::string processed_pastie;
|
||||
if (m_syntax_highlight) {
|
||||
processed_pastie = std::move(*pastie);
|
||||
}
|
||||
else {
|
||||
Escapist houdini;
|
||||
processed_pastie = houdini.escape_html(*pastie);
|
||||
}
|
||||
|
||||
if (not m_plain_text and m_syntax_highlight) {
|
||||
std::istringstream iss(std::move(processed_pastie));
|
||||
std::ostringstream oss;
|
||||
highlighter.highlight(iss, oss, lang);
|
||||
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
|
39
src/tawashi_implem/pastie_response.hpp
Normal file
39
src/tawashi_implem/pastie_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 <string>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
class PastieResponse : public Response {
|
||||
public:
|
||||
explicit PastieResponse (const Kakoune::SafePtr<SettingsBag>& parSettings);
|
||||
|
||||
private:
|
||||
virtual void 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;
|
||||
};
|
||||
} //namespace tawashi
|
254
src/tawashi_implem/pathname/pathname.cpp
Normal file
254
src/tawashi_implem/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_implem/pathname/pathname.hpp
Normal file
67
src/tawashi_implem/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_implem/pathname/stringpool.hpp
Normal file
70
src/tawashi_implem/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_implem/pathname/stringpool.inl
Normal file
140
src/tawashi_implem/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
|
231
src/tawashi_implem/response.cpp
Normal file
231
src/tawashi_implem/response.cpp
Normal file
|
@ -0,0 +1,231 @@
|
|||
/* 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 "tawashiConfig.h"
|
||||
#include "duckhandy/stringize.h"
|
||||
#include "pathname/pathname.hpp"
|
||||
#include "list_highlight_langs.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 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 std::string& parName, bool parThrow) {
|
||||
std::ostringstream oss;
|
||||
oss << parWebsiteRoot << parName << parSuffix;
|
||||
spdlog::get("statuslog")->debug("Trying to load \"{}\"", oss.str());
|
||||
std::ifstream if_mstch(oss.str(), std::ios::binary | std::ios::in);
|
||||
|
||||
if (not if_mstch) {
|
||||
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;
|
||||
};
|
||||
} //unnamed namespace
|
||||
|
||||
Response::Response (Types parRespType, std::string&& parValue, std::string&& parPageBaseName, const Kakoune::SafePtr<SettingsBag>& parSettings, bool parWantRedis) :
|
||||
m_resp_value(std::move(parValue)),
|
||||
//m_page_basename(fetch_page_basename(m_cgi_env)),
|
||||
m_settings(parSettings),
|
||||
m_website_root(make_root_path(*parSettings)),
|
||||
m_page_basename(std::move(parPageBaseName)),
|
||||
m_resp_type(parRespType),
|
||||
m_header_sent(false)
|
||||
{
|
||||
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 to {}; size: {}",
|
||||
cgi_env().request_method(),
|
||||
cgi_env().query_string(),
|
||||
cgi_env().content_length()
|
||||
);
|
||||
}
|
||||
|
||||
Response::~Response() noexcept = default;
|
||||
|
||||
void Response::on_process() {
|
||||
}
|
||||
|
||||
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", m_settings->as<std::string>("base_uri")},
|
||||
{"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");
|
||||
this->on_process();
|
||||
SPDLOG_TRACE(statuslog, "Raising event on_mustache_prepare");
|
||||
this->on_mustache_prepare(mustache_context);
|
||||
|
||||
m_header_sent = true;
|
||||
switch (m_resp_type) {
|
||||
case ContentType:
|
||||
SPDLOG_TRACE(statuslog, "Response is a Content-type (data)");
|
||||
std::cout << "Content-type: " << m_resp_value << "\n\n";
|
||||
break;
|
||||
case Location:
|
||||
SPDLOG_TRACE(statuslog, "Response is a Location (redirect)");
|
||||
std::cout << "Location: " << m_resp_value << "\n\n";
|
||||
break;
|
||||
}
|
||||
|
||||
SPDLOG_TRACE(statuslog, "Rendering in mustache");
|
||||
std::cout << 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");
|
||||
std::cout.flush();
|
||||
}
|
||||
|
||||
std::string Response::on_mustache_retrieve() {
|
||||
return load_mustache();
|
||||
}
|
||||
|
||||
const cgi::Env& Response::cgi_env() const {
|
||||
return m_cgi_env;
|
||||
}
|
||||
|
||||
void Response::change_type (Types parRespType, std::string&& parValue) {
|
||||
assert(not m_header_sent);
|
||||
assert(not parValue.empty());
|
||||
m_resp_type = parRespType;
|
||||
m_resp_value = std::move(parValue);
|
||||
}
|
||||
|
||||
const boost::string_ref& Response::base_uri() const {
|
||||
return m_settings->at("base_uri");
|
||||
}
|
||||
|
||||
const std::string& Response::page_basename() const {
|
||||
return m_page_basename;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
} //namespace tawashi
|
70
src/tawashi_implem/response.hpp
Normal file
70
src/tawashi_implem/response.hpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/* 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 "cgi_env.hpp"
|
||||
#include "mstch/mstch.hpp"
|
||||
#include "kakoune/safe_ptr.hh"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace redis {
|
||||
class IncRedis;
|
||||
} //namespace redis
|
||||
|
||||
namespace tawashi {
|
||||
class SettingsBag;
|
||||
|
||||
class Response {
|
||||
public:
|
||||
virtual ~Response() noexcept;
|
||||
|
||||
void send();
|
||||
|
||||
protected:
|
||||
enum Types {
|
||||
ContentType,
|
||||
Location
|
||||
};
|
||||
|
||||
Response (Types parRespType, std::string&& parValue, std::string&& parPageBaseName, const Kakoune::SafePtr<SettingsBag>& parSettings, bool parWantRedis);
|
||||
const cgi::Env& cgi_env() const;
|
||||
void change_type (Types parRespType, std::string&& parValue);
|
||||
const boost::string_ref& base_uri() const;
|
||||
const std::string& page_basename() const;
|
||||
redis::IncRedis& redis() const;
|
||||
const SettingsBag& settings() const;
|
||||
virtual std::string load_mustache() const;
|
||||
|
||||
private:
|
||||
virtual void on_process();
|
||||
virtual void on_mustache_prepare (mstch::map& parContext);
|
||||
virtual std::string on_mustache_retrieve();
|
||||
|
||||
cgi::Env m_cgi_env;
|
||||
std::string m_resp_value;
|
||||
Kakoune::SafePtr<SettingsBag> m_settings;
|
||||
std::string m_website_root;
|
||||
std::string m_page_basename;
|
||||
Types m_resp_type;
|
||||
std::unique_ptr<redis::IncRedis> m_redis;
|
||||
bool m_header_sent;
|
||||
};
|
||||
} //namespace tawashi
|
64
src/tawashi_implem/response_factory.cpp
Normal file
64
src/tawashi_implem/response_factory.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 "response_factory.hpp"
|
||||
#include "settings_bag.hpp"
|
||||
#include <functional>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
} //unnamed namespace
|
||||
|
||||
struct ResponseFactory::LocalData {
|
||||
Kakoune::SafePtr<SettingsBag> settings;
|
||||
boost::container::flat_map<std::string, ResponseMakerFunc> makers;
|
||||
ResponseMakerFunc jolly_maker;
|
||||
};
|
||||
|
||||
ResponseFactory::ResponseFactory (const Kakoune::SafePtr<SettingsBag>& parSettings) :
|
||||
m_local_data(std::make_unique<LocalData>())
|
||||
{
|
||||
m_local_data->settings = parSettings;
|
||||
}
|
||||
|
||||
ResponseFactory::~ResponseFactory() noexcept = default;
|
||||
|
||||
std::unique_ptr<Response> ResponseFactory::make_response (const boost::string_ref& parName) {
|
||||
//spdlog::get("statuslog")->info("making response object for \"{}\"", parName);
|
||||
|
||||
auto maker_it = m_local_data->makers.find(std::string(parName.data(), parName.size()));
|
||||
if (m_local_data->makers.end() != maker_it) {
|
||||
return maker_it->second(m_local_data->settings);
|
||||
}
|
||||
else if (m_local_data->jolly_maker) {
|
||||
return m_local_data->jolly_maker(m_local_data->settings);
|
||||
}
|
||||
else {
|
||||
assert(false);
|
||||
return std::unique_ptr<Response>();
|
||||
}
|
||||
}
|
||||
|
||||
void ResponseFactory::register_maker (std::string&& parName, ResponseMakerFunc parMaker) {
|
||||
m_local_data->makers[std::move(parName)] = parMaker;
|
||||
}
|
||||
|
||||
void ResponseFactory::register_jolly_maker (ResponseMakerFunc parMaker) {
|
||||
m_local_data->jolly_maker = parMaker;
|
||||
}
|
||||
} //namespace tawashi
|
43
src/tawashi_implem/response_factory.hpp
Normal file
43
src/tawashi_implem/response_factory.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* 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 <memory>
|
||||
|
||||
namespace tawashi {
|
||||
class SettingsBag;
|
||||
|
||||
class ResponseFactory {
|
||||
public:
|
||||
typedef std::function<std::unique_ptr<Response>(const Kakoune::SafePtr<SettingsBag>&)> ResponseMakerFunc;
|
||||
|
||||
explicit ResponseFactory (const Kakoune::SafePtr<SettingsBag>& parSettings);
|
||||
~ResponseFactory() noexcept;
|
||||
|
||||
std::unique_ptr<Response> make_response(const boost::string_ref& parName);
|
||||
void register_maker (std::string&& parName, ResponseMakerFunc parMaker);
|
||||
void register_jolly_maker (ResponseMakerFunc parMaker);
|
||||
|
||||
private:
|
||||
struct LocalData;
|
||||
|
||||
std::unique_ptr<LocalData> m_local_data;
|
||||
};
|
||||
} //namespace tawashi
|
96
src/tawashi_implem/safe_stack_object.hpp
Normal file
96
src/tawashi_implem/safe_stack_object.hpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
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>&();
|
||||
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>
|
||||
T& SafeStackObject<T>::operator*() {
|
||||
return *m_obj_ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto SafeStackObject<T>::operator->() -> safe_ptr& {
|
||||
return m_obj_ptr;
|
||||
}
|
||||
} //namespace curry
|
29
src/tawashi_implem/sanitized_utf8.cpp
Normal file
29
src/tawashi_implem/sanitized_utf8.cpp
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/>.
|
||||
*/
|
||||
|
||||
#include "sanitized_utf8.hpp"
|
||||
#include "utf8.h"
|
||||
#include <iterator>
|
||||
|
||||
namespace tawashi {
|
||||
std::string sanitized_utf8 (const boost::string_ref& parStr) {
|
||||
std::string sanitized;
|
||||
sanitized.reserve(parStr.size());
|
||||
utf8::replace_invalid(parStr.begin(), parStr.end(), std::back_inserter(sanitized));
|
||||
return sanitized;
|
||||
}
|
||||
} //namespace tawashi
|
25
src/tawashi_implem/sanitized_utf8.hpp
Normal file
25
src/tawashi_implem/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_implem/settings_bag.cpp
Normal file
99
src/tawashi_implem/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 <spdlog/spdlog.h>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
const IniFile::KeyValueMapType* get_tawashi_node (const IniFile& parIni) {
|
||||
auto it_found = parIni.parsed().find("tawashi");
|
||||
if (parIni.parsed().end() != it_found) {
|
||||
return &it_found->second;
|
||||
}
|
||||
else {
|
||||
spdlog::get("statuslog")->warn("Couldn't find section [tawashi] in the settings file");
|
||||
static const IniFile::KeyValueMapType empty_key_values;
|
||||
return &empty_key_values;
|
||||
}
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
SettingsBag::SettingsBag (const Kakoune::SafePtr<IniFile>& parIni) :
|
||||
m_ini(parIni),
|
||||
m_values(get_tawashi_node(*parIni))
|
||||
{
|
||||
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_implem/settings_bag.hpp
Normal file
59
src/tawashi_implem/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:
|
||||
explicit SettingsBag (const Kakoune::SafePtr<IniFile>& parIni);
|
||||
~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_implem/spdlog.hpp
Normal file
28
src/tawashi_implem/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_implem/split_get_vars.cpp
Normal file
60
src/tawashi_implem/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_implem/split_get_vars.hpp
Normal file
29
src/tawashi_implem/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
|
130
src/tawashi_implem/submit_paste_response.cpp
Normal file
130
src/tawashi_implem/submit_paste_response.cpp
Normal file
|
@ -0,0 +1,130 @@
|
|||
/* 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 <ciso646>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
const char g_post_key[] = "pastie";
|
||||
const char g_language_key[] = "lang";
|
||||
const char g_duration_key[] = "ttl";
|
||||
|
||||
class MissingPostVarError : public std::runtime_error {
|
||||
public:
|
||||
MissingPostVarError (const std::string& parMsg) : std::runtime_error(parMsg) {}
|
||||
};
|
||||
|
||||
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) {
|
||||
std::ostringstream oss;
|
||||
oss << "can't find POST data field \"" << parKey << '"';
|
||||
throw MissingPostVarError(oss.str());
|
||||
}
|
||||
return post_data_it->second;
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
SubmitPasteResponse::SubmitPasteResponse (const Kakoune::SafePtr<SettingsBag>& parSettings) :
|
||||
Response(Response::ContentType, "text/plain", "paste", parSettings, true)
|
||||
{
|
||||
}
|
||||
|
||||
void SubmitPasteResponse::on_process() {
|
||||
auto post = cgi::read_post(cgi_env());
|
||||
boost::string_ref pastie;
|
||||
boost::string_ref lang;
|
||||
boost::string_ref duration;
|
||||
try {
|
||||
pastie = get_value_from_post(post, make_string_ref(g_post_key));
|
||||
}
|
||||
catch (const MissingPostVarError& e) {
|
||||
m_error_message = e.what();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
lang = get_value_from_post(post, make_string_ref(g_language_key));
|
||||
duration = get_value_from_post(post, make_string_ref(g_duration_key));
|
||||
}
|
||||
catch (const MissingPostVarError&) {
|
||||
}
|
||||
|
||||
const SettingsBag& settings = this->settings();
|
||||
const auto max_sz = settings.as<uint32_t>("max_pastie_size");
|
||||
if (pastie.size() < settings.as<uint32_t>("min_pastie_size"))
|
||||
return;
|
||||
if (max_sz and pastie.size() > max_sz) {
|
||||
if (settings.as<bool>("truncate_long_pasties"))
|
||||
pastie = pastie.substr(0, max_sz);
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
//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);
|
||||
boost::optional<std::string> token = submit_to_redis(pastie, duration_int, lang);
|
||||
if (token) {
|
||||
std::ostringstream oss;
|
||||
oss << base_uri() << '/' << *token;
|
||||
if (not lang.empty())
|
||||
oss << '?' << lang;
|
||||
this->change_type(Response::Location, oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
boost::optional<std::string> SubmitPasteResponse::submit_to_redis (const boost::string_ref& parText, uint32_t parExpiry, const boost::string_ref& parLang) const {
|
||||
auto& redis = this->redis();
|
||||
if (not redis.is_connected())
|
||||
return boost::optional<std::string>();
|
||||
|
||||
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)
|
||||
) {
|
||||
if (redis.expire(token, parExpiry))
|
||||
return boost::make_optional(token);
|
||||
}
|
||||
|
||||
return boost::optional<std::string>();
|
||||
}
|
||||
} //namespace tawashi
|
36
src/tawashi_implem/submit_paste_response.hpp
Normal file
36
src/tawashi_implem/submit_paste_response.hpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* 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>
|
||||
|
||||
namespace tawashi {
|
||||
class SubmitPasteResponse : public Response {
|
||||
public:
|
||||
explicit SubmitPasteResponse (const Kakoune::SafePtr<SettingsBag>& parSettings);
|
||||
|
||||
private:
|
||||
virtual void on_process() override;
|
||||
boost::optional<std::string> submit_to_redis (const boost::string_ref& parText, uint32_t parExpiry, const boost::string_ref& parLang) const;
|
||||
|
||||
std::string m_error_message;
|
||||
};
|
||||
} //namespace tawashi
|
Loading…
Add table
Add a link
Reference in a new issue