Line data Source code
1 : #include <sstream>
2 : #include "request_factory.hpp"
3 : #include "../common/http_request.hpp"
4 : #include "../util/url.hpp"
5 : #include "../../util/logger.hpp"
6 :
7 : namespace thinger::http {
8 :
9 858 : request_factory::request_factory() : state_(method_start) {
10 858 : }
11 :
12 103750 : boost::tribool request_factory::consume(char input) {
13 103750 : switch (state_) {
14 918 : case method_start:
15 918 : if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
16 0 : return false;
17 : }
18 : else {
19 918 : state_ = method;
20 918 : tempString1_.push_back(input);
21 918 : return boost::indeterminate;
22 : }
23 3444 : case method:
24 3444 : if (input == ' ') {
25 : // initialize a new http request if necessary
26 914 : if(!req) req = std::make_shared<http_request>();
27 : // store read method
28 914 : on_http_method(tempString1_);
29 914 : tempString1_.clear();
30 914 : state_ = uri;
31 914 : return boost::indeterminate;
32 : }
33 2530 : else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
34 0 : return false;
35 : }
36 : else {
37 2530 : tempString1_.push_back(input);
38 2530 : return boost::indeterminate;
39 : }
40 8501 : case uri:
41 8501 : if (input == ' ') {
42 : // decode get uri
43 914 : std::string parsed_uri;
44 914 : bool parsed_ok = util::url::url_decode(tempString1_, parsed_uri);
45 914 : if (parsed_ok) {
46 : // http_request path must be absolute and not contain "..".
47 914 : if (parsed_uri.empty() || parsed_uri[0] != '/' || parsed_uri.find("..") != std::string::npos) {
48 0 : return false;
49 : }
50 914 : on_http_uri(tempString1_);
51 914 : tempString1_.clear();
52 : // next step reading http version
53 914 : state_ = http_version_h;
54 914 : return boost::indeterminate;
55 : } else {
56 0 : tempString1_.clear();
57 0 : return false;
58 : }
59 914 : }
60 7587 : else if (is_ctl(input)) {
61 0 : return false;
62 : }
63 : else {
64 7587 : tempString1_.push_back(input);
65 7587 : return boost::indeterminate;
66 : }
67 914 : case http_version_h:
68 914 : if (input == 'H') {
69 914 : state_ = http_version_t_1;
70 914 : return boost::indeterminate;
71 : }
72 0 : return false;
73 914 : case http_version_t_1:
74 914 : if (input == 'T') {
75 914 : state_ = http_version_t_2;
76 914 : return boost::indeterminate;
77 : }
78 0 : return false;
79 914 : case http_version_t_2:
80 914 : if (input == 'T') {
81 914 : state_ = http_version_p;
82 914 : return boost::indeterminate;
83 : }
84 0 : return false;
85 914 : case http_version_p:
86 914 : if (input == 'P') {
87 914 : state_ = http_version_slash;
88 914 : return boost::indeterminate;
89 : }
90 0 : return false;
91 914 : case http_version_slash:
92 914 : if (input == '/') {
93 914 : state_ = http_version_major_start;
94 914 : return boost::indeterminate;
95 : }
96 0 : return false;
97 914 : case http_version_major_start:
98 914 : if (is_digit(input)) {
99 914 : tempInt_ = input - '0';
100 914 : state_ = http_version_major;
101 914 : return boost::indeterminate;
102 : }
103 0 : return false;
104 914 : case http_version_major:
105 914 : if (input == '.') {
106 914 : on_http_major_version(tempInt_);
107 914 : state_ = http_version_minor_start;
108 914 : return boost::indeterminate;
109 : }
110 0 : else if (is_digit(input)) {
111 0 : tempInt_ = tempInt_ * 10 + input - '0';
112 0 : return boost::indeterminate;
113 : }
114 0 : return false;
115 914 : case http_version_minor_start:
116 914 : if (is_digit(input)) {
117 914 : tempInt_ = input - '0';
118 914 : state_ = http_version_minor;
119 914 : return boost::indeterminate;
120 : }
121 0 : return false;
122 914 : case http_version_minor:
123 914 : if (is_digit(input)) {
124 0 : tempInt_ = tempInt_ * 10 + input - '0';
125 0 : return boost::indeterminate;
126 : }
127 914 : else if (input == '\r') {
128 914 : on_http_minor_version(tempInt_);
129 914 : tempInt_ = -1; // reserve temp int for storing content-lenght value
130 914 : state_ = expecting_newline_1;
131 914 : return boost::indeterminate;
132 : }
133 0 : return false;
134 914 : case expecting_newline_1:
135 914 : if (input == '\n') {
136 914 : state_ = header_line_start;
137 914 : return boost::indeterminate;
138 : }
139 0 : return false;
140 3863 : case header_line_start:
141 3863 : if (input == '\r') {
142 914 : state_ = expecting_newline_3;
143 914 : return boost::indeterminate;
144 : }
145 2949 : else if (!empty_headers() && (input == ' ' || input == '\t')) {
146 0 : state_ = header_lws;
147 0 : return boost::indeterminate;
148 : }
149 2949 : else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
150 0 : return false;
151 : }
152 : else {
153 2949 : tempString1_.clear();
154 2949 : tempString1_.push_back(input);
155 2949 : state_ = header_name;
156 2949 : return boost::indeterminate;
157 : }
158 0 : case header_lws:
159 0 : if (input == '\r') {
160 0 : state_ = expecting_newline_2;
161 0 : return boost::indeterminate;
162 : }
163 0 : else if (input == ' ' || input == '\t') {
164 0 : return boost::indeterminate;
165 : }
166 0 : else if (is_ctl(input)) {
167 0 : return false;
168 : }
169 : else {
170 0 : state_ = header_value;
171 0 : tempString1_.push_back(input);
172 0 : return boost::indeterminate;
173 : }
174 29591 : case header_name:
175 29591 : if (input == ':') {
176 2949 : state_ = space_before_header_value;
177 2949 : return boost::indeterminate;
178 : }
179 26642 : else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
180 0 : return false;
181 : }
182 : else {
183 26642 : tempString1_.push_back(input);
184 26642 : return boost::indeterminate;
185 : }
186 2949 : case space_before_header_value:
187 2949 : if (input == ' ') {
188 2949 : tempString2_.clear();
189 2949 : state_ = header_value;
190 2949 : return boost::indeterminate;
191 : }
192 0 : return false;
193 41481 : case header_value:
194 41481 : if (input == '\r') {
195 2949 : on_http_header(tempString1_, tempString2_);
196 2949 : state_ = expecting_newline_2;
197 2949 : return boost::indeterminate;
198 : }
199 38532 : else if (is_ctl(input)) {
200 0 : return false;
201 : }
202 : else {
203 38532 : tempString2_.push_back(input);
204 38532 : return boost::indeterminate;
205 : }
206 2949 : case expecting_newline_2:
207 2949 : if (input == '\n') {
208 2949 : state_ = header_line_start;
209 2949 : return boost::indeterminate;
210 : }
211 0 : return false;
212 914 : case expecting_newline_3:
213 914 : if (input == '\n'){
214 914 : if(headers_only_ || get_content_length() == 0){
215 914 : return true;
216 : }
217 0 : state_ = content;
218 0 : return boost::indeterminate;
219 : }
220 0 : return false;
221 0 : case content:
222 0 : on_content(input);
223 0 : if(get_content_read()<get_content_length()){
224 0 : return boost::indeterminate;
225 : }
226 0 : return true;
227 0 : default:
228 0 : return false;
229 : }
230 : }
231 :
232 33039 : bool request_factory::is_char(int c) {
233 33039 : return c >= 0 && c <= 127;
234 : }
235 :
236 79158 : bool request_factory::is_ctl(int c) {
237 79158 : return (c >= 0 && c <= 31) || (c == 127);
238 : }
239 :
240 33039 : bool request_factory::is_tspecial(int c) {
241 33039 : switch (c) {
242 0 : case '(':
243 : case ')':
244 : case '<':
245 : case '>':
246 : case '@':
247 : case ',':
248 : case ';':
249 : case ':':
250 : case '\\':
251 : case '"':
252 : case '/':
253 : case '[':
254 : case ']':
255 : case '?':
256 : case '=':
257 : case '{':
258 : case '}':
259 : case ' ':
260 : case '\t':
261 0 : return true;
262 33039 : default:
263 33039 : return false;
264 : }
265 : }
266 :
267 2742 : bool request_factory::is_digit(int c) {
268 2742 : return c >= '0' && c <= '9';
269 : }
270 :
271 912 : std::shared_ptr<http_request> request_factory::consume_request() {
272 912 : std::shared_ptr<http_request> request(req);
273 912 : req.reset();
274 912 : state_ = method_start;
275 912 : tempString1_.clear();
276 912 : tempString2_.clear();
277 912 : return request;
278 : }
279 :
280 914 : void request_factory::on_http_method(const std::string& method){
281 914 : req->set_method(method);
282 914 : }
283 :
284 0 : void request_factory::on_http_status_code(unsigned short status_code){
285 :
286 0 : }
287 :
288 914 : void request_factory::on_http_uri(const std::string& uri){
289 914 : req->set_uri(uri);
290 914 : }
291 :
292 914 : void request_factory::on_http_major_version(uint8_t major)
293 : {
294 914 : req->set_http_version_major(major);
295 914 : }
296 :
297 914 : void request_factory::on_http_minor_version(uint16_t minor){
298 914 : req->set_http_version_minor(minor);
299 914 : }
300 :
301 2949 : void request_factory::on_http_header(const std::string& name, const std::string& value){
302 2949 : req->process_header(name, value);
303 2949 : }
304 :
305 0 : void request_factory::on_content(char content){
306 0 : req->get_body().push_back(content);
307 0 : }
308 :
309 4 : size_t request_factory::get_content_length(){
310 4 : return req->get_content_length();
311 : }
312 :
313 0 : size_t request_factory::get_content_read(){
314 0 : return req->get_body().size();
315 : }
316 :
317 2949 : bool request_factory::empty_headers(){
318 2949 : return req->empty_headers();
319 : }
320 : }
|