]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* |
2 | * This file is open source software, licensed to you under the terms | |
3 | * of the Apache License, Version 2.0 (the "License"). See the NOTICE file | |
4 | * distributed with this work for additional information regarding copyright | |
5 | * ownership. You may not use this file except in compliance with the License. | |
6 | * | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, | |
12 | * software distributed under the License is distributed on an | |
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
14 | * KIND, either express or implied. See the License for the | |
15 | * specific language governing permissions and limitations | |
16 | * under the License. | |
17 | */ | |
18 | /* | |
19 | * Copyright (C) 2015 Cloudius Systems, Ltd. | |
20 | */ | |
21 | ||
22 | #include <seastar/core/ragel.hh> | |
23 | #include <memory> | |
24 | #include <unordered_map> | |
25 | ||
26 | namespace seastar { | |
27 | ||
28 | struct http_response { | |
29 | sstring _version; | |
30 | std::unordered_map<sstring, sstring> _headers; | |
20effc67 | 31 | int _status_code; |
11fdf7f2 TL |
32 | }; |
33 | ||
34 | %% machine http_response; | |
35 | ||
36 | %%{ | |
37 | ||
38 | access _fsm_; | |
39 | ||
40 | action mark { | |
41 | g.mark_start(p); | |
42 | } | |
43 | ||
44 | action store_version { | |
45 | _rsp->_version = str(); | |
46 | } | |
47 | ||
48 | action store_field_name { | |
49 | _field_name = str(); | |
50 | } | |
51 | ||
52 | action store_value { | |
53 | _value = str(); | |
54 | } | |
55 | ||
56 | action assign_field { | |
57 | _rsp->_headers[_field_name] = std::move(_value); | |
58 | } | |
59 | ||
60 | action extend_field { | |
61 | _rsp->_headers[_field_name] += sstring(" ") + std::move(_value); | |
62 | } | |
63 | ||
20effc67 TL |
64 | action store_status { |
65 | _rsp->_status_code = std::atoi(str().c_str()); | |
66 | } | |
67 | ||
11fdf7f2 TL |
68 | action done { |
69 | done = true; | |
70 | fbreak; | |
71 | } | |
72 | ||
73 | cr = '\r'; | |
74 | lf = '\n'; | |
75 | crlf = '\r\n'; | |
76 | tchar = alpha | digit | '-' | '!' | '#' | '$' | '%' | '&' | '\'' | '*' | |
77 | | '+' | '.' | '^' | '_' | '`' | '|' | '~'; | |
78 | ||
79 | sp = ' '; | |
80 | ht = '\t'; | |
81 | ||
82 | sp_ht = sp | ht; | |
83 | ||
84 | http_version = 'HTTP/' (digit '.' digit) >mark %store_version; | |
85 | ||
86 | field = tchar+ >mark %store_field_name; | |
87 | value = any* >mark %store_value; | |
20effc67 TL |
88 | status_code = (digit digit digit) >mark %store_status; |
89 | start_line = http_version space status_code space (any - cr - lf)* crlf; | |
11fdf7f2 TL |
90 | header_1st = (field sp_ht* ':' value :> crlf) %assign_field; |
91 | header_cont = (sp_ht+ value sp_ht* crlf) %extend_field; | |
92 | header = header_1st header_cont*; | |
93 | main := start_line header* :> (crlf @done); | |
94 | ||
95 | }%% | |
96 | ||
97 | class http_response_parser : public ragel_parser_base<http_response_parser> { | |
98 | %% write data nofinal noprefix; | |
99 | public: | |
100 | enum class state { | |
101 | error, | |
102 | eof, | |
103 | done, | |
104 | }; | |
105 | std::unique_ptr<http_response> _rsp; | |
106 | sstring _field_name; | |
107 | sstring _value; | |
108 | state _state; | |
109 | public: | |
110 | void init() { | |
111 | init_base(); | |
112 | _rsp.reset(new http_response()); | |
113 | _state = state::eof; | |
114 | %% write init; | |
115 | } | |
116 | char* parse(char* p, char* pe, char* eof) { | |
117 | sstring_builder::guard g(_builder, p, pe); | |
118 | auto str = [this, &g, &p] { g.mark_end(p); return get_str(); }; | |
119 | bool done = false; | |
120 | if (p != pe) { | |
121 | _state = state::error; | |
122 | } | |
9f95a23c TL |
123 | #ifdef __clang__ |
124 | #pragma clang diagnostic push | |
125 | #pragma clang diagnostic ignored "-Wmisleading-indentation" | |
126 | #endif | |
11fdf7f2 | 127 | %% write exec; |
9f95a23c TL |
128 | #ifdef __clang__ |
129 | #pragma clang diagnostic pop | |
130 | #endif | |
11fdf7f2 TL |
131 | if (!done) { |
132 | p = nullptr; | |
133 | } else { | |
134 | _state = state::done; | |
135 | } | |
136 | return p; | |
137 | } | |
138 | auto get_parsed_response() { | |
139 | return std::move(_rsp); | |
140 | } | |
141 | bool eof() const { | |
142 | return _state == state::eof; | |
143 | } | |
144 | }; | |
145 | ||
146 | } |