#pragma once #include #include "crow/http_request.h" #include "crow/http_response.h" namespace crow { // Any middleware requires following 3 members: // struct context; // storing data for the middleware; can be read from another middleware or handlers // before_handle // called before handling the request. // if res.end() is called, the operation is halted. // (still call after_handle of this middleware) // 2 signatures: // void before_handle(request& req, response& res, context& ctx) // if you only need to access this middlewares context. // template // void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx) // you can access another middlewares' context by calling `all_ctx.template get()' // ctx == all_ctx.template get() // after_handle // called after handling the request. // void after_handle(request& req, response& res, context& ctx) // template // void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx) struct CookieParser { struct context { std::unordered_map jar; std::unordered_map cookies_to_add; std::string get_cookie(const std::string& key) const { auto cookie = jar.find(key); if (cookie != jar.end()) return cookie->second; return {}; } void set_cookie(const std::string& key, const std::string& value) { cookies_to_add.emplace(key, value); } }; void before_handle(request& req, response& res, context& ctx) { int count = req.headers.count("Cookie"); if (!count) return; if (count > 1) { res.code = 400; res.end(); return; } std::string cookies = req.get_header_value("Cookie"); size_t pos = 0; while(pos < cookies.size()) { size_t pos_equal = cookies.find('=', pos); if (pos_equal == cookies.npos) break; std::string name = cookies.substr(pos, pos_equal-pos); boost::trim(name); pos = pos_equal+1; while(pos < cookies.size() && cookies[pos] == ' ') pos++; if (pos == cookies.size()) break; size_t pos_semicolon = cookies.find(';', pos); std::string value = cookies.substr(pos, pos_semicolon-pos); boost::trim(value); if (value[0] == '"' && value[value.size()-1] == '"') { value = value.substr(1, value.size()-2); } ctx.jar.emplace(std::move(name), std::move(value)); pos = pos_semicolon; if (pos == cookies.npos) break; pos++; while(pos < cookies.size() && cookies[pos] == ' ') pos++; } } void after_handle(request& /*req*/, response& res, context& ctx) { for(auto& cookie:ctx.cookies_to_add) { if (cookie.second.empty()) res.add_header("Set-Cookie", cookie.first + "=\"\""); else res.add_header("Set-Cookie", cookie.first + "=" + cookie.second); } } }; /* App app; A B C A::context int aa; ctx1 : public A::context ctx2 : public ctx1, public B::context ctx3 : public ctx2, public C::context C depends on A C::handle context.aaa App::context : private CookieParser::contetx, ... { jar } SimpleApp */ }