diff options
-rw-r--r-- | chrome/chrome_tests.gypi | 2 | ||||
-rw-r--r-- | chrome/test/webdriver/http_response.cc | 67 | ||||
-rw-r--r-- | chrome/test/webdriver/http_response.h | 22 | ||||
-rw-r--r-- | chrome/test/webdriver/http_response_unittest.cc | 28 | ||||
-rw-r--r-- | chrome/test/webdriver/webdriver_dispatch.cc | 75 | ||||
-rw-r--r-- | chrome/test/webdriver/webdriver_dispatch_unittest.cc | 9 | ||||
-rw-r--r-- | chrome/test/webdriver/webdriver_server.cc | 3 | ||||
-rw-r--r-- | chrome/test/webdriver/webdriver_switches.cc | 13 | ||||
-rw-r--r-- | chrome/test/webdriver/webdriver_switches.h | 14 |
9 files changed, 126 insertions, 107 deletions
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 9a6d4f3..00523b0 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -806,6 +806,8 @@ 'test/webdriver/webdriver_session.h', 'test/webdriver/webdriver_session_manager.cc', 'test/webdriver/webdriver_session_manager.h', + 'test/webdriver/webdriver_switches.cc', + 'test/webdriver/webdriver_switches.h', 'test/webdriver/webdriver_util.cc', 'test/webdriver/webdriver_util.h', 'test/webdriver/webdriver_util_mac.mm', diff --git a/chrome/test/webdriver/http_response.cc b/chrome/test/webdriver/http_response.cc index 6bbe4a9..d07a6b3 100644 --- a/chrome/test/webdriver/http_response.cc +++ b/chrome/test/webdriver/http_response.cc @@ -15,14 +15,26 @@ const int HttpResponse::kNoContent = 204; const int HttpResponse::kSeeOther = 303; const int HttpResponse::kNotModified = 304; const int HttpResponse::kBadRequest = 400; +const int HttpResponse::kForbidden = 403; const int HttpResponse::kNotFound = 404; const int HttpResponse::kMethodNotAllowed = 405; const int HttpResponse::kInternalServerError = 500; +const int HttpResponse::kNotImplemented = 501; + +namespace { + +const char* kContentLengthHeader = "content-length"; + +} // namespace HttpResponse::HttpResponse() : status_(kOk) { } +HttpResponse::HttpResponse(int status) + : status_(status) { +} + HttpResponse::~HttpResponse() { } @@ -69,26 +81,10 @@ void HttpResponse::ClearHeaders() { headers_.clear(); } -void HttpResponse::UpdateHeader(const std::string& name, - const std::string& new_value) { - RemoveHeader(name); - AddHeader(name, new_value); -} - void HttpResponse::SetMimeType(const std::string& mime_type) { UpdateHeader("Content-Type", mime_type); } -void HttpResponse::SetBody(const std::string& data) { - SetBody(data.data(), data.length()); -} - -void HttpResponse::SetBody(const char* const data, size_t length) { - data_ = std::string(data, length); - UpdateHeader("Content-Length", - base::StringPrintf("%"PRIuS"", data_.length())); -} - std::string HttpResponse::GetReasonPhrase() const { switch (status_) { case kOk: @@ -101,17 +97,42 @@ std::string HttpResponse::GetReasonPhrase() const { return "Not Modified"; case kBadRequest: return "Bad Request"; + case kForbidden: + return "Forbidden"; case kNotFound: return "Not Found"; case kMethodNotAllowed: return "Method Not Allowed"; case kInternalServerError: return "Internal Server Error"; + case kNotImplemented: + return "Not Implemented"; default: return "Unknown"; } } +void HttpResponse::GetData(std::string* data) const { + *data += base::StringPrintf("HTTP/1.1 %d %s\r\n", + status_, GetReasonPhrase().c_str()); + + typedef HttpResponse::HeaderMap::const_iterator HeaderIter; + for (HeaderIter header = headers_.begin(); header != headers_.end(); + ++header) { + *data += header->first + ":" + header->second + "\r\n"; + } + std::string length; + if (!GetHeader(kContentLengthHeader, &length)) { + *data += base::StringPrintf( + "%s:%"PRIuS"\r\n", + kContentLengthHeader, body_.length()); + } + *data += "\r\n"; + + if (body_.length()) + *data += body_; +} + int HttpResponse::status() const { return status_; } @@ -120,16 +141,18 @@ void HttpResponse::set_status(int status) { status_ = status; } -const HttpResponse::HeaderMap* HttpResponse::headers() const { - return &headers_; +const std::string& HttpResponse::body() const { + return body_; } -const char* HttpResponse::data() const { - return data_.data(); +void HttpResponse::set_body(const std::string& body) { + body_ = body; } -size_t HttpResponse::length() const { - return data_.length(); +void HttpResponse::UpdateHeader(const std::string& name, + const std::string& new_value) { + RemoveHeader(name); + AddHeader(name, new_value); } } // namespace webdriver diff --git a/chrome/test/webdriver/http_response.h b/chrome/test/webdriver/http_response.h index f3c37d8..a3828f2 100644 --- a/chrome/test/webdriver/http_response.h +++ b/chrome/test/webdriver/http_response.h @@ -22,11 +22,15 @@ class HttpResponse { static const int kSeeOther; static const int kNotModified; static const int kBadRequest; + static const int kForbidden; static const int kNotFound; static const int kMethodNotAllowed; static const int kInternalServerError; + static const int kNotImplemented; + // Creates an HTTP response with a 200 OK status. HttpResponse(); + explicit HttpResponse(int status); ~HttpResponse(); // Sets a header in this response. If a header with the same |name| already @@ -48,30 +52,26 @@ class HttpResponse { // Convenience function for setting the Content-Type header for this response. void SetMimeType(const std::string& mime_type); - // Sets the message body for this response; will also set the "Content-Length" - // message header. - void SetBody(const std::string& data); - void SetBody(const char* const data, size_t length); - // Returns the status phrase recommended by RFC 2616 section 6.1.1 for this // response's status code. If the status code is not recognized, the default // "Unknown" status phrase will be used. std::string GetReasonPhrase() const; + // Appends this response to |data|, abiding by HTTP 1.1. + // This will add an appropriate "Content-Length" header if not already set. + void GetData(std::string* data) const; + int status() const; void set_status(int status); - const HeaderMap* headers() const; - const char* data() const; - size_t length() const; + const std::string& body() const; + void set_body(const std::string& body); private: void UpdateHeader(const std::string& name, const std::string& new_value); int status_; HeaderMap headers_; - std::string data_; - - DISALLOW_COPY_AND_ASSIGN(HttpResponse); + std::string body_; }; } // webdriver diff --git a/chrome/test/webdriver/http_response_unittest.cc b/chrome/test/webdriver/http_response_unittest.cc index 71be83f..4e204c6 100644 --- a/chrome/test/webdriver/http_response_unittest.cc +++ b/chrome/test/webdriver/http_response_unittest.cc @@ -65,25 +65,17 @@ TEST(HttpResponseTest, CanSetMimeType) { ExpectHeaderValue(response, "content-type", "text/html"); } -TEST(HttpResponseTest, SetBody) { +TEST(HttpResponseTest, GetData) { HttpResponse response; - - std::string body("foo bar"); - response.SetBody(body); - ASSERT_EQ(body.length(), response.length()); - ASSERT_EQ(body, std::string(response.data(), response.length())); - - // Grow the response size. - body.append(" baz"); - response.SetBody(body); - ASSERT_EQ(body.length(), response.length()); - ASSERT_EQ(body, std::string(response.data(), response.length())); - - // Shrink the response size. - body = "small"; - response.SetBody(body); - ASSERT_EQ(body.length(), response.length()); - ASSERT_EQ(body, std::string(response.data(), response.length())); + response.set_body("my body"); + std::string data; + response.GetData(&data); + const char* expected = + "HTTP/1.1 200 OK\r\n" + "content-length:7\r\n" + "\r\n" + "my body"; + ASSERT_STREQ(expected, data.c_str()); } } // namespace webdriver diff --git a/chrome/test/webdriver/webdriver_dispatch.cc b/chrome/test/webdriver/webdriver_dispatch.cc index d5a2784..7034229 100644 --- a/chrome/test/webdriver/webdriver_dispatch.cc +++ b/chrome/test/webdriver/webdriver_dispatch.cc @@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "base/command_line.h" #include "base/format_macros.h" #include "base/json/json_reader.h" #include "base/logging.h" @@ -25,6 +26,7 @@ #include "chrome/test/webdriver/http_response.h" #include "chrome/test/webdriver/webdriver_logging.h" #include "chrome/test/webdriver/webdriver_session_manager.h" +#include "chrome/test/webdriver/webdriver_switches.h" #include "chrome/test/webdriver/webdriver_util.h" namespace webdriver { @@ -35,14 +37,6 @@ namespace { // the message may not be transferred at all. const size_t kMaxHttpMessageSize = 1024 * 1024 * 16; // 16MB -bool ForbidsMessageBody(const std::string& request_method, - const HttpResponse& response) { - return request_method == "HEAD" || - response.status() == HttpResponse::kNoContent || - response.status() == HttpResponse::kNotModified || - (response.status() >= 100 && response.status() < 200); -} - void ReadRequestBody(const struct mg_request_info* const request_info, struct mg_connection* const connection, std::string* request_body) { @@ -69,6 +63,16 @@ void ReadRequestBody(const struct mg_request_info* const request_info, } } +void WriteHttpResponse(struct mg_connection* connection, + const HttpResponse& response) { + HttpResponse modified_response(response); + if (!CommandLine::ForCurrentProcess()->HasSwitch(kEnableKeepAlive)) + modified_response.AddHeader("connection", "close"); + std::string data; + modified_response.GetData(&data); + mg_write(connection, data.data(), data.length()); +} + void DispatchCommand(Command* const command, const std::string& method, Response* response) { @@ -89,12 +93,9 @@ void DispatchCommand(Command* const command, void SendOkWithBody(struct mg_connection* connection, const std::string& content) { - const char* response_fmt = "HTTP/1.1 200 OK\r\n" - "Content-Length:%d\r\n\r\n" - "%s"; - std::string response = base::StringPrintf( - response_fmt, content.length(), content.c_str()); - mg_write(connection, response.data(), response.length()); + HttpResponse response; + response.set_body(content); + WriteHttpResponse(connection, response); } void Shutdown(struct mg_connection* connection, @@ -102,7 +103,7 @@ void Shutdown(struct mg_connection* connection, void* user_data) { base::WaitableEvent* shutdown_event = reinterpret_cast<base::WaitableEvent*>(user_data); - mg_printf(connection, "HTTP/1.1 200 OK\r\n\r\n\r\n"); + WriteHttpResponse(connection, HttpResponse()); shutdown_event->Signal(); } @@ -161,16 +162,13 @@ void SimulateHang(struct mg_connection* connection, void SendNoContentResponse(struct mg_connection* connection, const struct mg_request_info* request_info, void* user_data) { - std::string response = "HTTP/1.1 204 No Content\r\n" - "Content-Length:0\r\n" - "\r\n"; - mg_write(connection, response.data(), response.length()); + WriteHttpResponse(connection, HttpResponse(HttpResponse::kNoContent)); } void SendForbidden(struct mg_connection* connection, const struct mg_request_info* request_info, void* user_data) { - mg_printf(connection, "HTTP/1.1 403 Forbidden\r\n\r\n"); + WriteHttpResponse(connection, HttpResponse(HttpResponse::kForbidden)); } void SendNotImplementedError(struct mg_connection* connection, @@ -183,14 +181,10 @@ void SendNotImplementedError(struct mg_connection* connection, "\"Command has not been implemented yet: %s %s\"}}", kUnknownCommand, request_info->request_method, request_info->uri); - std::string header = base::StringPrintf( - "HTTP/1.1 501 Not Implemented\r\n" - "Content-Type:application/json\r\n" - "Content-Length:%" PRIuS "\r\n" - "\r\n", body.length()); - - mg_write(connection, header.data(), header.length()); - mg_write(connection, body.data(), body.length()); + HttpResponse response(HttpResponse::kNotImplemented); + response.AddHeader("Content-Type", "application/json"); + response.set_body(body); + WriteHttpResponse(connection, response); } } // namespace @@ -214,7 +208,7 @@ void PrepareHttpResponse(const Response& command_response, if (!value->GetAsString(&location)) { // This should never happen. http_response->set_status(HttpResponse::kInternalServerError); - http_response->SetBody("Unable to set 'Location' header: response " + http_response->set_body("Unable to set 'Location' header: response " "value is not a string: " + command_response.ToJSON()); return; @@ -234,7 +228,7 @@ void PrepareHttpResponse(const Response& command_response, if (!value->IsType(Value::TYPE_LIST)) { // This should never happen. http_response->set_status(HttpResponse::kInternalServerError); - http_response->SetBody( + http_response->set_body( "Unable to set 'Allow' header: response value was " "not a list of strings: " + command_response.ToJSON()); return; @@ -250,7 +244,7 @@ void PrepareHttpResponse(const Response& command_response, } else { // This should never happen. http_response->set_status(HttpResponse::kInternalServerError); - http_response->SetBody( + http_response->set_body( "Unable to set 'Allow' header: response value was " "not a list of strings: " + command_response.ToJSON()); return; @@ -270,7 +264,7 @@ void PrepareHttpResponse(const Response& command_response, } http_response->SetMimeType("application/json; charset=utf-8"); - http_response->SetBody(command_response.ToJSON()); + http_response->set_body(command_response.ToJSON()); } void SendResponse(struct mg_connection* const connection, @@ -278,22 +272,7 @@ void SendResponse(struct mg_connection* const connection, const Response& response) { HttpResponse http_response; PrepareHttpResponse(response, &http_response); - - std::string message_header = base::StringPrintf("HTTP/1.1 %d %s\r\n", - http_response.status(), http_response.GetReasonPhrase().c_str()); - - typedef HttpResponse::HeaderMap::const_iterator HeaderIter; - for (HeaderIter header = http_response.headers()->begin(); - header != http_response.headers()->end(); - ++header) { - message_header.append(base::StringPrintf("%s:%s\r\n", - header->first.c_str(), header->second.c_str())); - } - message_header.append("\r\n"); - - mg_write(connection, message_header.data(), message_header.length()); - if (!ForbidsMessageBody(request_method, http_response)) - mg_write(connection, http_response.data(), http_response.length()); + WriteHttpResponse(connection, http_response); } bool ParseRequestInfo(const struct mg_request_info* const request_info, diff --git a/chrome/test/webdriver/webdriver_dispatch_unittest.cc b/chrome/test/webdriver/webdriver_dispatch_unittest.cc index edee103..6abf90c 100644 --- a/chrome/test/webdriver/webdriver_dispatch_unittest.cc +++ b/chrome/test/webdriver/webdriver_dispatch_unittest.cc @@ -121,23 +121,18 @@ TEST(DispatchTest, ReturnsCommandResponseAsJson) { EXPECT_EQ(HttpResponse::kOk, http_response.status()); ExpectHeaderValue(http_response, "content-type", "application/json; charset=utf-8"); - ExpectHeaderValue(http_response, "content-length", - base::StringPrintf("%"PRIuS, kExpectedData.length())); // We do not know whether the response status or value will be // encoded first, so we have to parse the response body to // verify it is correct. - std::string actual_data(http_response.data(), - http_response.length()); - int error_code; std::string error_message; scoped_ptr<Value> parsed_response(base::JSONReader::ReadAndReturnError( - actual_data, base::JSON_PARSE_RFC, &error_code, &error_message)); + http_response.body(), base::JSON_PARSE_RFC, &error_code, &error_message)); ASSERT_TRUE(parsed_response.get() != NULL) << error_message; ASSERT_TRUE(parsed_response->IsType(Value::TYPE_DICTIONARY)) - << "Response should be a dictionary: " << actual_data; + << "Response should be a dictionary: " << http_response.body(); DictionaryValue* dict = static_cast<DictionaryValue*>(parsed_response.get()); EXPECT_EQ(2u, dict->size()); diff --git a/chrome/test/webdriver/webdriver_server.cc b/chrome/test/webdriver/webdriver_server.cc index 899ed28..ccb8c70 100644 --- a/chrome/test/webdriver/webdriver_server.cc +++ b/chrome/test/webdriver/webdriver_server.cc @@ -59,6 +59,7 @@ #include "chrome/test/webdriver/webdriver_dispatch.h" #include "chrome/test/webdriver/webdriver_logging.h" #include "chrome/test/webdriver/webdriver_session_manager.h" +#include "chrome/test/webdriver/webdriver_switches.h" #include "chrome/test/webdriver/webdriver_util.h" #include "third_party/mongoose/mongoose.h" @@ -259,7 +260,7 @@ int RunChromeDriver() { return 1; } } - if (cmd_line->HasSwitch("enable-keep-alive")) + if (cmd_line->HasSwitch(kEnableKeepAlive)) enable_keep_alive = true; bool logging_success = InitWebDriverLogging(log_path, kAllLogLevel); diff --git a/chrome/test/webdriver/webdriver_switches.cc b/chrome/test/webdriver/webdriver_switches.cc new file mode 100644 index 0000000..3e44277 --- /dev/null +++ b/chrome/test/webdriver/webdriver_switches.cc @@ -0,0 +1,13 @@ +// 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/test/webdriver/webdriver_switches.h" + +namespace webdriver { + +// Instructs the mongoose webserver to enable HTTP persistent +// connections. +const char kEnableKeepAlive[] = "enable-keep-alive"; + +} // namespace webdriver diff --git a/chrome/test/webdriver/webdriver_switches.h b/chrome/test/webdriver/webdriver_switches.h new file mode 100644 index 0000000..639d1b3 --- /dev/null +++ b/chrome/test/webdriver/webdriver_switches.h @@ -0,0 +1,14 @@ +// 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. + +#ifndef CHROME_TEST_WEBDRIVER_WEBDRIVER_SWITCHES_H_ +#define CHROME_TEST_WEBDRIVER_WEBDRIVER_SWITCHES_H_ + +namespace webdriver { + +extern const char kEnableKeepAlive[]; + +} // namespace webdriver + +#endif // CHROME_TEST_WEBDRIVER_WEBDRIVER_SWITCHES_H_ |