From e6f2cae62404d8f3be44667157387f1e0908f661 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 9 Sep 2021 20:53:22 +0100 Subject: Introduce MaybeString Allows at least a string_view, but maybe a string... used when input might need decoding, but removes the need for a copy when it doesn't. --- icespider/common/maybeString.h | 65 +++++++++++++++++++++++++++++++++++ icespider/core/xwwwFormUrlEncoded.cpp | 12 ++++--- icespider/core/xwwwFormUrlEncoded.h | 5 +-- icespider/fcgi/cgiRequestBase.h | 3 +- 4 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 icespider/common/maybeString.h diff --git a/icespider/common/maybeString.h b/icespider/common/maybeString.h new file mode 100644 index 0000000..b760faa --- /dev/null +++ b/icespider/common/maybeString.h @@ -0,0 +1,65 @@ +#ifndef ICESPIDER_COMMON_MAYBESTRING_H +#define ICESPIDER_COMMON_MAYBESTRING_H + +#include +#include +#include + +namespace IceSpider { + class MaybeString { + public: + MaybeString() { } + + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline MaybeString(std::string s) : value_ {std::move(s)} { } + + // NOLINTNEXTLINE(hicpp-explicit-conversions) + inline MaybeString(std::string_view s) : value_ {std::move(s)} { } + + [[nodiscard]] inline operator std::string_view() const + { + if (value_.index() == 0) { + return std::get<0>(value_); + } + return std::get<1>(value_); + } + + [[nodiscard]] inline std::string_view + value() const + { + return *this; + } + + [[nodiscard]] inline bool + isString() const + { + return value_.index() > 0; + } + + [[nodiscard]] inline bool + operator<(const MaybeString & o) const + { + return value() < o.value(); + } + + [[nodiscard]] inline bool + operator<(const std::string_view & o) const + { + return value() < o; + } + + private: + using value_type = std::variant; + value_type value_; + }; +}; + +namespace std { + inline std::ostream & + operator<<(std::ostream & s, const IceSpider::MaybeString & ms) + { + return s << ms.value(); + } +} + +#endif diff --git a/icespider/core/xwwwFormUrlEncoded.cpp b/icespider/core/xwwwFormUrlEncoded.cpp index e594bb0..7a785bd 100644 --- a/icespider/core/xwwwFormUrlEncoded.cpp +++ b/icespider/core/xwwwFormUrlEncoded.cpp @@ -108,6 +108,7 @@ namespace IceSpider { static constexpr const std::string_view FALSE = "false"; static constexpr const std::string_view KEY = "key"; static constexpr const std::string_view VALUE = "value"; + static constexpr const std::string_view URL_ESCAPES = "%+"; XWwwFormUrlEncoded::XWwwFormUrlEncoded(std::istream & in) : input(std::istreambuf_iterator(in), std::istreambuf_iterator()) @@ -139,7 +140,7 @@ namespace IceSpider { class SetFromString : public Slicer::ValueSource { public: - explicit SetFromString(const std::string & v) : s(v) { } + explicit SetFromString(const MaybeString & v) : s(v) { } void set(bool & t) const override @@ -176,7 +177,7 @@ namespace IceSpider { SET(Ice::Double); private: - const std::string & s; + const MaybeString & s; }; std::string @@ -219,9 +220,12 @@ namespace IceSpider { urlencoderange(std::ostream_iterator(o), i, e); } - std::string + MaybeString XWwwFormUrlEncoded::urldecode(std::string_view::const_iterator i, std::string_view::const_iterator e) { + if (std::find_first_of(i, e, URL_ESCAPES.begin(), URL_ESCAPES.end()) == e) { + return std::string_view {i, e}; + } std::string t; t.reserve(static_cast(std::distance(i, e))); while (i != e) { @@ -252,7 +256,7 @@ namespace IceSpider { for (; pi != decltype(pi)(); ++pi) { auto eq = std::find(pi->begin(), pi->end(), '='); if (eq == pi->end()) { - h(urldecode(pi->begin(), pi->end()), std::string()); + h(urldecode(pi->begin(), pi->end()), {}); } else { h(urldecode(pi->begin(), eq), urldecode(eq + 1, pi->end())); diff --git a/icespider/core/xwwwFormUrlEncoded.h b/icespider/core/xwwwFormUrlEncoded.h index e0f8053..6c266b6 100644 --- a/icespider/core/xwwwFormUrlEncoded.h +++ b/icespider/core/xwwwFormUrlEncoded.h @@ -2,13 +2,14 @@ #define ICESPIDER_CGI_XWWWFORMURLENCODED_H #include +#include #include #include namespace IceSpider { class XWwwFormUrlEncoded : public Slicer::Deserializer { public: - using KVh = std::function; + using KVh = std::function; explicit XWwwFormUrlEncoded(std::istream & in); @@ -16,7 +17,7 @@ namespace IceSpider { DLL_PUBLIC static void iterateVars( const std::string_view & input, const KVh & h, const std::string_view & split); - DLL_PUBLIC static std::string urldecode(std::string_view::const_iterator s, std::string_view::const_iterator); + DLL_PUBLIC static MaybeString urldecode(std::string_view::const_iterator s, std::string_view::const_iterator); DLL_PUBLIC static std::string urlencode(std::string_view::const_iterator s, std::string_view::const_iterator); DLL_PUBLIC static void urlencodeto( std::ostream &, std::string_view::const_iterator s, std::string_view::const_iterator); diff --git a/icespider/fcgi/cgiRequestBase.h b/icespider/fcgi/cgiRequestBase.h index 774f06d..fdc82d7 100644 --- a/icespider/fcgi/cgiRequestBase.h +++ b/icespider/fcgi/cgiRequestBase.h @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace IceSpider { @@ -17,7 +18,7 @@ namespace IceSpider { public: using VarMap = flatmap; using HdrMap = flatmap; - using StrMap = flatmap; + using StrMap = flatmap; [[nodiscard]] const PathElements & getRequestPath() const override; [[nodiscard]] PathElements & getRequestPath() override; -- cgit v1.2.3