Electroneum
middleware.h
Go to the documentation of this file.
1 #pragma once
2 #include <boost/algorithm/string/trim.hpp>
3 #include "http_request.h"
4 #include "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)
39  {
40  if (jar.count(key))
41  return jar[key];
42  return {};
43  }
44 
45  void set_cookie(const std::string& key, const std::string& value)
46  {
47  cookies_to_add.emplace(key, value);
48  }
49  };
50 
51  void before_handle(request& req, response& res, context& ctx)
52  {
53  int count = req.headers.count("Cookie");
54  if (!count)
55  return;
56  if (count > 1)
57  {
58  res.code = 400;
59  res.end();
60  return;
61  }
62  std::string cookies = req.get_header_value("Cookie");
63  size_t pos = 0;
64  while(pos < cookies.size())
65  {
66  size_t pos_equal = cookies.find('=', pos);
67  if (pos_equal == cookies.npos)
68  break;
69  std::string name = cookies.substr(pos, pos_equal-pos);
71  pos = pos_equal+1;
72  while(pos < cookies.size() && cookies[pos] == ' ') pos++;
73  if (pos == cookies.size())
74  break;
75 
76  std::string value;
77 
78  if (cookies[pos] == '"')
79  {
80  int dquote_meet_count = 0;
81  pos ++;
82  size_t pos_dquote = pos-1;
83  do
84  {
85  pos_dquote = cookies.find('"', pos_dquote+1);
86  dquote_meet_count ++;
87  } while(pos_dquote < cookies.size() && cookies[pos_dquote-1] == '\\');
88  if (pos_dquote == cookies.npos)
89  break;
90 
91  if (dquote_meet_count == 1)
92  value = cookies.substr(pos, pos_dquote - pos);
93  else
94  {
95  value.clear();
96  value.reserve(pos_dquote-pos);
97  for(size_t p = pos; p < pos_dquote; p++)
98  {
99  // FIXME minimal escaping
100  if (cookies[p] == '\\' && p + 1 < pos_dquote)
101  {
102  p++;
103  if (cookies[p] == '\\' || cookies[p] == '"')
104  value += cookies[p];
105  else
106  {
107  value += '\\';
108  value += cookies[p];
109  }
110  }
111  else
112  value += cookies[p];
113  }
114  }
115 
116  ctx.jar.emplace(std::move(name), std::move(value));
117  pos = cookies.find(";", pos_dquote+1);
118  if (pos == cookies.npos)
119  break;
120  pos++;
121  while(pos < cookies.size() && cookies[pos] == ' ') pos++;
122  if (pos == cookies.size())
123  break;
124  }
125  else
126  {
127  size_t pos_semicolon = cookies.find(';', pos);
128  value = cookies.substr(pos, pos_semicolon - pos);
129  boost::trim(value);
130  ctx.jar.emplace(std::move(name), std::move(value));
131  pos = pos_semicolon;
132  if (pos == cookies.npos)
133  break;
134  pos ++;
135  while(pos < cookies.size() && cookies[pos] == ' ') pos++;
136  if (pos == cookies.size())
137  break;
138  }
139  }
140  }
141 
142  void after_handle(request& /*req*/, response& res, context& ctx)
143  {
144  for(auto& cookie:ctx.cookies_to_add)
145  {
146  res.add_header("Set-Cookie", cookie.first + "=" + cookie.second);
147  }
148  }
149  };
150 
151  /*
152  App<CookieParser, AnotherJarMW> app;
153  A B C
154  A::context
155  int aa;
156 
157  ctx1 : public A::context
158  ctx2 : public ctx1, public B::context
159  ctx3 : public ctx2, public C::context
160 
161  C depends on A
162 
163  C::handle
164  context.aaa
165 
166  App::context : private CookieParser::contetx, ...
167  {
168  jar
169 
170  }
171 
172  SimpleApp
173  */
174 }
Definition: http_response.h:12
Definition: http_request.h:23
void set_cookie(const std::string &key, const std::string &value)
Definition: middleware.h:45
std::string trim(const std::string &str, const std::string &trimChars)
Definition: minicsv.h:88
std::string get_cookie(const std::string &key)
Definition: middleware.h:38
ci_map headers
Definition: http_request.h:29
const std::string & get_header_value(const std::string &key) const
Definition: http_request.h:50
int code
Definition: http_response.h:17
void before_handle(request &req, response &res, context &ctx)
Definition: middleware.h:51
std::unordered_map< std::string, std::string > jar
Definition: middleware.h:35
Definition: middleware.h:33
void after_handle(request &, response &res, context &ctx)
Definition: middleware.h:142
std::unordered_map< std::string, std::string > cookies_to_add
Definition: middleware.h:36
Definition: ci_map.h:7
const char * name
Definition: simplewallet.cpp:180
void end()
Definition: http_response.h:93
void add_header(std::string key, std::string value)
Definition: http_response.h:29
Definition: middleware.h:31