Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: chrome/browser/chromeos/gdata/test_servers/http_request.cc

Issue 11088073: HTTP server for testing Google Drive. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Added the forgotten file. Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/gdata/test_servers/http_request.h"
6
7 #include <algorithm>
8 #include <map>
9 #include <string>
10 #include "base/basictypes.h"
11 #include "base/logging.h"
12 #include "googleurl/src/gurl.h"
13
14 namespace gdata {
15 namespace test_servers {
16
17 namespace {
18 int kRequestSizeLimit = 64 * 1024 * 1024; // 64 mb.
19 } // namespace
20
21 HttpRequestParser::HttpRequestParser() : request_builder_(new HttpRequest()),
22 state_(REQUEST_LINE),
23 buffer_position_(0),
24 crlf_position_(-1),
25 crlf_checked_position_(0),
26 current_content_length_(0) {
27 }
28
29 HttpRequestParser::~HttpRequestParser() {
30 }
31
32 void HttpRequestParser::ProcessChunk(const char *data, int length) {
33 buffer_.append(data, length);
34 if (static_cast<int>(buffer_.length()) + length > kRequestSizeLimit) {
35 // Too big request. Treat it as a syntax error.
36 LOG(ERROR) << "The HTTP request is too large.";
37 state_ = SYNTAX_ERROR;
38 return;
39 }
40 if (crlf_position_ == -1 && state_ != DATA)
41 FindNextCrLf();
42 }
43
44 HttpRequestParser::STATE HttpRequestParser::ParseRequest() {
45 while (state_ != READY &&
46 state_ != SYNTAX_ERROR &&
47 ShouldParseBuffer()) {
48 std::string token;
49 switch (state_) {
50 case REQUEST_LINE:
51 // Parse a method, eg. GET.
52 token = ShiftToken(IDENTIFIER);
53 if (token.empty()) {
54 state_ = SYNTAX_ERROR;
55 break;
56 }
57 std::transform(token.begin(), token.end(), token.begin(), ::toupper);
58 if (token == "OPTIONS") {
59 request_builder_->method = OPTIONS;
60 } else if (token == "GET") {
61 request_builder_->method = GET;
62 } else if (token == "HEAD") {
63 request_builder_->method = HEAD;
64 } else if (token == "POST") {
65 request_builder_->method = POST;
66 } else if (token == "PUT") {
67 request_builder_->method = PUT;
68 } else if (token == "DELETE") {
69 request_builder_->method = DELETE;
70 } else if (token == "TRACE") {
71 request_builder_->method = TRACE;
72 } else if (token == "CONNECT") {
73 request_builder_->method = CONNECT;
74 } else {
75 request_builder_->method = CUSTOM;
76 }
77
78 // Parse an URL, eg. index.cgi.
79 token = ShiftToken(IDENTIFIER);
80 if (token.empty()) {
81 LOG(ERROR) << "The url token must not be empty.";
82 state_ = SYNTAX_ERROR;
83 break;
84 }
85 request_builder_->raw_url = token;
86
87 // Parse a protocol, eg. HTTP/1.1.
88 // Currently we support only HTTP/1.1, since HTTP/1.0 is quite obsolete.
89 token = ShiftToken(LINE);
90 std::transform(token.begin(), token.end(), token.begin(), ::tolower);
91 if (token.empty() || token != "http/1.1") {
92 LOG(ERROR) << "This protocol is not supported: [" << token << "]";
93 state_ = SYNTAX_ERROR;
94 break;
95 }
96 request_builder_->protocol = token;
97 state_ = HEADER_LINE;
98 break;
99 case HEADER_LINE:
100 // If we have an empty line, then finish parsing headers and validate
101 // the request.
102 if (ShiftCrLf()) {
103 // TODO(mtomasz): Check if these are really case-insensitive in the
104 // rfc.
105 if (request_builder_->headers.find("host") ==
106 request_builder_->headers.end()) {
107 LOG(ERROR) << "Host header is required for HTTP/1.1";
108 state_ = SYNTAX_ERROR;
109 break;
110 } else {
111 // TODO(mtomasz): We add http:// protocol, but how about https://?
112 // Do we want to support it?
113 GURL host = GURL("http://" + request_builder_->headers["host"]);
114 request_builder_->url = host.Resolve(request_builder_->raw_url);
115 }
116 if (request_builder_->headers.find("content-length") !=
117 request_builder_->headers.end()) {
118 current_content_length_ =
119 atoi(request_builder_->headers["content-length"].c_str());
120 }
121 if (current_content_length_ > 0) {
122 state_ = DATA;
123 } else {
124 state_ = READY;
125 }
126 break;
127 }
128 {
129 // Parse a header name, eg. Content-length.
130 std::string header_name = ShiftToken(HEADER_KEY);
131 std::transform(header_name.begin(),
132 header_name.end(),
133 header_name.begin(),
134 ::tolower);
135 if (header_name.empty()) {
136 LOG(ERROR) << "Header key must not be empty.";
137 state_ = SYNTAX_ERROR;
138 break;
139 }
140
141 // Parse a header value, eg. 100 (for Content-Length).
142 token = ShiftToken(LINE);
143 request_builder_->headers[header_name] = token;
144 break;
145 }
146 case DATA:
147 if (current_content_length_ ==
148 static_cast<int>(request_builder_->content.length())) {
149 // Entire data received.
150 state_ = READY;
151 } else {
152 int to_read = current_content_length_ -
153 request_builder_->content.length();
154 if (to_read > static_cast<int>(request_builder_->content.length()) -
155 buffer_position_) {
156 to_read = request_builder_->content.length() - buffer_position_;
157 }
158 request_builder_->content.append(ShiftData(to_read), to_read);
159 }
160 break;
161 case SYNTAX_ERROR:
162 break;
163 default:
164 state_ = SYNTAX_ERROR;
165 break;
166 }
167 }
168 return state_;
169 }
170
171 scoped_ptr<HttpRequest> HttpRequestParser::GetRequest() {
172 DCHECK(state_ == READY);
173 scoped_ptr<HttpRequest> result = request_builder_.Pass();
174 request_builder_.reset(new HttpRequest());
175
176 // Reset the parser state.
177 state_ = REQUEST_LINE;
178 buffer_position_ = 0;
179 buffer_.clear();
180 crlf_position_ = -1;
181 crlf_checked_position_ = 0;
182 current_content_length_ = 0;
183
184 return result.Pass();
185 }
186
187 std::string HttpRequestParser::ShiftToken(SHIFT_TOKEN_TYPE token_type) {
188 SkipSpaces(); // Ignore any spaces from the beginning.
189 size_t found_position;
190 int token_start_position = buffer_position_;
191
192 switch (token_type) {
193 case IDENTIFIER:
194 found_position = buffer_.find(' ', buffer_position_);
195 if (found_position != std::string::npos) {
196 buffer_position_ = static_cast<int>(found_position) + 1;
197 return buffer_.substr(token_start_position,
198 found_position - token_start_position);
199 }
200 break;
201 case HEADER_KEY:
202 found_position = buffer_.find(':', buffer_position_);
203 if (found_position != std::string::npos) {
204 buffer_position_ = static_cast<int>(found_position) + 1;
205 return buffer_.substr(token_start_position,
206 found_position - token_start_position);
207 }
208 break;
209 case LINE:
210 DCHECK(crlf_position_ != -1) << "CRLF not found, but expected.";
211 buffer_position_ = crlf_position_ + 2;
212 int token_length = crlf_position_ - token_start_position;
213 FindNextCrLf();
214 return buffer_.substr(token_start_position, token_length);
215 break;
216 }
217
218 return "";
219 }
220
221 bool HttpRequestParser::ShiftCrLf() {
222 if (buffer_position_ == crlf_position_) {
223 buffer_position_ += 2;
224 FindNextCrLf();
225 return true;
226 }
227
228 return false;
229 }
230
231 const char* HttpRequestParser::ShiftData(int length) {
232 DCHECK(length <= static_cast<int>(request_builder_->content.length()) -
233 buffer_position_) << "Tried to read more than available.";
234 const char *result = buffer_.data() + buffer_position_;
235 buffer_position_ += length;
236
237 return result;
238 }
239
240 void HttpRequestParser::SkipSpaces() {
241 const char *buffer_data = buffer_.data();
242 int buffer_left = static_cast<int>(buffer_.length()) - buffer_position_;
243
244 // Ignore any spaces from the beginning.
245 while (buffer_left && buffer_data[buffer_position_] == ' ') {
246 buffer_position_++;
247 buffer_left--;
248 }
249 }
250
251 bool HttpRequestParser::ShouldParseBuffer() {
252 return buffer_position_ < static_cast<int>(buffer_.length()) &&
253 (crlf_position_ != -1 || state_ == DATA);
254 }
255
256 bool HttpRequestParser::FindNextCrLf() {
257 if (!buffer_.length()) {
258 return false;
259 }
260
261 size_t found_position = buffer_.find("\r\n", crlf_checked_position_);
262 if (found_position == std::string::npos) {
263 crlf_position_ = -1;
264 crlf_checked_position_ = buffer_.length() - 1;
265 return false;
266 }
267
268 crlf_position_ = static_cast<int>(found_position);
269 crlf_checked_position_ = crlf_position_ + 2;
270 return true;
271 }
272
273 } // namespace test_servers
274 } // namespace gdata
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698