#ifndef ICESPIDER_IHTTPREQUEST_H #define ICESPIDER_IHTTPREQUEST_H #include "exceptions.h" #include #include #include #include #include #include #include #include namespace IceSpider { class Core; class IRouteHandler; struct Accept { std::optional group, type; float q {1.0F}; }; using Accepted = std::vector; using PathElements = std::vector; using OptionalString = std::optional; using ContentTypeSerializer = std::pair; class DLL_PUBLIC IHttpRequest { public: explicit IHttpRequest(const Core *); virtual ~IHttpRequest() = default; [[nodiscard]] Ice::Context getContext() const; [[nodiscard]] virtual const PathElements & getRequestPath() const = 0; [[nodiscard]] virtual PathElements & getRequestPath() = 0; [[nodiscard]] virtual HttpMethod getRequestMethod() const = 0; [[nodiscard]] OptionalString getURLParam(const unsigned int &) const; [[nodiscard]] virtual OptionalString getQueryStringParam(const std::string_view &) const = 0; [[nodiscard]] virtual OptionalString getHeaderParam(const std::string_view &) const = 0; [[nodiscard]] virtual OptionalString getCookieParam(const std::string_view &) const = 0; [[nodiscard]] virtual OptionalString getEnv(const std::string_view &) const = 0; [[nodiscard]] virtual bool isSecure() const = 0; [[nodiscard]] static Accepted parseAccept(std::string_view); [[nodiscard]] virtual Slicer::DeserializerPtr getDeserializer() const; [[nodiscard]] virtual ContentTypeSerializer getSerializer(const IRouteHandler *) const; [[nodiscard]] virtual std::istream & getInputStream() const = 0; [[nodiscard]] virtual std::ostream & getOutputStream() const = 0; virtual void setHeader(const std::string_view &, const std::string_view &) const = 0; virtual std::ostream & dump(std::ostream & s) const = 0; template [[nodiscard]] inline std::optional getFrom(const K & key, OptionalString (IHttpRequest::*src)(const K &) const) const { if (auto v = (this->*src)(key)) { if constexpr (std::is_convertible::value) { return *v; } else if constexpr (std::is_constructible::value) { return T(*v); } else if constexpr (std::is_same::value) { return std::to_string(*v); } else { try { return boost::lexical_cast(*v); } catch (const boost::bad_lexical_cast & e) { throw Http400_BadRequest(); } } } else { return std::nullopt; } } template [[nodiscard]] T getURLParam(unsigned int n) const { return *getFrom(n, &IHttpRequest::getURLParam); } template [[nodiscard]] std::optional getBody() const { return Slicer::DeserializeAnyWith(getDeserializer()); } template [[nodiscard]] std::optional getBodyParam(const std::optional & map, const std::string_view & key) const { if (!map) { return {}; } auto i = map->find(key); if (i == map->end()) { return {}; } else { return boost::lexical_cast(i->second); } } void responseRedirect(const std::string_view & url, const OptionalString & = {}) const; void setCookie(const std::string_view &, const std::string_view &, const OptionalString & = {}, const OptionalString & = {}, bool = false, std::optional = {}); template void setCookie(const std::string_view & n, const T & v, const OptionalString & d, const OptionalString & p, bool s, std::optional e) { if constexpr (std::is_constructible::value) { setCookie(n, std::string_view(v), d, p, s, e); } else { auto vs = boost::lexical_cast(v); setCookie(n, std::string_view(vs), d, p, s, e); } } template [[nodiscard]] std::optional getQueryStringParam(const std::string_view & key) const { return getFrom(key, &IHttpRequest::getQueryStringParam); } template [[nodiscard]] std::optional getHeaderParam(const std::string_view & key) const { return getFrom(key, &IHttpRequest::getHeaderParam); } template [[nodiscard]] std::optional getCookieParam(const std::string_view & key) const { return getFrom(key, &IHttpRequest::getCookieParam); } virtual void response(short, const std::string_view &) const = 0; template void response(const IRouteHandler * route, const T & t) const { modelPartResponse(route, Slicer::ModelPart::CreateRootFor(t)); } void modelPartResponse(const IRouteHandler * route, const Slicer::ModelPartForRootPtr &) const; const Core * core; }; } #endif