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

Side by Side Diff: chrome/browser/chromeos/drive/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: Addressed comments and simplified. Added tests. Created 8 years, 1 month 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/drive/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 "base/string_util.h"
13 #include "googleurl/src/gurl.h"
14
15
16 namespace drive {
17 namespace test_servers {
18
19 namespace {
20 size_t kRequestSizeLimit = 64 * 1024 * 1024; // 64 mb.
21 } // namespace
22
23 HttpRequestParser::HttpRequestParser() : http_request_(new HttpRequest()),
24 state_(STATE_HEADERS),
25 buffer_position_(0),
26 current_content_length_(0) {
27 }
28
29 HttpRequestParser::~HttpRequestParser() {
30 }
31
32 void HttpRequestParser::ProcessChunk(const char *data, size_t length) {
33 buffer_.append(data, length);
34 DCHECK(buffer_.length() + length <= kRequestSizeLimit) <<
35 "The HTTP request is too large.";
36 }
37
38 std::string HttpRequestParser::ShiftLine() {
39 size_t eoln_position = buffer_.find("\r\n", buffer_position_);
40 if (eoln_position == std::string::npos)
41 return "";
42 const int line_length = eoln_position - buffer_position_;
43 std::string result = buffer_.substr(buffer_position_, line_length);
44 buffer_position_ += line_length + 2;
45 return result;
46 }
47
48 HttpRequestParser::ParseResult HttpRequestParser::ParseRequest() {
49 DCHECK(state_ != STATE_ACCEPTED);
50 // Parse the request from beginning. However, entire request may not be
51 // available in the buffer.
52 if (state_ == STATE_HEADERS) {
53 if (ParseHeaders() == ACCEPTED)
54 return ACCEPTED;
55 }
56 if (state_ == STATE_CONTENT) {
57 if (ParseContent() == ACCEPTED)
58 return ACCEPTED;
59 }
60 return WAITING;
61 }
62
63 HttpRequestParser::ParseResult HttpRequestParser::ParseHeaders() {
64 // Check if the whole request input is available.
65 if (buffer_.find("\r\n\r\n", buffer_position_) == std::string::npos)
66 return WAITING;
67
68 // Parse request's the first header line.
69 // Request main main header, eg. GET /foobar.html HTTP/1.1
70 {
71 const std::string header_line = ShiftLine();
72 std::vector<std::string> header_line_tokens;
73 Tokenize(header_line, " ", &header_line_tokens);
74 DCHECK(header_line_tokens.size() == 3);
75 // Method.
76 http_request_->method = GetMethodType(StringToLowerASCII(
77 header_line_tokens[0]));
78 // Address.
79 const GURL host = GURL("http://localhost/");
80 http_request_->uri = host.Resolve(header_line_tokens[1]);
81 // Protocol.
82 const std::string protocol = StringToLowerASCII(header_line_tokens[2]);
83 CHECK(protocol == "http/1.0" || protocol == "http/1.1") <<
84 "Protocol not supported: " << protocol;
85 }
86
87 // Parse further headers.
88 {
89 std::string header_line = ShiftLine();
90 std::string header_name;
91 while (header_line != "") {
92 if (header_line[0] == ' ') {
93 // Continuation of the previous multi-line header.
94 http_request_->headers[header_name] += "\n" +
95 header_line.substr(1, header_line.length() - 1);
96 } else {
97 // New header.
98 size_t delimiter_pos = header_line.find(":");
99 DCHECK(delimiter_pos != std::string::npos) << "Syntax error.";
100 header_name = header_line.substr(0, delimiter_pos);
101 size_t header_value_pos = delimiter_pos + 1;
102 // Skip spaces (if any) after the colon.
103 while (header_value_pos < header_line.length() &&
104 header_line[header_value_pos] == ' ') {
105 header_value_pos++;
106 }
107 http_request_->headers[header_name] =
108 header_line.substr(header_value_pos,
109 header_line.length() - header_value_pos);
110 }
111 header_line = ShiftLine();
112 }
113 }
114
115 // Headers done. Is any content data attached to the request?
116 if (http_request_->headers.find("Content-Length") !=
117 http_request_->headers.end()) {
118 current_content_length_ =
119 atoi(http_request_->headers["Content-Length"].c_str());
120 if (!current_content_length_)
121 return ACCEPTED;
122 }
123
124 // The request has not yet been parsed, content data is still to be parsed.
125 state_ = STATE_CONTENT;
126 return WAITING;
127 }
128
129 HttpRequestParser::ParseResult HttpRequestParser::ParseContent() {
130 const size_t available_bytes = buffer_.length() - buffer_position_;
131 const size_t fetch_bytes = std::min(available_bytes,
132 current_content_length_);
133 http_request_->content.append(buffer_.data() + buffer_position_,
134 fetch_bytes);
135 buffer_position_ += fetch_bytes;
136
137 if (current_content_length_ == http_request_->content.length()) {
138 state_ = STATE_ACCEPTED;
139 return ACCEPTED;
140 }
141
142 return WAITING;
143 }
144
145 scoped_ptr<HttpRequest> HttpRequestParser::GetRequest() {
146 DCHECK(state_ == STATE_ACCEPTED);
147 scoped_ptr<HttpRequest> result = http_request_.Pass();
148
149 // Prepare for parsing a new request.
150 state_ = STATE_HEADERS;
151 http_request_.reset(new HttpRequest());
152 buffer_ = buffer_.substr(buffer_position_,
153 buffer_.length() - buffer_position_);
154 buffer_position_ = 0;
155 current_content_length_ = 0;
156
157 return result.Pass();
158 }
159
160 HttpMethod HttpRequestParser::GetMethodType(const std::string& token) const {
161 if (token == "get") {
162 return GET;
163 } else if (token == "head") {
164 return HEAD;
165 } else if (token == "post") {
166 return POST;
167 } else if (token == "put") {
168 return PUT;
169 } else if (token == "delete") {
170 return DELETE;
171 }
172 NOTREACHED() << "Method not implemented: " << token;
173 return UNKNOWN;
174 }
175
176 } // namespace test_servers
177 } // namespace drive
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698