diff --git a/cloud_print/gcp20/prototype/privet_http_server.h b/cloud_print/gcp20/prototype/privet_http_server.h index c4071f0729507d..84a464cae4739d 100644 --- a/cloud_print/gcp20/prototype/privet_http_server.h +++ b/cloud_print/gcp20/prototype/privet_http_server.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/values.h" +#include "net/http/http_status_code.h" #include "net/server/http_server.h" #include "net/server/http_server_request_info.h" diff --git a/content/browser/devtools/devtools_http_handler_impl.cc b/content/browser/devtools/devtools_http_handler_impl.cc index 55b2787c90eba0..6afc65d6dd2dfa 100644 --- a/content/browser/devtools/devtools_http_handler_impl.cc +++ b/content/browser/devtools/devtools_http_handler_impl.cc @@ -43,6 +43,7 @@ #include "net/base/io_buffer.h" #include "net/base/ip_endpoint.h" #include "net/server/http_server_request_info.h" +#include "net/server/http_server_response_info.h" #include "ui/base/layout.h" #include "url/gurl.h" #include "webkit/common/user_agent/user_agent.h" @@ -754,19 +755,15 @@ void DevToolsHttpHandlerImpl::SendJson(int connection_id, scoped_ptr message_object(new base::StringValue(message)); base::JSONWriter::Write(message_object.get(), &json_message); - std::string response; - std::string mime_type = "application/json; charset=UTF-8"; - - response = base::StringPrintf("%s%s", json_value.c_str(), message.c_str()); + net::HttpServerResponseInfo response(status_code); + response.SetBody(json_value + message, "application/json; charset=UTF-8"); thread_->message_loop()->PostTask( FROM_HERE, - base::Bind(&net::HttpServer::Send, + base::Bind(&net::HttpServer::SendResponse, server_.get(), connection_id, - status_code, - response, - mime_type)); + response)); } void DevToolsHttpHandlerImpl::Send200(int connection_id, diff --git a/content/browser/devtools/devtools_http_handler_impl.h b/content/browser/devtools/devtools_http_handler_impl.h index 766bb61e56cf57..88dcd311a3ab7d 100644 --- a/content/browser/devtools/devtools_http_handler_impl.h +++ b/content/browser/devtools/devtools_http_handler_impl.h @@ -16,6 +16,7 @@ #include "content/public/browser/devtools_http_handler.h" #include "content/public/browser/devtools_http_handler_delegate.h" #include "content/public/browser/worker_service.h" +#include "net/http/http_status_code.h" #include "net/server/http_server.h" namespace base { diff --git a/net/net.gyp b/net/net.gyp index b945ce0ad96138..68e4116c550186 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -1475,6 +1475,7 @@ '../testing/gtest.gyp:gtest', '../third_party/zlib/zlib.gyp:zlib', '../url/url.gyp:url_lib', + 'http_server', 'net', 'net_test_support' ], @@ -1747,6 +1748,7 @@ 'quic/quic_time_test.cc', 'quic/quic_utils_test.cc', 'quic/reliable_quic_stream_test.cc', + 'server/http_server_response_info_unittest.cc', 'socket/buffered_write_stream_socket_unittest.cc', 'socket/client_socket_pool_base_unittest.cc', 'socket/deterministic_socket_data_unittest.cc', @@ -2328,6 +2330,8 @@ 'server/http_server.h', 'server/http_server_request_info.cc', 'server/http_server_request_info.h', + 'server/http_server_response_info.cc', + 'server/http_server_response_info.h', 'server/web_socket.cc', 'server/web_socket.h', ], diff --git a/net/server/http_connection.cc b/net/server/http_connection.cc index 66541faa37354a..d964cb0738b3ad 100644 --- a/net/server/http_connection.cc +++ b/net/server/http_connection.cc @@ -4,9 +4,8 @@ #include "net/server/http_connection.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" #include "net/server/http_server.h" +#include "net/server/http_server_response_info.h" #include "net/server/web_socket.h" #include "net/socket/stream_listen_socket.h" @@ -26,22 +25,8 @@ void HttpConnection::Send(const char* bytes, int len) { socket_->Send(bytes, len); } -void HttpConnection::Send(HttpStatusCode status_code, - const std::string& data, - const std::string& content_type) { - if (!socket_.get()) - return; - - socket_->Send(base::StringPrintf( - "HTTP/1.1 %d %s\r\n" - "Content-Type:%s\r\n" - "Content-Length:%d\r\n" - "\r\n", - status_code, - GetHttpReasonPhrase(status_code), - content_type.c_str(), - static_cast(data.length()))); - socket_->Send(data); +void HttpConnection::Send(const HttpServerResponseInfo& response) { + Send(response.Serialize()); } HttpConnection::HttpConnection(HttpServer* server, StreamListenSocket* sock) diff --git a/net/server/http_connection.h b/net/server/http_connection.h index 488d5283f8d93c..b0e37663d4f61b 100644 --- a/net/server/http_connection.h +++ b/net/server/http_connection.h @@ -15,6 +15,7 @@ namespace net { class HttpServer; +class HttpServerResponseInfo; class StreamListenSocket; class WebSocket; @@ -24,9 +25,7 @@ class HttpConnection { void Send(const std::string& data); void Send(const char* bytes, int len); - void Send(HttpStatusCode status_code, - const std::string& data, - const std::string& content_type); + void Send(const HttpServerResponseInfo& response); void Shift(int num_bytes); diff --git a/net/server/http_server.cc b/net/server/http_server.cc index b78073983aed08..3d54c4071e7880 100644 --- a/net/server/http_server.cc +++ b/net/server/http_server.cc @@ -13,6 +13,7 @@ #include "build/build_config.h" #include "net/server/http_connection.h" #include "net/server/http_server_request_info.h" +#include "net/server/http_server_response_info.h" #include "net/server/web_socket.h" #include "net/socket/tcp_listen_socket.h" @@ -45,14 +46,21 @@ void HttpServer::SendOverWebSocket(int connection_id, connection->web_socket_->Send(data); } +void HttpServer::SendResponse(int connection_id, + const HttpServerResponseInfo& response) { + HttpConnection* connection = FindConnection(connection_id); + if (connection == NULL) + return; + connection->Send(response); +} + void HttpServer::Send(int connection_id, HttpStatusCode status_code, const std::string& data, const std::string& content_type) { - HttpConnection* connection = FindConnection(connection_id); - if (connection == NULL) - return; - connection->Send(status_code, data, content_type); + HttpServerResponseInfo response(status_code); + response.SetBody(data, content_type); + SendResponse(connection_id, response); } void HttpServer::Send200(int connection_id, @@ -62,11 +70,11 @@ void HttpServer::Send200(int connection_id, } void HttpServer::Send404(int connection_id) { - Send(connection_id, HTTP_NOT_FOUND, std::string(), "text/html"); + SendResponse(connection_id, HttpServerResponseInfo::CreateFor404()); } void HttpServer::Send500(int connection_id, const std::string& message) { - Send(connection_id, HTTP_INTERNAL_SERVER_ERROR, message, "text/html"); + SendResponse(connection_id, HttpServerResponseInfo::CreateFor500(message)); } void HttpServer::Close(int connection_id) { diff --git a/net/server/http_server.h b/net/server/http_server.h index b5ba0378d219c7..f4345752e2dd2b 100644 --- a/net/server/http_server.h +++ b/net/server/http_server.h @@ -17,6 +17,7 @@ namespace net { class HttpConnection; class HttpServerRequestInfo; +class HttpServerResponseInfo; class IPEndPoint; class WebSocket; @@ -46,6 +47,7 @@ class HttpServer : public StreamListenSocket::Delegate, void AcceptWebSocket(int connection_id, const HttpServerRequestInfo& request); void SendOverWebSocket(int connection_id, const std::string& data); + void SendResponse(int connection_id, const HttpServerResponseInfo& response); void Send(int connection_id, HttpStatusCode status_code, const std::string& data, diff --git a/net/server/http_server_response_info.cc b/net/server/http_server_response_info.cc new file mode 100644 index 00000000000000..e4c6043aa8d627 --- /dev/null +++ b/net/server/http_server_response_info.cc @@ -0,0 +1,67 @@ +// Copyright 2013 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 "net/server/http_server_response_info.h" + +#include "base/format_macros.h" +#include "base/strings/stringprintf.h" +#include "net/http/http_request_headers.h" + +namespace net { + +HttpServerResponseInfo::HttpServerResponseInfo() : status_code_(HTTP_OK) {} + +HttpServerResponseInfo::HttpServerResponseInfo(HttpStatusCode status_code) + : status_code_(status_code) {} + +HttpServerResponseInfo::~HttpServerResponseInfo() {} + +// static +HttpServerResponseInfo HttpServerResponseInfo::CreateFor404() { + HttpServerResponseInfo response(HTTP_NOT_FOUND); + response.SetBody(std::string(), "text/html"); + return response; +} + +// static +HttpServerResponseInfo HttpServerResponseInfo::CreateFor500( + const std::string& body) { + HttpServerResponseInfo response(HTTP_INTERNAL_SERVER_ERROR); + response.SetBody(body, "text/html"); + return response; +} + +void HttpServerResponseInfo::AddHeader(const std::string& name, + const std::string& value) { + headers_.push_back(std::make_pair(name, value)); +} + +void HttpServerResponseInfo::SetBody(const std::string& body, + const std::string& content_type) { + DCHECK(body_.empty()); + body_ = body; + AddHeader(HttpRequestHeaders::kContentLength, + base::StringPrintf("%" PRIuS, body.length())); + AddHeader(HttpRequestHeaders::kContentType, content_type); +} + +std::string HttpServerResponseInfo::Serialize() const { + std::string response = base::StringPrintf( + "HTTP/1.1 %d %s\r\n", status_code_, GetHttpReasonPhrase(status_code_)); + Headers::const_iterator header; + for (header = headers_.begin(); header != headers_.end(); ++header) + response += header->first + ":" + header->second + "\r\n"; + + return response + "\r\n" + body_; +} + +HttpStatusCode HttpServerResponseInfo::status_code() const { + return status_code_; +} + +const std::string& HttpServerResponseInfo::body() const { + return body_; +} + +} // namespace net diff --git a/net/server/http_server_response_info.h b/net/server/http_server_response_info.h new file mode 100644 index 00000000000000..d6cedaa844664d --- /dev/null +++ b/net/server/http_server_response_info.h @@ -0,0 +1,46 @@ +// Copyright 2013 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 NET_SERVER_HTTP_SERVER_RESPONSE_INFO_H_ +#define NET_SERVER_HTTP_SERVER_RESPONSE_INFO_H_ + +#include +#include +#include + +#include "net/http/http_status_code.h" + +namespace net { + +class HttpServerResponseInfo { + public: + // Creates a 200 OK HttpServerResponseInfo. + HttpServerResponseInfo(); + explicit HttpServerResponseInfo(HttpStatusCode status_code); + ~HttpServerResponseInfo(); + + static HttpServerResponseInfo CreateFor404(); + static HttpServerResponseInfo CreateFor500(const std::string& body); + + void AddHeader(const std::string& name, const std::string& value); + + // This also adds an appropriate Content-Length header. + void SetBody(const std::string& body, const std::string& content_type); + + std::string Serialize() const; + + HttpStatusCode status_code() const; + const std::string& body() const; + + private: + typedef std::vector > Headers; + + HttpStatusCode status_code_; + Headers headers_; + std::string body_; +}; + +} // namespace net + +#endif // NET_SERVER_HTTP_SERVER_RESPONSE_INFO_H_ diff --git a/net/server/http_server_response_info_unittest.cc b/net/server/http_server_response_info_unittest.cc new file mode 100644 index 00000000000000..f7b8e251d34136 --- /dev/null +++ b/net/server/http_server_response_info_unittest.cc @@ -0,0 +1,51 @@ +// Copyright 2013 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 "net/http/http_status_code.h" +#include "net/server/http_server_response_info.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +TEST(HttpServerResponseInfoTest, StatusLine) { + HttpServerResponseInfo response; + ASSERT_EQ(HTTP_OK, response.status_code()); + ASSERT_EQ("HTTP/1.1 200 OK\r\n\r\n", response.Serialize()); +} + +TEST(HttpServerResponseInfoTest, Headers) { + HttpServerResponseInfo response; + response.AddHeader("A", "1"); + response.AddHeader("A", "2"); + ASSERT_EQ("HTTP/1.1 200 OK\r\nA:1\r\nA:2\r\n\r\n", response.Serialize()); +} + +TEST(HttpServerResponseInfoTest, Body) { + HttpServerResponseInfo response; + ASSERT_EQ(std::string(), response.body()); + response.SetBody("body", "type"); + ASSERT_EQ("body", response.body()); + ASSERT_EQ( + "HTTP/1.1 200 OK\r\nContent-Length:4\r\nContent-Type:type\r\n\r\nbody", + response.Serialize()); +} + +TEST(HttpServerResponseInfoTest, CreateFor404) { + HttpServerResponseInfo response = HttpServerResponseInfo::CreateFor404(); + ASSERT_EQ( + "HTTP/1.1 404 Not Found\r\n" + "Content-Length:0\r\nContent-Type:text/html\r\n\r\n", + response.Serialize()); +} + +TEST(HttpServerResponseInfoTest, CreateFor500) { + HttpServerResponseInfo response = + HttpServerResponseInfo::CreateFor500("mess"); + ASSERT_EQ( + "HTTP/1.1 500 Internal Server Error\r\n" + "Content-Length:4\r\nContent-Type:text/html\r\n\r\nmess", + response.Serialize()); +} + +} // namespace net diff --git a/net/server/web_socket.cc b/net/server/web_socket.cc index df5b0ae073841c..746108548e69fd 100644 --- a/net/server/web_socket.cc +++ b/net/server/web_socket.cc @@ -16,6 +16,7 @@ #include "base/sys_byteorder.h" #include "net/server/http_connection.h" #include "net/server/http_server_request_info.h" +#include "net/server/http_server_response_info.h" namespace net { @@ -115,18 +116,16 @@ class WebSocketHixie76 : public net::WebSocket { std::string key2 = request.GetHeaderValue("Sec-WebSocket-Key2"); if (key1.empty()) { - connection->Send(net::HTTP_INTERNAL_SERVER_ERROR, - "Invalid request format. " - "Sec-WebSocket-Key1 is empty or isn't specified.", - "text/html"); + connection->Send(HttpServerResponseInfo::CreateFor500( + "Invalid request format. Sec-WebSocket-Key1 is empty or isn't " + "specified.")); return; } if (key2.empty()) { - connection->Send(net::HTTP_INTERNAL_SERVER_ERROR, - "Invalid request format. " - "Sec-WebSocket-Key2 is empty or isn't specified.", - "text/html"); + connection->Send(HttpServerResponseInfo::CreateFor500( + "Invalid request format. Sec-WebSocket-Key2 is empty or isn't " + "specified.")); return; } @@ -179,10 +178,9 @@ class WebSocketHybi17 : public WebSocket { std::string key = request.GetHeaderValue("Sec-WebSocket-Key"); if (key.empty()) { - connection->Send(net::HTTP_INTERNAL_SERVER_ERROR, - "Invalid request format. " - "Sec-WebSocket-Key is empty or isn't specified.", - "text/html"); + connection->Send(HttpServerResponseInfo::CreateFor500( + "Invalid request format. Sec-WebSocket-Key is empty or isn't " + "specified.")); return NULL; } return new WebSocketHybi17(connection, request, pos);