mirror of
https://github.com/KingDuckZ/kamokan.git
synced 2025-02-17 09:35:49 +00:00
Add CurlWrapper class and use it to escape GET/POST values.
Use the new code to print the values from the request.
This commit is contained in:
parent
6a502df135
commit
cc20a8ccfb
10 changed files with 143 additions and 17 deletions
|
@ -1,6 +1,7 @@
|
||||||
project(tawashi CXX)
|
project(tawashi CXX)
|
||||||
|
|
||||||
find_package(Boost 1.53.0 REQUIRED COMPONENTS program_options filesystem system)
|
find_package(Boost 1.53.0 REQUIRED COMPONENTS program_options filesystem system)
|
||||||
|
find_package(CURL REQUIRED)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
@ -15,15 +16,18 @@ add_executable(${PROJECT_NAME}
|
||||||
cgi_env.cpp
|
cgi_env.cpp
|
||||||
num_to_token.cpp
|
num_to_token.cpp
|
||||||
cgi_post.cpp
|
cgi_post.cpp
|
||||||
|
curl_wrapper.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} SYSTEM
|
target_include_directories(${PROJECT_NAME} SYSTEM
|
||||||
PRIVATE ${Boost_INCLUDE_DIRS}
|
PRIVATE ${Boost_INCLUDE_DIRS}
|
||||||
PRIVATE ${TAWASHI_SOURCE_ROOT}/lib/bette-enums
|
PRIVATE ${TAWASHI_SOURCE_ROOT}/lib/bette-enums
|
||||||
|
PRIVATE ${CURL_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
target_link_libraries(${PROJECT_NAME}
|
target_link_libraries(${PROJECT_NAME}
|
||||||
PRIVATE ${Boost_LIBRARIES}
|
PRIVATE ${Boost_LIBRARIES}
|
||||||
PRIVATE incredis
|
PRIVATE incredis
|
||||||
|
${CURL_LIBRARIES}
|
||||||
)
|
)
|
||||||
target_compile_definitions(${PROJECT_NAME}
|
target_compile_definitions(${PROJECT_NAME}
|
||||||
PRIVATE BOOST_SPIRIT_USE_PHOENIX_V3=1
|
PRIVATE BOOST_SPIRIT_USE_PHOENIX_V3=1
|
||||||
|
|
|
@ -29,7 +29,6 @@ namespace tawashi {
|
||||||
using boost::spirit::ascii::space;
|
using boost::spirit::ascii::space;
|
||||||
using boost::spirit::qi::raw;
|
using boost::spirit::qi::raw;
|
||||||
using boost::spirit::qi::char_;
|
using boost::spirit::qi::char_;
|
||||||
using boost::spirit::qi::int_;
|
|
||||||
using boost::string_ref;
|
using boost::string_ref;
|
||||||
using VerNum = boost::spirit::qi::uint_parser<uint16_t, 10, 1, 1>;
|
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 RuleType = boost::spirit::qi::rule<std::string::const_iterator, string_ref(), boost::spirit::ascii::space_type>;
|
||||||
|
@ -143,8 +142,14 @@ namespace tawashi {
|
||||||
return m_cgi_env[CGIVars::SERVER_SOFTWARE];
|
return m_cgi_env[CGIVars::SERVER_SOFTWARE];
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyValueList CGIEnv::query_string_split() const {
|
CGIEnv::GetMapType CGIEnv::query_string_split() const {
|
||||||
return split_env_vars(m_cgi_env[CGIVars::QUERY_STRING]);
|
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_curl.url_unescape(itm.first)] = m_curl.url_unescape(itm.second);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& CGIEnv::print_all (std::ostream& parStream, const char* parNewline) const {
|
std::ostream& CGIEnv::print_all (std::ostream& parStream, const char* parNewline) const {
|
||||||
|
|
|
@ -2,12 +2,14 @@
|
||||||
|
|
||||||
#include "split_get_vars.hpp"
|
#include "split_get_vars.hpp"
|
||||||
#include "duckhandy/compatibility.h"
|
#include "duckhandy/compatibility.h"
|
||||||
|
#include "curl_wrapper.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <boost/utility/string_ref.hpp>
|
#include <boost/utility/string_ref.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
#include <boost/container/flat_map.hpp>
|
||||||
|
|
||||||
namespace tawashi {
|
namespace tawashi {
|
||||||
class CGIEnv {
|
class CGIEnv {
|
||||||
|
@ -18,6 +20,8 @@ namespace tawashi {
|
||||||
uint16_t minor;
|
uint16_t minor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef boost::container::flat_map<std::string, std::string> GetMapType;
|
||||||
|
|
||||||
CGIEnv();
|
CGIEnv();
|
||||||
~CGIEnv() noexcept;
|
~CGIEnv() noexcept;
|
||||||
|
|
||||||
|
@ -39,11 +43,12 @@ namespace tawashi {
|
||||||
boost::optional<VersionInfo> server_protocol() const a_pure;
|
boost::optional<VersionInfo> server_protocol() const a_pure;
|
||||||
const std::string& server_software() const;
|
const std::string& server_software() const;
|
||||||
|
|
||||||
KeyValueList query_string_split() const a_pure;
|
GetMapType query_string_split() const a_pure;
|
||||||
|
|
||||||
std::ostream& print_all (std::ostream& parStream, const char* parNewline) const;
|
std::ostream& print_all (std::ostream& parStream, const char* parNewline) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> m_cgi_env;
|
std::vector<std::string> m_cgi_env;
|
||||||
|
CurlWrapper m_curl;
|
||||||
};
|
};
|
||||||
} //namespace tawashi
|
} //namespace tawashi
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "cgi_post.hpp"
|
#include "cgi_post.hpp"
|
||||||
#include "cgi_env.hpp"
|
#include "cgi_env.hpp"
|
||||||
#include "split_get_vars.hpp"
|
#include "split_get_vars.hpp"
|
||||||
|
#include "curl_wrapper.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -31,8 +32,9 @@ namespace tawashi {
|
||||||
std::back_inserter(original_data)
|
std::back_inserter(original_data)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CurlWrapper curl;
|
||||||
for (auto& itm : split_env_vars(original_data)) {
|
for (auto& itm : split_env_vars(original_data)) {
|
||||||
map[itm.first] = itm.second;
|
map[curl.url_unescape(itm.first)] = curl.url_unescape(itm.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <boost/container/flat_map.hpp>
|
#include <boost/container/flat_map.hpp>
|
||||||
#include <boost/utility/string_ref.hpp>
|
#include <string>
|
||||||
|
|
||||||
namespace tawashi {
|
namespace tawashi {
|
||||||
class CGIEnv;
|
class CGIEnv;
|
||||||
|
|
||||||
namespace cgi {
|
namespace cgi {
|
||||||
typedef boost::container::flat_map<boost::string_ref, boost::string_ref> PostMapType;
|
typedef boost::container::flat_map<std::string, std::string> PostMapType;
|
||||||
|
|
||||||
const PostMapType& read_post (const CGIEnv& parEnv);
|
const PostMapType& read_post (const CGIEnv& parEnv);
|
||||||
} //namespace cgi
|
} //namespace cgi
|
||||||
|
|
87
src/curl_wrapper.cpp
Normal file
87
src/curl_wrapper.cpp
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#include "curl_wrapper.hpp"
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <cassert>
|
||||||
|
#include <ciso646>
|
||||||
|
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
# define CURL_WRAPPER_VERBOSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CURL_WRAPPER_VERBOSE)
|
||||||
|
# include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace tawashi {
|
||||||
|
namespace {
|
||||||
|
struct CurlDeleter {
|
||||||
|
void operator() (CURL* parCurl) const {
|
||||||
|
#if defined(CURL_WRAPPER_VERBOSE)
|
||||||
|
std::cout << "Deleting CURL* " << parCurl << " and cleaning up\n";
|
||||||
|
#endif
|
||||||
|
assert(parCurl);
|
||||||
|
curl_easy_cleanup(parCurl);
|
||||||
|
curl_global_cleanup();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CurlBufferDeleter {
|
||||||
|
void operator() (char* parPtr) {
|
||||||
|
assert(parPtr);
|
||||||
|
curl_free(parPtr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::unique_ptr<char, CurlBufferDeleter> CurlBufferPointer;
|
||||||
|
|
||||||
|
CurlWrapper::CurlPtr get_new_curl() {
|
||||||
|
static std::weak_ptr<CURL> curl;
|
||||||
|
|
||||||
|
#if defined(CURL_WRAPPER_VERBOSE)
|
||||||
|
std::cout << "CURL object requested\n";
|
||||||
|
#endif
|
||||||
|
auto shared = curl.lock();
|
||||||
|
if (not shared) {
|
||||||
|
#if defined(CURL_WRAPPER_VERBOSE)
|
||||||
|
std::cout << "CURL weak pointer has expired! Calling curl_global_init()\n";
|
||||||
|
#endif
|
||||||
|
if (curl_global_init(CURL_GLOBAL_ALL))
|
||||||
|
return CurlWrapper::CurlPtr();
|
||||||
|
#if defined(CURL_WRAPPER_VERBOSE)
|
||||||
|
std::cout << "Calling curl_easy_init()\n";
|
||||||
|
#endif
|
||||||
|
shared.reset(curl_easy_init(), CurlDeleter());
|
||||||
|
|
||||||
|
if (not shared) {
|
||||||
|
curl_global_cleanup();
|
||||||
|
return CurlWrapper::CurlPtr();
|
||||||
|
}
|
||||||
|
curl = shared;
|
||||||
|
}
|
||||||
|
#if defined(CURL_WRAPPER_VERBOSE)
|
||||||
|
std::cout << "CURL shared pointer ready: " << shared.get() << '\n';
|
||||||
|
#endif
|
||||||
|
assert(shared);
|
||||||
|
return shared;
|
||||||
|
}
|
||||||
|
} //unnamed namespace
|
||||||
|
|
||||||
|
CurlWrapper::CurlWrapper() :
|
||||||
|
m_curl(get_new_curl())
|
||||||
|
{
|
||||||
|
assert(m_curl);
|
||||||
|
}
|
||||||
|
|
||||||
|
CurlWrapper::~CurlWrapper() noexcept = default;
|
||||||
|
|
||||||
|
std::string CurlWrapper::url_escape (const boost::string_ref& parText) const {
|
||||||
|
const CurlBufferPointer buff(curl_easy_escape(m_curl.get(), parText.data(), parText.size()));
|
||||||
|
return std::string(buff.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CurlWrapper::url_unescape (const boost::string_ref& parText) const {
|
||||||
|
int outLen;
|
||||||
|
const CurlBufferPointer buff(curl_easy_unescape(m_curl.get(), parText.data(), parText.size(), &outLen));
|
||||||
|
return std::string(buff.get(), outLen);
|
||||||
|
}
|
||||||
|
} //namespace tawashi
|
||||||
|
|
24
src/curl_wrapper.hpp
Normal file
24
src/curl_wrapper.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/utility/string_ref.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
typedef void CURL;
|
||||||
|
|
||||||
|
namespace tawashi {
|
||||||
|
class CurlWrapper {
|
||||||
|
public:
|
||||||
|
typedef std::shared_ptr<CURL> CurlPtr;
|
||||||
|
|
||||||
|
CurlWrapper();
|
||||||
|
CurlWrapper (const CurlWrapper&) = delete;
|
||||||
|
~CurlWrapper() noexcept;
|
||||||
|
|
||||||
|
std::string url_escape (const boost::string_ref& parText) const;
|
||||||
|
std::string url_unescape (const boost::string_ref& parText) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CurlPtr m_curl;
|
||||||
|
};
|
||||||
|
} //namespace tawashi
|
11
src/main.cpp
11
src/main.cpp
|
@ -1,10 +1,9 @@
|
||||||
#include "incredis/incredis.hpp"
|
#include "incredis/incredis.hpp"
|
||||||
#include "submit_form_response.hpp"
|
#include "submit_form_response.hpp"
|
||||||
#include "cgi_env.hpp"
|
#include "cgi_env.hpp"
|
||||||
|
#include "cgi_post.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
//www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4150.pdf
|
//www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4150.pdf
|
||||||
|
|
||||||
|
@ -30,10 +29,10 @@ int main() {
|
||||||
std::cout << "Content length: \"" << in_len << "\"\n<br>\n";
|
std::cout << "Content length: \"" << in_len << "\"\n<br>\n";
|
||||||
|
|
||||||
cgi_env.print_all(std::cout, "<br>\n");
|
cgi_env.print_all(std::cout, "<br>\n");
|
||||||
std::string input;
|
for (auto& itm : tawashi::cgi::read_post(cgi_env)) {
|
||||||
if (in_len > 0)
|
std::cout << "Key: \"" << itm.first << "\"<br>\nValue: \"" <<
|
||||||
std::copy_n(std::istream_iterator<char>(std::cin), in_len, std::back_inserter(input));
|
itm.second << "\"<br>\n";
|
||||||
std::cout << input << '\n';
|
}
|
||||||
|
|
||||||
auto ver = cgi_env.gateway_interface();
|
auto ver = cgi_env.gateway_interface();
|
||||||
if (ver)
|
if (ver)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <boost/range/algorithm/find.hpp>
|
#include <boost/range/algorithm/find.hpp>
|
||||||
|
|
||||||
namespace tawashi {
|
namespace tawashi {
|
||||||
KeyValueList split_env_vars (const std::string& parList) {
|
RawKeyValueList split_env_vars (const std::string& parList) {
|
||||||
using MatchRange = boost::iterator_range<std::string::const_iterator>;
|
using MatchRange = boost::iterator_range<std::string::const_iterator>;
|
||||||
using boost::token_finder;
|
using boost::token_finder;
|
||||||
using boost::adaptors::transformed;
|
using boost::adaptors::transformed;
|
||||||
|
@ -23,7 +23,7 @@ namespace tawashi {
|
||||||
//https://stackoverflow.com/questions/27999941/how-to-use-boostsplit-with-booststring-ref-in-boost-1-55
|
//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
|
//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
|
//https://stackoverflow.com/questions/20781090/difference-between-boostsplit-vs-boostiter-split
|
||||||
return boost::copy_range<KeyValueList>(
|
return boost::copy_range<RawKeyValueList>(
|
||||||
make_iterator_range(
|
make_iterator_range(
|
||||||
split_iterator<std::string::const_iterator>(parList, token_finder([](char c){return '&'==c;})),
|
split_iterator<std::string::const_iterator>(parList, token_finder([](char c){return '&'==c;})),
|
||||||
split_iterator<std::string::const_iterator>()
|
split_iterator<std::string::const_iterator>()
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace tawashi {
|
namespace tawashi {
|
||||||
typedef std::vector<std::pair<boost::string_ref, boost::string_ref>> KeyValueList;
|
typedef std::vector<std::pair<boost::string_ref, boost::string_ref>> RawKeyValueList;
|
||||||
|
|
||||||
KeyValueList split_env_vars ( const std::string& parCommaSeparatedList ) a_pure;
|
RawKeyValueList split_env_vars ( const std::string& parCommaSeparatedList ) a_pure;
|
||||||
} //namespace tawashi
|
} //namespace tawashi
|
||||||
|
|
Loading…
Add table
Reference in a new issue