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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/gdata/test_servers/http_request.cc
diff --git a/chrome/browser/chromeos/gdata/test_servers/http_request.cc b/chrome/browser/chromeos/gdata/test_servers/http_request.cc
new file mode 100644
index 0000000000000000000000000000000000000000..62f2c857a608f88e335ab82948de1f5af05ad5ae
--- /dev/null
+++ b/chrome/browser/chromeos/gdata/test_servers/http_request.cc
@@ -0,0 +1,274 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/gdata/test_servers/http_request.h"
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "googleurl/src/gurl.h"
+
+namespace gdata {
+namespace test_servers {
+
+namespace {
+int kRequestSizeLimit = 64 * 1024 * 1024; // 64 mb.
+} // namespace
+
+HttpRequestParser::HttpRequestParser() : request_builder_(new HttpRequest()),
+ state_(REQUEST_LINE),
+ buffer_position_(0),
+ crlf_position_(-1),
+ crlf_checked_position_(0),
+ current_content_length_(0) {
+}
+
+HttpRequestParser::~HttpRequestParser() {
+}
+
+void HttpRequestParser::ProcessChunk(const char *data, int length) {
+ buffer_.append(data, length);
+ if (static_cast<int>(buffer_.length()) + length > kRequestSizeLimit) {
+ // Too big request. Treat it as a syntax error.
+ LOG(ERROR) << "The HTTP request is too large.";
+ state_ = SYNTAX_ERROR;
+ return;
+ }
+ if (crlf_position_ == -1 && state_ != DATA)
+ FindNextCrLf();
+}
+
+HttpRequestParser::STATE HttpRequestParser::ParseRequest() {
+ while (state_ != READY &&
+ state_ != SYNTAX_ERROR &&
+ ShouldParseBuffer()) {
+ std::string token;
+ switch (state_) {
+ case REQUEST_LINE:
+ // Parse a method, eg. GET.
+ token = ShiftToken(IDENTIFIER);
+ if (token.empty()) {
+ state_ = SYNTAX_ERROR;
+ break;
+ }
+ std::transform(token.begin(), token.end(), token.begin(), ::toupper);
+ if (token == "OPTIONS") {
+ request_builder_->method = OPTIONS;
+ } else if (token == "GET") {
+ request_builder_->method = GET;
+ } else if (token == "HEAD") {
+ request_builder_->method = HEAD;
+ } else if (token == "POST") {
+ request_builder_->method = POST;
+ } else if (token == "PUT") {
+ request_builder_->method = PUT;
+ } else if (token == "DELETE") {
+ request_builder_->method = DELETE;
+ } else if (token == "TRACE") {
+ request_builder_->method = TRACE;
+ } else if (token == "CONNECT") {
+ request_builder_->method = CONNECT;
+ } else {
+ request_builder_->method = CUSTOM;
+ }
+
+ // Parse an URL, eg. index.cgi.
+ token = ShiftToken(IDENTIFIER);
+ if (token.empty()) {
+ LOG(ERROR) << "The url token must not be empty.";
+ state_ = SYNTAX_ERROR;
+ break;
+ }
+ request_builder_->raw_url = token;
+
+ // Parse a protocol, eg. HTTP/1.1.
+ // Currently we support only HTTP/1.1, since HTTP/1.0 is quite obsolete.
+ token = ShiftToken(LINE);
+ std::transform(token.begin(), token.end(), token.begin(), ::tolower);
+ if (token.empty() || token != "http/1.1") {
+ LOG(ERROR) << "This protocol is not supported: [" << token << "]";
+ state_ = SYNTAX_ERROR;
+ break;
+ }
+ request_builder_->protocol = token;
+ state_ = HEADER_LINE;
+ break;
+ case HEADER_LINE:
+ // If we have an empty line, then finish parsing headers and validate
+ // the request.
+ if (ShiftCrLf()) {
+ // TODO(mtomasz): Check if these are really case-insensitive in the
+ // rfc.
+ if (request_builder_->headers.find("host") ==
+ request_builder_->headers.end()) {
+ LOG(ERROR) << "Host header is required for HTTP/1.1";
+ state_ = SYNTAX_ERROR;
+ break;
+ } else {
+ // TODO(mtomasz): We add http:// protocol, but how about https://?
+ // Do we want to support it?
+ GURL host = GURL("http://" + request_builder_->headers["host"]);
+ request_builder_->url = host.Resolve(request_builder_->raw_url);
+ }
+ if (request_builder_->headers.find("content-length") !=
+ request_builder_->headers.end()) {
+ current_content_length_ =
+ atoi(request_builder_->headers["content-length"].c_str());
+ }
+ if (current_content_length_ > 0) {
+ state_ = DATA;
+ } else {
+ state_ = READY;
+ }
+ break;
+ }
+ {
+ // Parse a header name, eg. Content-length.
+ std::string header_name = ShiftToken(HEADER_KEY);
+ std::transform(header_name.begin(),
+ header_name.end(),
+ header_name.begin(),
+ ::tolower);
+ if (header_name.empty()) {
+ LOG(ERROR) << "Header key must not be empty.";
+ state_ = SYNTAX_ERROR;
+ break;
+ }
+
+ // Parse a header value, eg. 100 (for Content-Length).
+ token = ShiftToken(LINE);
+ request_builder_->headers[header_name] = token;
+ break;
+ }
+ case DATA:
+ if (current_content_length_ ==
+ static_cast<int>(request_builder_->content.length())) {
+ // Entire data received.
+ state_ = READY;
+ } else {
+ int to_read = current_content_length_ -
+ request_builder_->content.length();
+ if (to_read > static_cast<int>(request_builder_->content.length()) -
+ buffer_position_) {
+ to_read = request_builder_->content.length() - buffer_position_;
+ }
+ request_builder_->content.append(ShiftData(to_read), to_read);
+ }
+ break;
+ case SYNTAX_ERROR:
+ break;
+ default:
+ state_ = SYNTAX_ERROR;
+ break;
+ }
+ }
+ return state_;
+}
+
+scoped_ptr<HttpRequest> HttpRequestParser::GetRequest() {
+ DCHECK(state_ == READY);
+ scoped_ptr<HttpRequest> result = request_builder_.Pass();
+ request_builder_.reset(new HttpRequest());
+
+ // Reset the parser state.
+ state_ = REQUEST_LINE;
+ buffer_position_ = 0;
+ buffer_.clear();
+ crlf_position_ = -1;
+ crlf_checked_position_ = 0;
+ current_content_length_ = 0;
+
+ return result.Pass();
+}
+
+std::string HttpRequestParser::ShiftToken(SHIFT_TOKEN_TYPE token_type) {
+ SkipSpaces(); // Ignore any spaces from the beginning.
+ size_t found_position;
+ int token_start_position = buffer_position_;
+
+ switch (token_type) {
+ case IDENTIFIER:
+ found_position = buffer_.find(' ', buffer_position_);
+ if (found_position != std::string::npos) {
+ buffer_position_ = static_cast<int>(found_position) + 1;
+ return buffer_.substr(token_start_position,
+ found_position - token_start_position);
+ }
+ break;
+ case HEADER_KEY:
+ found_position = buffer_.find(':', buffer_position_);
+ if (found_position != std::string::npos) {
+ buffer_position_ = static_cast<int>(found_position) + 1;
+ return buffer_.substr(token_start_position,
+ found_position - token_start_position);
+ }
+ break;
+ case LINE:
+ DCHECK(crlf_position_ != -1) << "CRLF not found, but expected.";
+ buffer_position_ = crlf_position_ + 2;
+ int token_length = crlf_position_ - token_start_position;
+ FindNextCrLf();
+ return buffer_.substr(token_start_position, token_length);
+ break;
+ }
+
+ return "";
+}
+
+bool HttpRequestParser::ShiftCrLf() {
+ if (buffer_position_ == crlf_position_) {
+ buffer_position_ += 2;
+ FindNextCrLf();
+ return true;
+ }
+
+ return false;
+}
+
+const char* HttpRequestParser::ShiftData(int length) {
+ DCHECK(length <= static_cast<int>(request_builder_->content.length()) -
+ buffer_position_) << "Tried to read more than available.";
+ const char *result = buffer_.data() + buffer_position_;
+ buffer_position_ += length;
+
+ return result;
+}
+
+void HttpRequestParser::SkipSpaces() {
+ const char *buffer_data = buffer_.data();
+ int buffer_left = static_cast<int>(buffer_.length()) - buffer_position_;
+
+ // Ignore any spaces from the beginning.
+ while (buffer_left && buffer_data[buffer_position_] == ' ') {
+ buffer_position_++;
+ buffer_left--;
+ }
+}
+
+bool HttpRequestParser::ShouldParseBuffer() {
+ return buffer_position_ < static_cast<int>(buffer_.length()) &&
+ (crlf_position_ != -1 || state_ == DATA);
+}
+
+bool HttpRequestParser::FindNextCrLf() {
+ if (!buffer_.length()) {
+ return false;
+ }
+
+ size_t found_position = buffer_.find("\r\n", crlf_checked_position_);
+ if (found_position == std::string::npos) {
+ crlf_position_ = -1;
+ crlf_checked_position_ = buffer_.length() - 1;
+ return false;
+ }
+
+ crlf_position_ = static_cast<int>(found_position);
+ crlf_checked_position_ = crlf_position_ + 2;
+ return true;
+}
+
+} // namespace test_servers
+} // namespace gdata

Powered by Google App Engine
This is Rietveld 408576698