]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/asio/example/cpp03/http/server4/request_parser.cpp
5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 #include "request_parser.hpp"
14 #include <boost/lexical_cast.hpp>
15 #include "request.hpp"
20 // Enable the pseudo-keywords reenter, yield and fork.
21 #include <boost/asio/yield.hpp>
23 std::string
request_parser::content_length_name_
= "Content-Length";
25 boost::tribool
request_parser::consume(request
& req
, char c
)
31 req
.http_version_major
= 0;
32 req
.http_version_minor
= 0;
38 while (is_char(c
) && !is_ctl(c
) && !is_tspecial(c
) && c
!= ' ')
40 req
.method
.push_back(c
);
41 yield
return boost::indeterminate
;
43 if (req
.method
.empty())
47 if (c
!= ' ') return false;
48 yield
return boost::indeterminate
;
51 while (!is_ctl(c
) && c
!= ' ')
54 yield
return boost::indeterminate
;
56 if (req
.uri
.empty()) return false;
59 if (c
!= ' ') return false;
60 yield
return boost::indeterminate
;
62 // HTTP protocol identifier.
63 if (c
!= 'H') return false;
64 yield
return boost::indeterminate
;
65 if (c
!= 'T') return false;
66 yield
return boost::indeterminate
;
67 if (c
!= 'T') return false;
68 yield
return boost::indeterminate
;
69 if (c
!= 'P') return false;
70 yield
return boost::indeterminate
;
73 if (c
!= '/') return false;
74 yield
return boost::indeterminate
;
76 // Major version number.
77 if (!is_digit(c
)) return false;
80 req
.http_version_major
= req
.http_version_major
* 10 + c
- '0';
81 yield
return boost::indeterminate
;
85 if (c
!= '.') return false;
86 yield
return boost::indeterminate
;
88 // Minor version number.
89 if (!is_digit(c
)) return false;
92 req
.http_version_minor
= req
.http_version_minor
* 10 + c
- '0';
93 yield
return boost::indeterminate
;
97 if (c
!= '\r') return false;
98 yield
return boost::indeterminate
;
99 if (c
!= '\n') return false;
100 yield
return boost::indeterminate
;
103 while ((is_char(c
) && !is_ctl(c
) && !is_tspecial(c
) && c
!= '\r')
104 || (c
== ' ' || c
== '\t'))
106 if (c
== ' ' || c
== '\t')
108 // Leading whitespace. Must be continuation of previous header's value.
109 if (req
.headers
.empty()) return false;
110 while (c
== ' ' || c
== '\t')
111 yield
return boost::indeterminate
;
115 // Start the next header.
116 req
.headers
.push_back(header());
119 while (is_char(c
) && !is_ctl(c
) && !is_tspecial(c
) && c
!= ':')
121 req
.headers
.back().name
.push_back(c
);
122 yield
return boost::indeterminate
;
125 // Colon and space separates the header name from the header value.
126 if (c
!= ':') return false;
127 yield
return boost::indeterminate
;
128 if (c
!= ' ') return false;
129 yield
return boost::indeterminate
;
133 while (is_char(c
) && !is_ctl(c
) && c
!= '\r')
135 req
.headers
.back().value
.push_back(c
);
136 yield
return boost::indeterminate
;
140 if (c
!= '\r') return false;
141 yield
return boost::indeterminate
;
142 if (c
!= '\n') return false;
143 yield
return boost::indeterminate
;
147 if (c
!= '\r') return false;
148 yield
return boost::indeterminate
;
149 if (c
!= '\n') return false;
151 // Check for optional Content-Length header.
152 for (std::size_t i
= 0; i
< req
.headers
.size(); ++i
)
154 if (headers_equal(req
.headers
[i
].name
, content_length_name_
))
159 boost::lexical_cast
<std::size_t>(req
.headers
[i
].value
);
161 catch (boost::bad_lexical_cast
&)
169 while (req
.content
.size() < content_length_
)
171 yield
return boost::indeterminate
;
172 req
.content
.push_back(c
);
179 // Disable the pseudo-keywords reenter, yield and fork.
180 #include <boost/asio/unyield.hpp>
182 bool request_parser::is_char(int c
)
184 return c
>= 0 && c
<= 127;
187 bool request_parser::is_ctl(int c
)
189 return (c
>= 0 && c
<= 31) || (c
== 127);
192 bool request_parser::is_tspecial(int c
)
196 case '(': case ')': case '<': case '>': case '@':
197 case ',': case ';': case ':': case '\\': case '"':
198 case '/': case '[': case ']': case '?': case '=':
199 case '{': case '}': case ' ': case '\t':
206 bool request_parser::is_digit(int c
)
208 return c
>= '0' && c
<= '9';
211 bool request_parser::tolower_compare(char a
, char b
)
213 return std::tolower(a
) == std::tolower(b
);
216 bool request_parser::headers_equal(const std::string
& a
, const std::string
& b
)
218 if (a
.length() != b
.length())
221 return std::equal(a
.begin(), a
.end(), b
.begin(),
222 &request_parser::tolower_compare
);
225 } // namespace server4