Tamer
C++ language extensions for event-driven programming
Loading...
Searching...
No Matches
http.hh
1#ifndef TAMER_HTTP_HH
2#define TAMER_HTTP_HH 1
3#include "fd.hh"
4#include "http_parser.h"
5#include <vector>
6#include <string>
7#include <sstream>
8#include <memory>
9#include <unordered_map>
10#include <ctime>
11namespace tamer {
12class http_parser;
13
14struct http_header {
15 std::string name;
16 std::string value;
17 inline http_header(std::string n, std::string v)
18 : name(std::move(n)), value(std::move(v)) {
19 }
20 inline bool is(const char* s, size_t len) const {
21 return name.length() == len && memcmp(name.data(), s, len) == 0;
22 }
23 inline bool is(const std::string& s) const {
24 return is(s.data(), s.length());
25 }
26 static inline bool equals_canonical(const char* s1, const char* s2, size_t len) {
27 const char* end2 = s2 + len;
28 for (; s2 != end2; ++s1, ++s2)
29 if (*s1 != *s2
30 && (*s1 < 'A' || *s1 > 'Z' || (*s1 - 'A' + 'a') != *s2))
31 return false;
32 return true;
33 }
34 static inline bool equals_canonical(const std::string& str, const char* s, size_t len) {
35 return str.length() == len && equals_canonical(str.data(), s, len);
36 }
37 inline bool is_canonical(const char* s, size_t len) const {
38 return equals_canonical(name, s, len);
39 }
40 inline bool is_canonical(const std::string& s) const {
41 return is_canonical(s.data(), s.length());
42 }
43 inline bool is_content_length() const {
44 return is_canonical("content-length", 14);
45 }
46};
47
48class http_message {
49 public:
50 typedef std::vector<http_header>::const_iterator header_iterator;
51
52 inline http_message();
53
54 inline bool ok() const;
55 inline bool operator!() const;
56 inline enum http_errno error() const;
57
58 inline unsigned http_major() const;
59 inline unsigned http_minor() const;
60
61 inline unsigned status_code() const;
62 inline const std::string& status_message() const;
63 inline enum http_method method() const;
64 inline const std::string& url() const;
65 inline bool has_canonical_header(const char* name, size_t length) const;
66 inline bool has_canonical_header(const char* name) const;
67 inline bool has_canonical_header(const std::string& name) const;
68 header_iterator find_canonical_header(const char* name, size_t length) const;
69 inline header_iterator find_canonical_header(const char* name) const;
70 inline header_iterator find_canonical_header(const std::string& name) const;
71 std::string canonical_header(const char* name, size_t length) const;
72 inline std::string canonical_header(const char* name) const;
73 inline std::string canonical_header(const std::string& name) const;
74 inline bool has_header(const std::string& name) const;
75 inline header_iterator find_header(const std::string& name) const;
76 inline std::string header(const std::string& name) const;
77 inline const std::string& body() const;
78
79 std::string host() const;
80 inline std::string url_schema() const;
81 inline std::string url_host() const;
82 std::string url_host_port() const;
83 uint16_t url_port() const;
84 inline std::string url_path() const;
85 inline bool has_query() const;
86 inline std::string query() const;
87 bool has_query(const std::string& name) const;
88 std::string query(const std::string& name) const;
89
90 inline header_iterator header_begin() const;
91 inline header_iterator header_end() const;
92 inline header_iterator query_begin() const;
93 inline header_iterator query_end() const;
94
95 inline http_message& clear();
96 void add_header(std::string key, std::string value);
97
98 inline http_message& http_major(unsigned v);
99 inline http_message& http_minor(unsigned v);
100 inline http_message& error(enum http_errno e);
101 inline http_message& status_code(unsigned code);
102 inline http_message& status_code(unsigned code, std::string message);
103 inline http_message& method(enum http_method method);
104 inline http_message& url(std::string url);
105 inline http_message& header(std::string key, std::string value);
106 inline http_message& header(std::string key, size_t value);
107 inline http_message& date_header(std::string key, time_t value);
108 inline http_message& body(std::string body);
109 inline http_message& append_body(const std::string& x);
110
111 static std::string canonicalize(std::string x);
112 static const char* default_status_message(unsigned code);
113
114 private:
115 enum {
116 info_url = 1, info_query = 2
117 };
118
119 struct info_type {
120 unsigned flags;
121 struct http_parser_url urlp;
122 std::vector<http_header> raw_query;
123 inline info_type()
124 : flags(0) {
125 }
126 };
127
128 unsigned short major_;
129 unsigned short minor_;
130 unsigned status_code_ : 16;
131 unsigned method_ : 8;
132 unsigned error_ : 7;
133 unsigned upgrade_ : 1;
134
135 std::string url_;
136 std::string status_message_;
137 std::vector<http_header> raw_headers_;
138 std::string body_;
139
140 mutable std::shared_ptr<info_type> info_;
141
142 inline void kill_info(unsigned f) const;
143 inline info_type& info(unsigned f) const;
144 void make_info(unsigned f) const;
145 inline bool has_url_field(int field) const;
146 inline std::string url_field(int field) const;
147 void do_clear();
148 friend class http_parser;
149};
150
151class http_parser : public tamed_class {
152 public:
153 http_parser(enum http_parser_type type);
154
155 void clear();
156 inline bool ok() const;
157 inline enum http_errno error() const;
158 inline bool should_keep_alive() const;
159
160 void receive(fd f, event<http_message> done);
161 void send(fd f, const http_message& m, event<> done);
162 static void send_request(fd f, const http_message& m, event<> done);
163 static void send_request(fd f, http_message&& m, event<> done);
164 static void send_response(fd f, const http_message& m, event<> done);
165 static void send_response(fd f, http_message&& m, event<> done);
166 static void send_response_headers(fd f, const http_message& m, event<> done);
167 static void send_response_chunk(fd f, std::string s, event<> done);
168 static void send_response_end(fd f, event<> done);
169
170 inline void clear_should_keep_alive();
171
172 private:
173 ::http_parser hp_;
174
175 struct message_data {
176 http_message hm;
177 std::string key;
178 std::ostringstream sbuf;
179 bool done;
180 };
181
182 static const http_parser_settings settings;
183 static http_parser* get_parser(::http_parser* hp);
184 static message_data* get_message_data(::http_parser* hp);
185 static int on_message_begin(::http_parser* hp);
186 static int on_url(::http_parser* hp, const char* s, size_t len);
187 static int on_status(::http_parser* hp, const char* s, size_t len);
188 static int on_header_field(::http_parser* hp, const char* s, size_t len);
189 static int on_header_value(::http_parser* hp, const char* s, size_t len);
190 static int on_headers_complete(::http_parser* hp);
191 static int on_body(::http_parser* hp, const char* s, size_t len);
192 static int on_message_complete(::http_parser* hp);
193 inline void copy_parser_status(message_data& md);
194 static void unparse_request_headers(std::ostringstream& buf,
195 const http_message& m);
196 static void unparse_response_headers(std::ostringstream& buf,
197 const http_message& m,
198 bool include_content_length);
199 static inline std::string prepare_headers(const http_message& m,
200 std::string& body,
201 bool is_response);
202 static inline void send_message(fd f, std::string headers,
203 std::string body, event<> done);
204 static void send_two(fd f, std::string a, std::string b, event<> done);
205
206 class closure__receive__2fdQ12http_message_; void receive(closure__receive__2fdQ12http_message_&);
207 class closure__send_response_chunk__2fdSsQ_; static void send_response_chunk(closure__send_response_chunk__2fdSsQ_&);
208 class closure__send_two__2fdSsSsQ_; static void send_two(closure__send_two__2fdSsSsQ_&);
209};
210
211inline http_message::http_message()
212 : major_(1), minor_(1), status_code_(200), method_(HTTP_GET),
213 error_(HPE_OK), upgrade_(0) {
214}
215
216inline void http_message::kill_info(unsigned f) const {
217 if (info_)
218 info_->flags &= ~f;
219}
220
221inline unsigned http_message::http_major() const {
222 return major_;
223}
224
225inline unsigned http_message::http_minor() const {
226 return minor_;
227}
228
229inline bool http_message::ok() const {
230 return error_ == HPE_OK;
231}
232
233inline bool http_message::operator!() const {
234 return !ok();
235}
236
237inline enum http_errno http_message::error() const {
238 return (enum http_errno) error_;
239}
240
241inline unsigned http_message::status_code() const {
242 return status_code_;
243}
244
245inline const std::string& http_message::status_message() const {
246 return status_message_;
247}
248
249inline enum http_method http_message::method() const {
250 return (enum http_method) method_;
251}
252
253inline const std::string& http_message::url() const {
254 return url_;
255}
256
257inline bool http_message::has_canonical_header(const char* name, size_t length) const {
258 return find_canonical_header(name, length) != header_end();
259}
260
261inline bool http_message::has_canonical_header(const char* name) const {
262 return find_canonical_header(name) != header_end();
263}
264
265inline bool http_message::has_canonical_header(const std::string& name) const {
266 return find_canonical_header(name) != header_end();
267}
268
269inline http_message::header_iterator http_message::find_canonical_header(const char* name) const {
270 return find_canonical_header(name, strlen(name));
271}
272
273inline http_message::header_iterator http_message::find_canonical_header(const std::string& name) const {
274 return find_canonical_header(name.data(), name.length());
275}
276
277inline std::string http_message::canonical_header(const char* name) const {
278 return canonical_header(name, strlen(name));
279}
280
281inline std::string http_message::canonical_header(const std::string& name) const {
282 return canonical_header(name.data(), name.length());
283}
284
285inline bool http_message::has_header(const std::string& name) const {
286 return has_canonical_header(canonicalize(name));
287}
288
289inline http_message::header_iterator http_message::find_header(const std::string& name) const {
290 return find_canonical_header(canonicalize(name));
291}
292
293inline std::string http_message::header(const std::string& name) const {
294 return canonical_header(canonicalize(name));
295}
296
297inline const std::string& http_message::body() const {
298 return body_;
299}
300
301inline bool http_message::has_url_field(int field) const {
302 return info(info_url).urlp.field_set & (1 << field);
303}
304
305inline std::string http_message::url_field(int field) const {
306 const info_type& i = info(info_url);
307 if (i.urlp.field_set & (1 << field))
308 return url_.substr(i.urlp.field_data[field].off,
309 i.urlp.field_data[field].len);
310 else
311 return std::string();
312}
313
314inline bool http_message::has_query() const {
315 return has_url_field(UF_QUERY);
316}
317
318inline std::string http_message::query() const {
319 return url_field(UF_QUERY);
320}
321
322inline std::string http_message::url_schema() const {
323 return url_field(UF_SCHEMA);
324}
325
326inline std::string http_message::url_host() const {
327 return url_field(UF_HOST);
328}
329
330inline std::string http_message::url_path() const {
331 return url_field(UF_PATH);
332}
333
334inline http_message& http_message::http_major(unsigned v) {
335 major_ = v;
336 return *this;
337}
338
339inline http_message& http_message::http_minor(unsigned v) {
340 minor_ = v;
341 return *this;
342}
343
344inline http_message& http_message::clear() {
345 do_clear();
346 return *this;
347}
348
349inline http_message& http_message::error(enum http_errno e) {
350 error_ = e;
351 return *this;
352}
353
354inline http_message& http_message::status_code(unsigned code) {
355 status_code_ = code;
356 status_message_ = std::string();
357 return *this;
358}
359
360inline http_message& http_message::status_code(unsigned code, std::string message) {
361 status_code_ = code;
362 status_message_ = std::move(message);
363 return *this;
364}
365
366inline http_message& http_message::method(enum http_method method) {
367 method_ = (unsigned) method;
368 return *this;
369}
370
371inline http_message& http_message::url(std::string url) {
372 url_ = std::move(url);
373 kill_info(info_url | info_query);
374 return *this;
375}
376
377inline http_message& http_message::header(std::string key, std::string value) {
378 add_header(std::move(key), std::move(value));
379 return *this;
380}
381
382inline http_message& http_message::header(std::string key, size_t value) {
383 std::ostringstream buf;
384 buf << value;
385 add_header(std::move(key), buf.str());
386 return *this;
387}
388
389inline http_message& http_message::date_header(std::string key, time_t value) {
390 char buf[128];
391 // XXX current locale
392 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&value));
393 add_header(std::move(key), std::string(buf));
394 return *this;
395}
396
397inline http_message& http_message::body(std::string body) {
398 body_ = std::move(body);
399 return *this;
400}
401
402inline http_message& http_message::append_body(const std::string& x) {
403 body_ += x;
404 return *this;
405}
406
407inline http_message::info_type& http_message::info(unsigned f) const {
408 if (!info_ || !info_.unique() || (info_->flags & f) != f)
409 make_info(f);
410 return *info_.get();
411}
412
413inline http_message::header_iterator http_message::header_begin() const {
414 return raw_headers_.begin();
415}
416
417inline http_message::header_iterator http_message::header_end() const {
418 return raw_headers_.end();
419}
420
421inline http_message::header_iterator http_message::query_begin() const {
422 return info(info_query).raw_query.begin();
423}
424
425inline http_message::header_iterator http_message::query_end() const {
426 return info(info_query).raw_query.end();
427}
428
429inline bool http_parser::ok() const {
430 return hp_.http_errno == (unsigned) HPE_OK;
431}
432
433inline enum http_errno http_parser::error() const {
434 return (enum http_errno) hp_.http_errno;
435}
436
437inline bool http_parser::should_keep_alive() const {
438 return http_should_keep_alive(&hp_);
439}
440
441inline void http_parser::clear_should_keep_alive() {
442 hp_.flags = (hp_.flags & ~F_CONNECTION_KEEP_ALIVE) | F_CONNECTION_CLOSE;
443}
444
445inline void http_parser::send_message(fd f, std::string headers,
446 std::string body, event<> done) {
447 if (body.empty())
448 f.write(headers, done);
449 else
450 send_two(f, headers, body, done);
451}
452
453} // namespace tamer
454#endif
Definition rendezvous.hh:463
Event-based file descriptor wrapper class.
Namespace containing public Tamer classes and functions for the Tamer core.
Definition adapter.hh:17