blob: e8dee119658a780694c504894bc5ca90a3442ca1 [file] [log] [blame]
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2016, Regents of the University of California.
4 *
5 * This file is part of ChronoShare, a decentralized file sharing application over NDN.
6 *
7 * ChronoShare is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
10 *
11 * ChronoShare is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License along with
16 * ChronoShare, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ChronoShare authors and contributors.
19 */
Zhenkai Zhua9a7e1d2013-02-25 18:29:07 -080020//
21// request_parser.cpp
22// ~~~~~~~~~~~~~~~~~~
23//
24// Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com)
25//
26// Distributed under the Boost Software License, Version 1.0. (See accompanying
27// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
28//
29
30#include "request_parser.hpp"
31#include "request.hpp"
32
33namespace http {
34namespace server {
35
36request_parser::request_parser()
37 : state_(method_start)
38{
39}
40
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080041void
42request_parser::reset()
Zhenkai Zhua9a7e1d2013-02-25 18:29:07 -080043{
44 state_ = method_start;
45}
46
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080047boost::tribool
48request_parser::consume(request& req, char input)
Zhenkai Zhua9a7e1d2013-02-25 18:29:07 -080049{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080050 switch (state_) {
51 case method_start:
52 if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
53 return false;
54 }
55 else {
56 state_ = method;
57 req.method.push_back(input);
58 return boost::indeterminate;
59 }
60 case method:
61 if (input == ' ') {
62 state_ = uri;
63 return boost::indeterminate;
64 }
65 else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
66 return false;
67 }
68 else {
69 req.method.push_back(input);
70 return boost::indeterminate;
71 }
72 case uri:
73 if (input == ' ') {
74 state_ = http_version_h;
75 return boost::indeterminate;
76 }
77 else if (is_ctl(input)) {
78 return false;
79 }
80 else {
81 req.uri.push_back(input);
82 return boost::indeterminate;
83 }
84 case http_version_h:
85 if (input == 'H') {
86 state_ = http_version_t_1;
87 return boost::indeterminate;
88 }
89 else {
90 return false;
91 }
92 case http_version_t_1:
93 if (input == 'T') {
94 state_ = http_version_t_2;
95 return boost::indeterminate;
96 }
97 else {
98 return false;
99 }
100 case http_version_t_2:
101 if (input == 'T') {
102 state_ = http_version_p;
103 return boost::indeterminate;
104 }
105 else {
106 return false;
107 }
108 case http_version_p:
109 if (input == 'P') {
110 state_ = http_version_slash;
111 return boost::indeterminate;
112 }
113 else {
114 return false;
115 }
116 case http_version_slash:
117 if (input == '/') {
118 req.http_version_major = 0;
119 req.http_version_minor = 0;
120 state_ = http_version_major_start;
121 return boost::indeterminate;
122 }
123 else {
124 return false;
125 }
126 case http_version_major_start:
127 if (is_digit(input)) {
128 req.http_version_major = req.http_version_major * 10 + input - '0';
129 state_ = http_version_major;
130 return boost::indeterminate;
131 }
132 else {
133 return false;
134 }
135 case http_version_major:
136 if (input == '.') {
137 state_ = http_version_minor_start;
138 return boost::indeterminate;
139 }
140 else if (is_digit(input)) {
141 req.http_version_major = req.http_version_major * 10 + input - '0';
142 return boost::indeterminate;
143 }
144 else {
145 return false;
146 }
147 case http_version_minor_start:
148 if (is_digit(input)) {
149 req.http_version_minor = req.http_version_minor * 10 + input - '0';
150 state_ = http_version_minor;
151 return boost::indeterminate;
152 }
153 else {
154 return false;
155 }
156 case http_version_minor:
157 if (input == '\r') {
158 state_ = expecting_newline_1;
159 return boost::indeterminate;
160 }
161 else if (is_digit(input)) {
162 req.http_version_minor = req.http_version_minor * 10 + input - '0';
163 return boost::indeterminate;
164 }
165 else {
166 return false;
167 }
168 case expecting_newline_1:
169 if (input == '\n') {
170 state_ = header_line_start;
171 return boost::indeterminate;
172 }
173 else {
174 return false;
175 }
176 case header_line_start:
177 if (input == '\r') {
178 state_ = expecting_newline_3;
179 return boost::indeterminate;
180 }
181 else if (!req.headers.empty() && (input == ' ' || input == '\t')) {
182 state_ = header_lws;
183 return boost::indeterminate;
184 }
185 else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
186 return false;
187 }
188 else {
189 req.headers.push_back(header());
190 req.headers.back().name.push_back(input);
191 state_ = header_name;
192 return boost::indeterminate;
193 }
194 case header_lws:
195 if (input == '\r') {
196 state_ = expecting_newline_2;
197 return boost::indeterminate;
198 }
199 else if (input == ' ' || input == '\t') {
200 return boost::indeterminate;
201 }
202 else if (is_ctl(input)) {
203 return false;
204 }
205 else {
206 state_ = header_value;
207 req.headers.back().value.push_back(input);
208 return boost::indeterminate;
209 }
210 case header_name:
211 if (input == ':') {
212 state_ = space_before_header_value;
213 return boost::indeterminate;
214 }
215 else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
216 return false;
217 }
218 else {
219 req.headers.back().name.push_back(input);
220 return boost::indeterminate;
221 }
222 case space_before_header_value:
223 if (input == ' ') {
224 state_ = header_value;
225 return boost::indeterminate;
226 }
227 else {
228 return false;
229 }
230 case header_value:
231 if (input == '\r') {
232 state_ = expecting_newline_2;
233 return boost::indeterminate;
234 }
235 else if (is_ctl(input)) {
236 return false;
237 }
238 else {
239 req.headers.back().value.push_back(input);
240 return boost::indeterminate;
241 }
242 case expecting_newline_2:
243 if (input == '\n') {
244 state_ = header_line_start;
245 return boost::indeterminate;
246 }
247 else {
248 return false;
249 }
250 case expecting_newline_3:
251 return (input == '\n');
252 default:
Zhenkai Zhua9a7e1d2013-02-25 18:29:07 -0800253 return false;
Zhenkai Zhua9a7e1d2013-02-25 18:29:07 -0800254 }
255}
256
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800257bool
258request_parser::is_char(int c)
Zhenkai Zhua9a7e1d2013-02-25 18:29:07 -0800259{
260 return c >= 0 && c <= 127;
261}
262
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800263bool
264request_parser::is_ctl(int c)
Zhenkai Zhua9a7e1d2013-02-25 18:29:07 -0800265{
266 return (c >= 0 && c <= 31) || (c == 127);
267}
268
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800269bool
270request_parser::is_tspecial(int c)
Zhenkai Zhua9a7e1d2013-02-25 18:29:07 -0800271{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800272 switch (c) {
273 case '(':
274 case ')':
275 case '<':
276 case '>':
277 case '@':
278 case ',':
279 case ';':
280 case ':':
281 case '\\':
282 case '"':
283 case '/':
284 case '[':
285 case ']':
286 case '?':
287 case '=':
288 case '{':
289 case '}':
290 case ' ':
291 case '\t':
292 return true;
293 default:
294 return false;
Zhenkai Zhua9a7e1d2013-02-25 18:29:07 -0800295 }
296}
297
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800298bool
299request_parser::is_digit(int c)
Zhenkai Zhua9a7e1d2013-02-25 18:29:07 -0800300{
301 return c >= '0' && c <= '9';
302}
303
304} // namespace server
305} // namespace http