Crow  0.3
A C++ microframework for the web
cookie_parser.h
1 #pragma once
2 #include <boost/algorithm/string/trim.hpp>
3 #include "crow/http_request.h"
4 #include "crow/http_response.h"
5 
6 namespace crow
7 {
8  // Any middleware requires following 3 members:
9 
10  // struct context;
11  // storing data for the middleware; can be read from another middleware or handlers
12 
13  // before_handle
14  // called before handling the request.
15  // if res.end() is called, the operation is halted.
16  // (still call after_handle of this middleware)
17  // 2 signatures:
18  // void before_handle(request& req, response& res, context& ctx)
19  // if you only need to access this middlewares context.
20  // template <typename AllContext>
21  // void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
22  // you can access another middlewares' context by calling `all_ctx.template get<MW>()'
23  // ctx == all_ctx.template get<CurrentMiddleware>()
24 
25  // after_handle
26  // called after handling the request.
27  // void after_handle(request& req, response& res, context& ctx)
28  // template <typename AllContext>
29  // void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
30 
31  struct CookieParser
32  {
33  struct context
34  {
35  std::unordered_map<std::string, std::string> jar;
36  std::unordered_map<std::string, std::string> cookies_to_add;
37 
38  std::string get_cookie(const std::string& key) const
39  {
40  auto cookie = jar.find(key);
41  if (cookie != jar.end())
42  return cookie->second;
43  return {};
44  }
45 
46  void set_cookie(const std::string& key, const std::string& value)
47  {
48  cookies_to_add.emplace(key, value);
49  }
50  };
51 
52  void before_handle(request& req, response& res, context& ctx)
53  {
54  int count = req.headers.count("Cookie");
55  if (!count)
56  return;
57  if (count > 1)
58  {
59  res.code = 400;
60  res.end();
61  return;
62  }
63  std::string cookies = req.get_header_value("Cookie");
64  size_t pos = 0;
65  while(pos < cookies.size())
66  {
67  size_t pos_equal = cookies.find('=', pos);
68  if (pos_equal == cookies.npos)
69  break;
70  std::string name = cookies.substr(pos, pos_equal-pos);
71  boost::trim(name);
72  pos = pos_equal+1;
73  while(pos < cookies.size() && cookies[pos] == ' ') pos++;
74  if (pos == cookies.size())
75  break;
76 
77  size_t pos_semicolon = cookies.find(';', pos);
78  std::string value = cookies.substr(pos, pos_semicolon-pos);
79 
80  boost::trim(value);
81  if (value[0] == '"' && value[value.size()-1] == '"')
82  {
83  value = value.substr(1, value.size()-2);
84  }
85 
86  ctx.jar.emplace(std::move(name), std::move(value));
87 
88  pos = pos_semicolon;
89  if (pos == cookies.npos)
90  break;
91  pos++;
92  while(pos < cookies.size() && cookies[pos] == ' ') pos++;
93  }
94  }
95 
96  void after_handle(request& /*req*/, response& res, context& ctx)
97  {
98  for(auto& cookie:ctx.cookies_to_add)
99  {
100  if (cookie.second.empty())
101  res.add_header("Set-Cookie", cookie.first + "=\"\"");
102  else
103  res.add_header("Set-Cookie", cookie.first + "=" + cookie.second);
104  }
105  }
106  };
107 
108  /*
109  App<CookieParser, AnotherJarMW> app;
110  A B C
111  A::context
112  int aa;
113 
114  ctx1 : public A::context
115  ctx2 : public ctx1, public B::context
116  ctx3 : public ctx2, public C::context
117 
118  C depends on A
119 
120  C::handle
121  context.aaa
122 
123  App::context : private CookieParser::contetx, ...
124  {
125  jar
126 
127  }
128 
129  SimpleApp
130  */
131 }
crow::request
An HTTP request.
Definition: http_request.h:26
crow::response::code
int code
The Status code for the response.
Definition: http_response.h:28
crow::response
HTTP response.
Definition: http_response.h:23
crow::response::end
void end()
Set the response completion flag and call the handler (to send the response).
Definition: http_response.h:151