diff --git a/net/BUILD.gn b/net/BUILD.gn index 43213a2f73..5a7e7fb42e 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn @@ -3261,12 +3261,16 @@ source_set("simple_quic_tools") { "third_party/quic/tools/quic_simple_dispatcher.h", "third_party/quic/tools/quic_simple_server_session.cc", "third_party/quic/tools/quic_simple_server_session.h", + "third_party/quic/tools/quic_naive_server_stream.cc", + "third_party/quic/tools/quic_naive_server_stream.h", "third_party/quic/tools/quic_simple_server_stream.cc", "third_party/quic/tools/quic_simple_server_stream.h", "third_party/quic/tools/quic_spdy_client_base.cc", "third_party/quic/tools/quic_spdy_client_base.h", "tools/quic/quic_client_message_loop_network_helper.cc", "tools/quic/quic_client_message_loop_network_helper.h", + "tools/quic/quic_naive_proxy_backend.cc", + "tools/quic/quic_naive_proxy_backend.h", "tools/quic/quic_http_proxy_backend.cc", "tools/quic/quic_http_proxy_backend.h", "tools/quic/quic_http_proxy_backend_stream.cc", diff --git a/net/third_party/quic/tools/quic_naive_server_stream.cc b/net/third_party/quic/tools/quic_naive_server_stream.cc new file mode 100644 index 0000000000..82c540db24 --- /dev/null +++ b/net/third_party/quic/tools/quic_naive_server_stream.cc @@ -0,0 +1,99 @@ +// 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 "net/third_party/quic/tools/quic_naive_server_stream.h" + +#include +#include + +#include "net/third_party/quic/core/http/quic_spdy_stream.h" +#include "net/third_party/quic/core/http/spdy_utils.h" +#include "net/third_party/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quic/platform/api/quic_flags.h" +#include "net/third_party/quic/platform/api/quic_logging.h" +#include "net/third_party/quic/platform/api/quic_map_util.h" +#include "net/third_party/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quic/tools/quic_simple_server_session.h" +#include "net/third_party/spdy/core/spdy_protocol.h" + +namespace quic { + +QuicNaiveServerStream::QuicNaiveServerStream( + QuicStreamId id, + QuicSpdySession* session, + QuicSimpleServerBackend* backend) + : QuicSpdyServerStreamBase(id, session), + backend_(backend) {} + +QuicNaiveServerStream::~QuicNaiveServerStream() { + backend_->OnCloseStream(this); +} + +void QuicNaiveServerStream::SendErrorResponse(int resp_code) { + QUIC_DVLOG(1) << "Stream " << id() << " sending error response."; + spdy::SpdyHeaderBlock headers; + if (resp_code <= 0) { + headers[":status"] = "500"; + } else { + headers[":status"] = QuicTextUtils::Uint64ToString(resp_code); + } + WriteHeaders(std::move(headers), /*fin=*/true, nullptr); +} + +void QuicNaiveServerStream::OnInitialHeadersComplete( + bool fin, + size_t frame_len, + const QuicHeaderList& header_list) { + QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list); + backend_->OnReadHeaders(this, header_list); + ConsumeHeaderList(); +} + +void QuicNaiveServerStream::OnTrailingHeadersComplete( + bool fin, + size_t frame_len, + const QuicHeaderList& header_list) { + QUIC_BUG << "Server does not support receiving Trailers."; + SendErrorResponse(0); +} + +void QuicNaiveServerStream::OnDataAvailable() { + while (HasBytesToRead()) { + struct iovec iov; + if (GetReadableRegions(&iov, 1) == 0) { + // No more data to read. + break; + } + backend_->OnReadData(this, iov.iov_base, iov.iov_len); + } + if (sequencer()->IsClosed()) { + OnFinRead(); + } else { + sequencer()->SetUnblocked(); + } +} + +void QuicNaiveServerStream::PushResponse( + spdy::SpdyHeaderBlock push_request_headers) { + QUIC_NOTREACHED(); +} + +QuicConnectionId QuicNaiveServerStream::connection_id() const { + return spdy_session()->connection_id(); +} + +QuicStreamId QuicNaiveServerStream::stream_id() const { + return id(); +} + +QuicString QuicNaiveServerStream::peer_host() const { + return spdy_session()->peer_address().host().ToString(); +} + +void QuicNaiveServerStream::OnResponseBackendComplete( + const QuicBackendResponse* response, + std::list resources) { +} + +} // namespace quic diff --git a/net/third_party/quic/tools/quic_naive_server_stream.h b/net/third_party/quic/tools/quic_naive_server_stream.h new file mode 100644 index 0000000000..5d82d0f397 --- /dev/null +++ b/net/third_party/quic/tools/quic_naive_server_stream.h @@ -0,0 +1,60 @@ +// 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 NET_THIRD_PARTY_QUIC_TOOLS_QUIC_NAIVE_SERVER_STREAM_H_ +#define NET_THIRD_PARTY_QUIC_TOOLS_QUIC_NAIVE_SERVER_STREAM_H_ + +#include "base/macros.h" +#include "net/third_party/quic/core/http/quic_spdy_server_stream_base.h" +#include "net/third_party/quic/core/quic_packets.h" +#include "net/third_party/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quic/tools/quic_backend_response.h" +#include "net/third_party/quic/tools/quic_simple_server_backend.h" +#include "net/third_party/spdy/core/spdy_framer.h" + +namespace quic { + +// All this does right now is aggregate data, and on fin, send an HTTP +// response. +class QuicNaiveServerStream : public QuicSpdyServerStreamBase, + public QuicSimpleServerBackend::RequestHandler { + public: + QuicNaiveServerStream(QuicStreamId id, + QuicSpdySession* session, + QuicSimpleServerBackend* backend); + QuicNaiveServerStream(const QuicNaiveServerStream&) = delete; + QuicNaiveServerStream& operator=(const QuicNaiveServerStream&) = delete; + ~QuicNaiveServerStream() override; + + void SendErrorResponse(int resp_code); + + // QuicSpdyStream + void OnInitialHeadersComplete(bool fin, + size_t frame_len, + const QuicHeaderList& header_list) override; + void OnTrailingHeadersComplete(bool fin, + size_t frame_len, + const QuicHeaderList& header_list) override; + + // QuicStream implementation called by the sequencer when there is + // data (or a FIN) to be read. + void OnDataAvailable() override; + + virtual void PushResponse(spdy::SpdyHeaderBlock push_request_headers); + + // Implements QuicSimpleServerBackend::RequestHandler callbacks + QuicConnectionId connection_id() const override; + QuicStreamId stream_id() const override; + QuicString peer_host() const override; + void OnResponseBackendComplete( + const QuicBackendResponse* response, + std::list resources) override; + + private: + QuicSimpleServerBackend* backend_; // Not owned. +}; + +} // namespace quic + +#endif // NET_THIRD_PARTY_QUIC_TOOLS_QUIC_NAIVE_SERVER_STREAM_H_ diff --git a/net/third_party/quic/tools/quic_simple_server_backend.h b/net/third_party/quic/tools/quic_simple_server_backend.h index 74a77c10b5..b7168f0c10 100644 --- a/net/third_party/quic/tools/quic_simple_server_backend.h +++ b/net/third_party/quic/tools/quic_simple_server_backend.h @@ -11,6 +11,7 @@ namespace spdy { class SpdyHeaderBlock; } // namespace spdy namespace quic { +class QuicSpdyStream; // This interface implements the functionality to fetch a response // from the backend (such as cache, http-proxy etc) to serve @@ -52,8 +53,12 @@ class QuicSimpleServerBackend { RequestHandler* request_handler) = 0; // Clears the state of the backend instance virtual void CloseBackendResponseStream(RequestHandler* request_handler) = 0; + + virtual void OnReadHeaders(QuicSpdyStream* stream, const QuicHeaderList& header_list) {}; + virtual void OnReadData(QuicSpdyStream* stream, void* data, size_t len) {}; + virtual void OnCloseStream(QuicSpdyStream* stream) {}; }; } // namespace quic -#endif // NET_THIRD_PARTY_QUIC_TOOLS_QUIC_SIMPLE_SERVER_BACKEND_H_ \ No newline at end of file +#endif // NET_THIRD_PARTY_QUIC_TOOLS_QUIC_SIMPLE_SERVER_BACKEND_H_ diff --git a/net/third_party/quic/tools/quic_simple_server_session.cc b/net/third_party/quic/tools/quic_simple_server_session.cc index 4f63c26546..18a600d2ea 100644 --- a/net/third_party/quic/tools/quic_simple_server_session.cc +++ b/net/third_party/quic/tools/quic_simple_server_session.cc @@ -11,6 +11,7 @@ #include "net/third_party/quic/platform/api/quic_logging.h" #include "net/third_party/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quic/tools/quic_simple_server_stream.h" +#include "net/third_party/quic/tools/quic_naive_server_stream.h" namespace quic { @@ -93,20 +94,13 @@ QuicSpdyStream* QuicSimpleServerSession::CreateIncomingDynamicStream( } QuicSpdyStream* stream = - new QuicSimpleServerStream(id, this, quic_simple_server_backend_); + new QuicNaiveServerStream(id, this, quic_simple_server_backend_); ActivateStream(QuicWrapUnique(stream)); return stream; } QuicSimpleServerStream* QuicSimpleServerSession::CreateOutgoingDynamicStream() { - if (!ShouldCreateOutgoingDynamicStream()) { - return nullptr; - } - - QuicSimpleServerStream* stream = new QuicSimpleServerStream( - GetNextOutgoingStreamId(), this, quic_simple_server_backend_); - ActivateStream(QuicWrapUnique(stream)); - return stream; + return nullptr; } void QuicSimpleServerSession::CloseStreamInner(QuicStreamId stream_id, diff --git a/net/tools/naive/naive_proxy_bin.cc b/net/tools/naive/naive_proxy_bin.cc index 690bdd7dd5..898ce98eb8 100644 --- a/net/tools/naive/naive_proxy_bin.cc +++ b/net/tools/naive/naive_proxy_bin.cc @@ -72,15 +72,18 @@ struct Params { std::string listen_addr; int listen_port; net::NaiveProxy::Protocol protocol; + bool is_quic; bool use_proxy; std::string proxy_url; - bool is_quic; + bool is_quic_proxy; std::string proxy_user; std::string proxy_pass; std::string host_resolver_rules; logging::LoggingSettings log_settings; base::FilePath net_log_path; base::FilePath ssl_key_path; + base::FilePath certificate_file; + base::FilePath key_file; }; std::unique_ptr GetConstants( @@ -117,7 +120,7 @@ std::unique_ptr BuildURLRequestContext( net::ProxyConfig proxy_config; if (params.use_proxy) { std::string proxy_url = params.proxy_url; - if (params.is_quic) { + if (params.is_quic_proxy) { proxy_url = base::StrCat({"quic://", proxy_url.substr(sizeof("https://") - 1)}); } proxy_config.proxy_rules().ParseFromString(proxy_url); @@ -162,11 +165,13 @@ bool ParseCommandLineFlags(Params* params) { "Options:\n" "-h, --help Show this message\n" "--version Print version\n" - "--proto=[socks|http] Protocol to accept (socks)\n" + "--proto=[socks|http|quic] Protocol to accept (socks)\n" "--addr=
Address to listen on (0.0.0.0)\n" "--port= Port to listen on (1080)\n" "--proxy=[https|quic]://:@[:]\n" " Proxy specification.\n" + "--certificate_file=\n" + "--key_file=\n" "--log Log to stderr, otherwise no log\n" "--log-net-log= Save NetLog\n" "--ssl-key-log-file= Save SSL keys for Wireshark\n"; @@ -181,23 +186,22 @@ bool ParseCommandLineFlags(Params* params) { } params->protocol = net::NaiveProxy::kSocks5; + params->is_quic = false; if (line.HasSwitch("proto")) { const auto& proto = line.GetSwitchValueASCII("proto"); if (proto == "socks") { params->protocol = net::NaiveProxy::kSocks5; } else if (proto == "http") { params->protocol = net::NaiveProxy::kHttp; + } else if (proto == "quic") { + params->is_quic = true; } else { LOG(ERROR) << "Invalid --proto"; return false; } } - if (params->protocol == net::NaiveProxy::kSocks5) { - params->listen_addr = "0.0.0.0"; - } else { - params->listen_addr = "127.0.0.1"; - } + params->listen_addr = "0.0.0.0"; if (line.HasSwitch("addr")) { params->listen_addr = line.GetSwitchValueASCII("addr"); } @@ -221,11 +225,11 @@ bool ParseCommandLineFlags(Params* params) { } params->use_proxy = false; - params->is_quic = false; + params->is_quic_proxy = false; std::string proxy_str = line.GetSwitchValueASCII("proxy"); if (base::StartsWith(proxy_str, "quic://", base::CompareCase::SENSITIVE)) { proxy_str = base::StrCat({"https://", proxy_str.substr(sizeof("quic://") - 1)}); - params->is_quic = true; + params->is_quic_proxy = true; } GURL url(proxy_str); if (line.HasSwitch("proxy")) { @@ -274,6 +278,19 @@ bool ParseCommandLineFlags(Params* params) { params->ssl_key_path = line.GetSwitchValuePath("ssl-key-log-file"); } + if (params->is_quic) { + if (!line.HasSwitch("certificate_file")) { + LOG(ERROR) << "Missing --certificate_file"; + return false; + } + if (!line.HasSwitch("key_file")) { + LOG(ERROR) << "Missing --key_file"; + return false; + } + params->certificate_file = line.GetSwitchValuePath("certificate_file"); + params->key_file = line.GetSwitchValuePath("key_file"); + } + return true; } @@ -376,6 +393,32 @@ int main(int argc, char* argv[]) { net::NetLogCaptureMode::Default()); auto context = BuildURLRequestContext(params, &net_log); + auto* session = context->http_transaction_factory()->GetSession(); + + if (params->is_quic) { + auto backend = std::make_unique(session); + quic::QuicConfig config; + auto proof_source = std::make_unique(); + CHECK(proof_source->Initialize(params.certificate_file, params.key_file, base::FilePath())); + net::QuicSimpleServer server( + std::move(proof_source), + config, quic::QuicCryptoServerConfig::ConfigOptions(), + quic::AllSupportedVersions(), backend.get()); + + net::IPAddress ip; + int result = net::ERR_ADDRESS_INVALID; + if (ip.AssignFromIPLiteral(params.listen_addr)) { + result = server.Listen(net::IPEndPoint(ip, params.listen_port)); + } + if (result != net::OK) { + LOG(ERROR) << "Failed to listen: " << result; + return EXIT_FAILURE; + } + + base::RunLoop().Run(); + + return EXIT_SUCCESS; + } auto listen_socket = std::make_unique(&net_log, net::NetLogSource()); @@ -389,7 +432,7 @@ int main(int argc, char* argv[]) { net::NaiveProxy naive_proxy( std::move(listen_socket), params.protocol, params.use_proxy, - context->http_transaction_factory()->GetSession(), kTrafficAnnotation); + session, kTrafficAnnotation); base::RunLoop().Run(); diff --git a/net/tools/quic/quic_naive_proxy_backend.cc b/net/tools/quic/quic_naive_proxy_backend.cc new file mode 100644 index 0000000000..44ad05b0ec --- /dev/null +++ b/net/tools/quic/quic_naive_proxy_backend.cc @@ -0,0 +1,59 @@ +// Copyright 2018 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 "net/tools/quic/quic_naive_proxy_backend.h" + +namespace net { + +QuicNaiveProxyBackend::QuicNaiveProxyBackend() {} + +QuicNaiveProxyBackend::~QuicNaiveProxyBackend() {} + +bool QuicNaiveProxyBackend::InitializeBackend(const std::string& backend_url) { + return true; +} + +bool QuicNaiveProxyBackend::IsBackendInitialized() const { + return true; +} + +void QuicNaiveProxyBackend::FetchResponseFromBackend( + const spdy::SpdyHeaderBlock& request_headers, + const std::string& incoming_body, + QuicSimpleServerBackend::RequestHandler* quic_server_stream) { +} + +void QuicNaiveProxyBackend::CloseBackendResponseStream( + QuicSimpleServerBackend::RequestHandler* quic_server_stream) { +} + +void QuicNaiveProxyBackend::OnReadHeaders(quic::QuicSpdyStream* stream, + const quic::QuicHeaderList& header_list) { + for (const auto& p : header_list) { + const auto& name = p.first; + const auto& value = p.second; + if (name == ":method" && value != "CONNECT") { + spdy::SpdyHeaderBlock headers; + headers[":status"] = "405"; + stream->WriteHeaders(std::move(headers), /*fin=*/true, nullptr); + return; + } + if (name == ":authority") { + } + } + + LOG(INFO) << "OnReadHeaders " << stream; +} + +void QuicNaiveProxyBackend::OnReadData(quic::QuicSpdyStream* stream, + void* data, size_t len) { + LOG(INFO) << "OnReadData " << stream; +} + +void QuicNaiveProxyBackend::OnCloseStream(quic::QuicSpdyStream* stream) { + LOG(INFO) << "OnCloseStream " << stream; +} + +} // namespace net diff --git a/net/tools/quic/quic_naive_proxy_backend.h b/net/tools/quic/quic_naive_proxy_backend.h new file mode 100644 index 0000000000..b505928c00 --- /dev/null +++ b/net/tools/quic/quic_naive_proxy_backend.h @@ -0,0 +1,52 @@ +// Copyright 2018 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_TOOLS_QUIC_QUIC_NAIVE_PROXY_BACKEND_H_ +#define NET_TOOLS_QUIC_QUIC_NAIVE_PROXY_BACKEND_H_ + +#include + +#include "base/callback.h" +#include "base/macros.h" +#include "net/third_party/quic/tools/quic_simple_server_backend.h" + +namespace quic { +class QuicSpdyStream; +} // namespace quic + +namespace net { + +// Manages the context to proxy HTTP requests to the backend server +// Owns instance of net::URLRequestContext. +class QuicNaiveProxyBackend : public quic::QuicSimpleServerBackend { + public: + explicit QuicNaiveProxyBackend(); + ~QuicNaiveProxyBackend() override; + + // Implements the functions for interface quic::QuicSimpleServerBackend + bool InitializeBackend(const std::string& backend_url) override; + bool IsBackendInitialized() const override; + void FetchResponseFromBackend( + const spdy::SpdyHeaderBlock& request_headers, + const std::string& incoming_body, + quic::QuicSimpleServerBackend::RequestHandler* quic_stream) override; + void CloseBackendResponseStream( + quic::QuicSimpleServerBackend::RequestHandler* quic_stream) override; + + void OnReadHeaders(quic::QuicSpdyStream* stream, + const quic::QuicHeaderList& header_list) override; + void OnReadData(quic::QuicSpdyStream* stream, + void* data, size_t len) override; + void OnCloseStream(quic::QuicSpdyStream* stream) override; + + private: + // Maps quic streams in the frontend to the corresponding http streams + // managed by |this| + //ProxyBackendStreamMap backend_stream_map_; + + DISALLOW_COPY_AND_ASSIGN(QuicNaiveProxyBackend); +}; +} // namespace net + +#endif // NET_TOOLS_QUIC_QUIC_NAIVE_PROXY_BACKEND_H_ diff --git a/net/tools/quic/quic_simple_server_bin.cc b/net/tools/quic/quic_simple_server_bin.cc index 55f7386570..a7cbed12ac 100644 --- a/net/tools/quic/quic_simple_server_bin.cc +++ b/net/tools/quic/quic_simple_server_bin.cc @@ -20,7 +20,7 @@ #include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/tools/quic_memory_cache_backend.h" #include "net/third_party/quic/tools/quic_simple_server_backend.h" -#include "net/tools/quic/quic_http_proxy_backend.h" +#include "net/tools/quic/quic_naive_proxy_backend.h" #include "net/tools/quic/quic_simple_server.h" // The port the quic server will listen on. @@ -104,7 +104,7 @@ int main(int argc, char* argv[]) { FLAGS_quic_proxy_backend_url = line->GetSwitchValueASCII("quic_proxy_backend_url"); quic_simple_server_backend = - std::make_unique(); + std::make_unique(); if (quic_simple_server_backend->InitializeBackend( FLAGS_quic_proxy_backend_url) != true) { LOG(ERROR) << "--quic_proxy_backend_url "