diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-04-05 17:15:33 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-04-11 07:47:18 +0000 |
commit | 7324afb043a0b1e623d8e8eb906cdc53bdeb4685 (patch) | |
tree | a3fe2d74ea9c9e142c390dac4ca0e219382ace46 /chromium/net/server | |
parent | 6a4cabb866f66d4128a97cdc6d9d08ce074f1247 (diff) | |
download | qtwebengine-chromium-7324afb043a0b1e623d8e8eb906cdc53bdeb4685.tar.gz |
BASELINE: Update Chromium to 58.0.3029.54
Change-Id: I67f57065a7afdc8e4614adb5c0230281428df4d1
Reviewed-by: Peter Varga <pvarga@inf.u-szeged.hu>
Diffstat (limited to 'chromium/net/server')
-rw-r--r-- | chromium/net/server/http_server.cc | 4 | ||||
-rw-r--r-- | chromium/net/server/http_server_fuzzer.cc | 109 | ||||
-rw-r--r-- | chromium/net/server/http_server_unittest.cc | 72 | ||||
-rw-r--r-- | chromium/net/server/web_socket.cc | 11 |
4 files changed, 185 insertions, 11 deletions
diff --git a/chromium/net/server/http_server.cc b/chromium/net/server/http_server.cc index 7300a38f8c1..77c2c0d9b6c 100644 --- a/chromium/net/server/http_server.cc +++ b/chromium/net/server/http_server.cc @@ -449,8 +449,8 @@ bool HttpServer::ParseHeaders(const char* data, buffer.append(&ch, 1); break; case ST_DONE: - DCHECK(input == INPUT_LF); - return true; + // We got CR to get this far, also need the LF + return (input == INPUT_LF); case ST_ERR: return false; } diff --git a/chromium/net/server/http_server_fuzzer.cc b/chromium/net/server/http_server_fuzzer.cc new file mode 100644 index 00000000000..55cdaf8661f --- /dev/null +++ b/chromium/net/server/http_server_fuzzer.cc @@ -0,0 +1,109 @@ +// Copyright 2017 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 "base/logging.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "base/test/fuzzed_data_provider.h" +#include "net/base/net_errors.h" +#include "net/log/test_net_log.h" +#include "net/server/http_server.h" +#include "net/socket/fuzzed_server_socket.h" + +namespace { + +class WaitTillHttpCloseDelegate : public net::HttpServer::Delegate { + public: + WaitTillHttpCloseDelegate(base::FuzzedDataProvider* data_provider, + const base::Closure& done_closure) + : server_(nullptr), + data_provider_(data_provider), + done_closure_(done_closure), + action_flags_(data_provider_->ConsumeUint8()) {} + + void set_server(net::HttpServer* server) { server_ = server; } + + void OnConnect(int connection_id) override { + if (!(action_flags_ & ACCEPT_CONNECTION)) + server_->Close(connection_id); + } + + void OnHttpRequest(int connection_id, + const net::HttpServerRequestInfo& info) override { + if (!(action_flags_ & ACCEPT_MESSAGE)) { + server_->Close(connection_id); + return; + } + + if (action_flags_ & REPLY_TO_MESSAGE) { + server_->Send200(connection_id, + data_provider_->ConsumeRandomLengthString(64), + "text/html"); + } + } + + void OnWebSocketRequest(int connection_id, + const net::HttpServerRequestInfo& info) override { + if (action_flags_ & CLOSE_WEBSOCKET_RATHER_THAN_ACCEPT) { + server_->Close(connection_id); + return; + } + + if (action_flags_ & ACCEPT_WEBSOCKET) + server_->AcceptWebSocket(connection_id, info); + } + + void OnWebSocketMessage(int connection_id, const std::string& data) override { + if (!(action_flags_ & ACCEPT_MESSAGE)) { + server_->Close(connection_id); + return; + } + + if (action_flags_ & REPLY_TO_MESSAGE) { + server_->SendOverWebSocket(connection_id, + data_provider_->ConsumeRandomLengthString(64)); + } + } + + void OnClose(int connection_id) override { done_closure_.Run(); } + + private: + enum { + ACCEPT_CONNECTION = 1, + ACCEPT_MESSAGE = 2, + REPLY_TO_MESSAGE = 4, + ACCEPT_WEBSOCKET = 8, + CLOSE_WEBSOCKET_RATHER_THAN_ACCEPT = 16 + }; + + net::HttpServer* server_; + base::FuzzedDataProvider* const data_provider_; + base::Closure done_closure_; + const uint8_t action_flags_; + + DISALLOW_COPY_AND_ASSIGN(WaitTillHttpCloseDelegate); +}; + +} // namespace + +// Fuzzer for HttpServer +// +// |data| is used to create a FuzzedServerSocket. +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + net::TestNetLog test_net_log; + base::FuzzedDataProvider data_provider(data, size); + + std::unique_ptr<net::ServerSocket> server_socket( + base::MakeUnique<net::FuzzedServerSocket>(&data_provider, &test_net_log)); + CHECK_EQ(net::OK, + server_socket->ListenWithAddressAndPort("127.0.0.1", 80, 5)); + + base::RunLoop run_loop; + WaitTillHttpCloseDelegate delegate(&data_provider, run_loop.QuitClosure()); + net::HttpServer server(std::move(server_socket), &delegate); + delegate.set_server(&server); + run_loop.Run(); + return 0; +} diff --git a/chromium/net/server/http_server_unittest.cc b/chromium/net/server/http_server_unittest.cc index 9b6dee1bea9..a9168c91374 100644 --- a/chromium/net/server/http_server_unittest.cc +++ b/chromium/net/server/http_server_unittest.cc @@ -133,6 +133,17 @@ class TestHttpClient { return true; } + void ExpectUsedThenDisconnectedWithNoData() { + // Check that the socket was opened... + ASSERT_TRUE(socket_->WasEverUsed()); + + // ...then closed when the server disconnected. Verify that the socket was + // closed by checking that a Read() fails. + std::string response; + ASSERT_FALSE(Read(&response, 1u)); + ASSERT_TRUE(response.empty()); + } + TCPClientSocket& socket() { return *socket_; } private: @@ -191,7 +202,8 @@ class TestHttpClient { class HttpServerTest : public testing::Test, public HttpServer::Delegate { public: - HttpServerTest() : quit_after_request_count_(0) {} + HttpServerTest() + : quit_after_request_count_(0), quit_on_close_connection_(-1) {} void SetUp() override { std::unique_ptr<ServerSocket> server_socket( @@ -201,6 +213,12 @@ class HttpServerTest : public testing::Test, ASSERT_THAT(server_->GetLocalAddress(&server_address_), IsOk()); } + void TearDown() override { + // Run the event loop some to make sure that the memory handed over to + // DeleteSoon gets fully freed. + base::RunLoop().RunUntilIdle(); + } + void OnConnect(int connection_id) override { DCHECK(connection_map_.find(connection_id) == connection_map_.end()); connection_map_[connection_id] = true; @@ -225,6 +243,8 @@ class HttpServerTest : public testing::Test, void OnClose(int connection_id) override { DCHECK(connection_map_.find(connection_id) != connection_map_.end()); connection_map_[connection_id] = false; + if (connection_id == quit_on_close_connection_) + run_loop_quit_func_.Run(); } bool RunUntilRequestsReceived(size_t count) { @@ -239,10 +259,27 @@ class HttpServerTest : public testing::Test, return success; } + bool RunUntilConnectionIdClosed(int connection_id) { + quit_on_close_connection_ = connection_id; + auto iter = connection_map_.find(connection_id); + if (iter != connection_map_.end() && !iter->second) { + // Already disconnected. + return true; + } + + base::RunLoop run_loop; + run_loop_quit_func_ = run_loop.QuitClosure(); + bool success = RunLoopWithTimeout(&run_loop); + run_loop_quit_func_.Reset(); + return success; + } + HttpServerRequestInfo GetRequest(size_t request_index) { return requests_[request_index].first; } + size_t num_requests() const { return requests_.size(); } + int GetConnectionId(size_t request_index) { return requests_[request_index].second; } @@ -264,6 +301,7 @@ class HttpServerTest : public testing::Test, private: size_t quit_after_request_count_; + int quit_on_close_connection_; }; namespace { @@ -296,6 +334,15 @@ TEST_F(HttpServerTest, Request) { base::CompareCase::SENSITIVE)); } +TEST_F(HttpServerTest, RequestBrokenTermination) { + TestHttpClient client; + ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk()); + client.Send("GET /test HTTP/1.1\r\n\r)"); + ASSERT_TRUE(RunUntilConnectionIdClosed(1)); + EXPECT_EQ(0u, num_requests()); + client.ExpectUsedThenDisconnectedWithNoData(); +} + TEST_F(HttpServerTest, RequestWithHeaders) { TestHttpClient client; ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk()); @@ -421,6 +468,20 @@ TEST_F(WebSocketTest, RequestWebSocket) { ASSERT_TRUE(RunUntilRequestsReceived(1)); } +TEST_F(WebSocketTest, RequestWebSocketTrailingJunk) { + TestHttpClient client; + ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk()); + client.Send( + "GET /test HTTP/1.1\r\n" + "Upgrade: WebSocket\r\n" + "Connection: SomethingElse, Upgrade\r\n" + "Sec-WebSocket-Version: 8\r\n" + "Sec-WebSocket-Key: key\r\n" + "\r\nHello? Anyone"); + ASSERT_TRUE(RunUntilConnectionIdClosed(1)); + client.ExpectUsedThenDisconnectedWithNoData(); +} + TEST_F(HttpServerTest, RequestWithTooLargeBody) { class TestURLFetcherDelegate : public URLFetcherDelegate { public: @@ -503,14 +564,7 @@ TEST_F(HttpServerTest, WrongProtocolRequest) { ASSERT_EQ(1u, connection_map().size()); ASSERT_FALSE(connection_map().begin()->second); - // Assert that the socket was opened... - ASSERT_TRUE(client.socket().WasEverUsed()); - - // ...then closed when the server disconnected. Verify that the socket was - // closed by checking that a Read() fails. - std::string response; - ASSERT_FALSE(client.Read(&response, 1u)); - ASSERT_EQ(std::string(), response); + client.ExpectUsedThenDisconnectedWithNoData(); // Reset the state of the connection map. connection_map().clear(); diff --git a/chromium/net/server/web_socket.cc b/chromium/net/server/web_socket.cc index 79ffcecb7ad..bd3d9e494ab 100644 --- a/chromium/net/server/web_socket.cc +++ b/chromium/net/server/web_socket.cc @@ -98,6 +98,17 @@ WebSocket::ParseResult WebSocket::Read(std::string* message) { if (closed_) return FRAME_CLOSE; + if (!encoder_) { + // RFC6455, section 4.1 says "Once the client's opening handshake has been + // sent, the client MUST wait for a response from the server before sending + // any further data". If |encoder_| is null here, ::Accept either has not + // been called at all, or has rejected a request rather than producing + // a server handshake. Either way, the client clearly couldn't have gotten + // a proper server handshake, so error out, especially since this method + // can't proceed without an |encoder_|. + return FRAME_ERROR; + } + HttpConnection::ReadIOBuffer* read_buf = connection_->read_buf(); base::StringPiece frame(read_buf->StartOfBuffer(), read_buf->GetSize()); int bytes_consumed = 0; |