Commit 4380217c authored by Rajesh Mahindra's avatar Rajesh Mahindra Committed by Commit Bot

Enabling quic_server to act as a HTTP proxy serving QUIC clients.

To add the functionality of a reverse proxy to the QUIC server, 2 classes
were added:
1. QuicHttpProxyBackend: Implements the interface: QuicSimpleServerBackend
to fetch the response from a backend server. Creates a proxy thread and manages an instance of
   net::URLRequestContext within that thread to make HTTP calls to a backend
   server.
2. QuicHttpProxyBackendStream: Created on a per-stream basis, manages an
   instance of the class net::URLRequest to make a single HTTP call to the
   backend server using the context created by QuicHttpProxyBackend.

Run As a Proxy
To run the quic_server as a reverse proxy, run
with --mode=proxy. The param --quic_proxy_backend_url specifies the
backend server from which the response is fetched. For instance,

./out/Default/quic_server \
  --certificate_file=net/tools/quic/certs/out/leaf_cert.pem \
  --key_file=net/tools/quic/certs/out/leaf_cert.pkcs8 \
  --mode=proxy \
  --quic_proxy_backend_url=http://localhost

R=rch@chromium.org, zhongyi@chromium.org

Change-Id: I79b7d66eb6bba9628d99181def004c0a5ea2e214
Reviewed-on: https://chromium-review.googlesource.com/1128323
Commit-Queue: Ryan Hamilton <rch@chromium.org>
Reviewed-by: default avatarRyan Hamilton <rch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577650}
parent c51b5582
...@@ -3232,6 +3232,10 @@ source_set("simple_quic_tools") { ...@@ -3232,6 +3232,10 @@ source_set("simple_quic_tools") {
"third_party/quic/tools/quic_spdy_client_base.h", "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.cc",
"tools/quic/quic_client_message_loop_network_helper.h", "tools/quic/quic_client_message_loop_network_helper.h",
"tools/quic/quic_http_proxy_backend.cc",
"tools/quic/quic_http_proxy_backend.h",
"tools/quic/quic_http_proxy_backend_stream.cc",
"tools/quic/quic_http_proxy_backend_stream.h",
"tools/quic/quic_simple_client.cc", "tools/quic/quic_simple_client.cc",
"tools/quic/quic_simple_client.h", "tools/quic/quic_simple_client.h",
"tools/quic/quic_simple_per_connection_packet_writer.cc", "tools/quic/quic_simple_per_connection_packet_writer.cc",
...@@ -5283,6 +5287,8 @@ test("net_unittests") { ...@@ -5283,6 +5287,8 @@ test("net_unittests") {
"third_party/quic/tools/quic_server_test.cc", "third_party/quic/tools/quic_server_test.cc",
"third_party/quic/tools/quic_simple_server_session_test.cc", "third_party/quic/tools/quic_simple_server_session_test.cc",
"third_party/quic/tools/quic_simple_server_stream_test.cc", "third_party/quic/tools/quic_simple_server_stream_test.cc",
"tools/quic/quic_http_proxy_backend_stream_test.cc",
"tools/quic/quic_http_proxy_backend_test.cc",
"tools/quic/quic_simple_server_session_helper_test.cc", "tools/quic/quic_simple_server_session_helper_test.cc",
"tools/quic/quic_simple_server_test.cc", "tools/quic/quic_simple_server_test.cc",
] ]
......
// 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 <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <iostream>
#include <limits>
#include <map>
#include <set>
#include <utility>
#include <vector>
#include "build/build_config.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/base/url_util.h"
#include "net/cert/cert_verifier.h"
#include "net/cookies/cookie_monster.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/proxy_resolution/proxy_config_service_fixed.h"
#include "net/ssl/channel_id_service.h"
#include "net/tools/quic/quic_http_proxy_backend.h"
#include "net/tools/quic/quic_http_proxy_backend_stream.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_builder.h"
#include "net/url_request/url_request_interceptor.h"
namespace net {
QuicHttpProxyBackend::QuicHttpProxyBackend()
: context_(nullptr), thread_initialized_(false), proxy_thread_(nullptr) {}
QuicHttpProxyBackend::~QuicHttpProxyBackend() {
backend_stream_map_.clear();
thread_initialized_ = false;
proxy_task_runner_->DeleteSoon(FROM_HERE, context_.release());
if (proxy_thread_ != nullptr) {
LOG(INFO) << "QUIC Proxy thread: " << proxy_thread_->thread_name()
<< " has stopped !";
proxy_thread_.reset();
}
}
bool QuicHttpProxyBackend::InitializeBackend(const std::string& backend_url) {
if (!ValidateBackendUrl(backend_url)) {
return false;
}
if (proxy_thread_ == nullptr) {
proxy_thread_ = std::make_unique<base::Thread>("quic proxy thread");
base::Thread::Options options;
options.message_loop_type = base::MessageLoop::TYPE_IO;
bool result = proxy_thread_->StartWithOptions(options);
proxy_task_runner_ = proxy_thread_->task_runner();
CHECK(result);
}
thread_initialized_ = true;
return true;
}
bool QuicHttpProxyBackend::ValidateBackendUrl(const std::string& backend_url) {
backend_url_ = GURL(backend_url);
// Only Http(s) backend supported
if (!backend_url_.is_valid() || !backend_url_.SchemeIsHTTPOrHTTPS()) {
LOG(ERROR) << "QUIC Proxy Backend URL '" << backend_url
<< "' is not valid !";
return false;
}
LOG(INFO)
<< "Successfully configured to run as a QUIC Proxy with Backend URL: "
<< backend_url_.spec();
return true;
}
bool QuicHttpProxyBackend::IsBackendInitialized() const {
return thread_initialized_;
}
void QuicHttpProxyBackend::FetchResponseFromBackend(
const spdy::SpdyHeaderBlock& request_headers,
const std::string& incoming_body,
QuicSimpleServerBackend::RequestHandler* quic_server_stream) {
QuicHttpProxyBackendStream* proxy_backend_stream =
InitializeQuicProxyBackendStream(quic_server_stream);
LOG(INFO) << " Forwarding QUIC request to the Backend Thread Asynchronously.";
if (proxy_backend_stream == nullptr ||
proxy_backend_stream->SendRequestToBackend(&request_headers,
incoming_body) != true) {
std::list<quic::QuicBackendResponse::ServerPushInfo> empty_resources;
quic_server_stream->OnResponseBackendComplete(nullptr, empty_resources);
}
}
QuicHttpProxyBackendStream*
QuicHttpProxyBackend::InitializeQuicProxyBackendStream(
QuicSimpleServerBackend::RequestHandler* quic_server_stream) {
if (!thread_initialized_) {
return nullptr;
}
QuicHttpProxyBackendStream* proxy_backend_stream =
new QuicHttpProxyBackendStream(this);
proxy_backend_stream->set_delegate(quic_server_stream);
proxy_backend_stream->Initialize(quic_server_stream->connection_id(),
quic_server_stream->stream_id(),
quic_server_stream->peer_host());
{
// Aquire write lock for this scope
base::AutoLock lock(backend_stream_mutex_);
auto inserted = backend_stream_map_.insert(std::make_pair(
quic_server_stream, base::WrapUnique(proxy_backend_stream)));
DCHECK(inserted.second);
}
return proxy_backend_stream;
}
void QuicHttpProxyBackend::CloseBackendResponseStream(
QuicSimpleServerBackend::RequestHandler* quic_server_stream) {
// Clean close of the backend stream handler
if (quic_server_stream == nullptr) {
return;
}
// Cleanup the handler on the proxy thread, since it owns the url_request
if (!proxy_task_runner_->BelongsToCurrentThread()) {
proxy_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&QuicHttpProxyBackend::CloseBackendResponseStream,
base::Unretained(this), quic_server_stream));
} else {
// Aquire write lock for this scope and cancel if the request is still
// pending
base::AutoLock lock(backend_stream_mutex_);
QuicHttpProxyBackendStream* proxy_backend_stream = nullptr;
ProxyBackendStreamMap::iterator it =
backend_stream_map_.find(quic_server_stream);
if (it != backend_stream_map_.end()) {
proxy_backend_stream = it->second.get();
proxy_backend_stream->CancelRequest();
proxy_backend_stream->reset_delegate();
LOG(INFO) << " Quic Proxy cleaned-up backend handler on context/main "
"thread for quic_conn_id: "
<< proxy_backend_stream->quic_connection_id()
<< " quic_stream_id: "
<< proxy_backend_stream->quic_stream_id();
size_t erased = backend_stream_map_.erase(quic_server_stream);
DCHECK_EQ(1u, erased);
}
}
}
void QuicHttpProxyBackend::InitializeURLRequestContext() {
DCHECK(context_ == nullptr);
net::URLRequestContextBuilder context_builder;
// Quic reverse proxy does not cache HTTP objects
context_builder.DisableHttpCache();
// Enable HTTP2, but disable QUIC on the backend
context_builder.SetSpdyAndQuicEnabled(true /* http2 */, false /* quic */);
#if defined(OS_LINUX)
// On Linux, use a fixed ProxyConfigService, since the default one
// depends on glib.
context_builder.set_proxy_config_service(
std::make_unique<ProxyConfigServiceFixed>(
ProxyConfigWithAnnotation::CreateDirect()));
#endif
// Disable net::CookieStore and net::ChannelIDService.
context_builder.SetCookieAndChannelIdStores(nullptr, nullptr);
context_ = context_builder.Build();
}
net::URLRequestContext* QuicHttpProxyBackend::GetURLRequestContext() {
// Access to URLRequestContext is only available on Backend Thread
DCHECK(proxy_task_runner_->BelongsToCurrentThread());
if (context_ == nullptr) {
InitializeURLRequestContext();
}
return context_.get();
}
scoped_refptr<base::SingleThreadTaskRunner>
QuicHttpProxyBackend::GetProxyTaskRunner() const {
return proxy_task_runner_;
}
} // namespace net
// 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.
//
// The proxy functionality is implemented as a separate thread namely
// “quic proxy thread”, managed by an instance of the QuicHttpProxyBackend
// class. The QuicHttpProxyBackend instance also manages an instance of the
// class net::URLRequestContext, that manages a single context for all the
// HTTP calls made to the backend server. Finally, the QuicHttpProxyBackend
// instance owns (creates/ destroys) the instances of QuicHttpProxyBackendStream
// to avoid orphan pointers of QuicHttpProxyBackendStream when the corresponding
// QUIC connection is destroyed on the main thread due to several reasons. The
// QUIC connection management and protocol parsing is performed by the main/quic
// thread, in the same way as the toy QUIC server.
//
// quic_http_proxy_backend_stream.h has a description of threads, the flow
// of packets in QUIC proxy in the forward and reverse directions.
#ifndef NET_TOOLS_QUIC_QUIC_HTTP_PROXY_BACKEND_H_
#define NET_TOOLS_QUIC_QUIC_HTTP_PROXY_BACKEND_H_
#include <stdint.h>
#include <memory>
#include <queue>
#include "base/base64.h"
#include "base/callback.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "net/third_party/quic/tools/quic_simple_server_backend.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_builder.h"
#include "url/gurl.h"
namespace base {
class SingleThreadTaskRunner;
} // namespace base
namespace quic {
class QuicSimpleServerBackend;
} // namespace quic
namespace net {
class QuicHttpProxyBackendStream;
// Manages the context to proxy HTTP requests to the backend server
// Owns instance of net::URLRequestContext.
class QuicHttpProxyBackend : public quic::QuicSimpleServerBackend {
public:
explicit QuicHttpProxyBackend();
~QuicHttpProxyBackend() override;
// Must be called from the backend thread of the quic proxy
net::URLRequestContext* GetURLRequestContext();
scoped_refptr<base::SingleThreadTaskRunner> GetProxyTaskRunner() const;
using ProxyBackendStreamMap =
std::unordered_map<quic::QuicSimpleServerBackend::RequestHandler*,
std::unique_ptr<QuicHttpProxyBackendStream>>;
const ProxyBackendStreamMap* proxy_backend_streams_map() const {
return &backend_stream_map_;
}
GURL backend_url() const { return backend_url_; }
// 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;
private:
// Maps quic streams in the frontend to the corresponding http streams
// managed by |this|
ProxyBackendStreamMap backend_stream_map_;
bool ValidateBackendUrl(const std::string& backend_url);
void InitializeURLRequestContext();
QuicHttpProxyBackendStream* InitializeQuicProxyBackendStream(
quic::QuicSimpleServerBackend::RequestHandler* quic_server_stream);
// URLRequestContext to make URL requests to the backend
std::unique_ptr<net::URLRequestContext> context_; // owned by this
bool thread_initialized_;
// <scheme://hostname:port/ for the backend HTTP server
GURL backend_url_;
// Backend thread is owned by |this|
std::unique_ptr<base::Thread> proxy_thread_;
scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_;
// Protects against concurrent access from quic (main) and proxy
// threads for adding and clearing a backend request handler
base::Lock backend_stream_mutex_;
DISALLOW_COPY_AND_ASSIGN(QuicHttpProxyBackend);
};
} // namespace net
#endif // NET_TOOLS_QUIC_QUIC_HTTP_PROXY_BACKEND_H_
\ No newline at end of file
This diff is collapsed.
// 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.
//
// The QuicHttpProxyBackendStream instance manages an instance of
// net::URLRequest to initiate a single HTTP call to the backend. It also
// implements the callbacks of net::URLRequest to receive the response. It is
// instantiated by a delegate (for instance, the QuicSimpleServerStream class)
// when a complete HTTP request is received within a single QUIC stream.
// However, the instance is owned by QuicHttpProxyBackend, that destroys it
// safely on the quic proxy thread. Upon receiving a response (success or
// failed), the response headers and body are posted back to the main thread. In
// the main thread, the QuicHttpProxyBackendStream instance calls the interface,
// that is implemented by the delegate to return the response headers and body.
// In addition to managing the HTTP request/response to the backend, it
// translates the quic_spdy headers to/from HTTP headers for the backend.
//
#ifndef NET_TOOLS_QUIC_QUIC_HTTP_PROXY_BACKEND_STREAM_H_
#define NET_TOOLS_QUIC_QUIC_HTTP_PROXY_BACKEND_STREAM_H_
#include <memory>
#include "base/bind.h"
#include "base/callback.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
#include "net/base/request_priority.h"
#include "net/base/upload_data_stream.h"
#include "net/url_request/url_request.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_header_block.h"
#include "net/tools/quic/quic_http_proxy_backend.h"
namespace base {
class SequencedTaskRunner;
class SingleThreadTaskRunner;
} // namespace base
namespace quic {
class QuicBackendResponse;
class QuicSimpleServerBackend;
} // namespace quic
namespace net {
class HttpRequestHeaders;
class SSLCertRequestInfo;
class SSLInfo;
class UploadDataStream;
class QuicHttpProxyBackend;
// An adapter for making HTTP requests to net::URLRequest.
class QuicHttpProxyBackendStream : public net::URLRequest::Delegate {
public:
QuicHttpProxyBackendStream(QuicHttpProxyBackend* context);
~QuicHttpProxyBackendStream() override;
static const std::set<std::string> kHopHeaders;
static const int kBufferSize;
static const int kProxyHttpBackendError;
static const std::string kDefaultQuicPeerIP;
// Set callbacks to be called from this to the main (quic) thread.
// A |delegate| may be NULL.
// If set_delegate() is called multiple times, only the last delegate will be
// used.
void set_delegate(quic::QuicSimpleServerBackend::RequestHandler* delegate);
void reset_delegate() { delegate_ = nullptr; }
void Initialize(quic::QuicConnectionId quic_connection_id,
quic::QuicStreamId quic_stream_id,
std::string quic_peer_ip);
virtual bool SendRequestToBackend(
const spdy::SpdyHeaderBlock* incoming_request_headers,
const std::string& incoming_body);
quic::QuicConnectionId quic_connection_id() const {
return quic_connection_id_;
}
quic::QuicStreamId quic_stream_id() const { return quic_stream_id_; }
const net::HttpRequestHeaders& request_headers() const {
return request_headers_;
}
// Releases all resources for the request and deletes the object itself.
virtual void CancelRequest();
// net::URLRequest::Delegate implementations:
void OnReceivedRedirect(net::URLRequest* request,
const net::RedirectInfo& redirect_info,
bool* defer_redirect) override;
void OnCertificateRequested(
net::URLRequest* request,
net::SSLCertRequestInfo* cert_request_info) override;
void OnSSLCertificateError(net::URLRequest* request,
const net::SSLInfo& ssl_info,
bool fatal) override;
void OnResponseStarted(net::URLRequest* request, int net_error) override;
void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
bool ResponseIsCompleted() const { return response_completed_; }
quic::QuicBackendResponse* GetBackendResponse() const;
private:
void StartOnBackendThread();
void SendRequestOnBackendThread();
void ReadOnceTask();
void OnResponseCompleted();
void CopyHeaders(const spdy::SpdyHeaderBlock* incoming_request_headers);
bool ValidateHttpMethod(std::string method);
bool AddRequestHeader(std::string name, std::string value);
// Adds a request body to the request before it starts.
void SetUpload(std::unique_ptr<net::UploadDataStream> upload);
void SendResponseOnDelegateThread();
void ReleaseRequest();
spdy::SpdyHeaderBlock getAsQuicHeaders(net::HttpResponseHeaders* resp_headers,
int response_code,
uint64_t response_decoded_body_size);
// The quic proxy backend context
QuicHttpProxyBackend* proxy_context_;
// Send back the response from the backend to |delegate_|
quic::QuicSimpleServerBackend::RequestHandler* delegate_;
// Task runner for interacting with the delegate
scoped_refptr<base::SequencedTaskRunner> delegate_task_runner_;
// Task runner for the proxy network operations.
scoped_refptr<base::SingleThreadTaskRunner> quic_proxy_task_runner_;
// The corresponding QUIC conn/client/stream
quic::QuicConnectionId quic_connection_id_;
quic::QuicStreamId quic_stream_id_;
std::string quic_peer_ip_;
// Url, method and spec for making a http request to the Backend
GURL url_;
std::string method_type_;
net::HttpRequestHeaders request_headers_;
std::unique_ptr<net::UploadDataStream> upload_;
std::unique_ptr<net::URLRequest> url_request_;
// Buffers that holds the response body
scoped_refptr<IOBuffer> buf_;
std::string data_received_;
bool response_completed_;
// Response and push resources received from the backend
bool headers_set_;
std::unique_ptr<quic::QuicBackendResponse> quic_response_;
base::WeakPtrFactory<QuicHttpProxyBackendStream> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(QuicHttpProxyBackendStream);
};
} // namespace net
#endif // NET_TOOLS_QUIC_QUIC_HTTP_PROXY_BACKEND_STREAM_H_
\ No newline at end of file
This diff is collapsed.
// 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/files/file_path.h"
#include "base/path_service.h"
#include "base/test/scoped_task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "net/base/url_util.h"
#include "net/third_party/quic/platform/api/quic_test.h"
#include "net/tools/quic/quic_http_proxy_backend.h"
#include "net/tools/quic/quic_http_proxy_backend_stream.h"
namespace net {
namespace test {
class TestQuicServerStream
: public quic::QuicSimpleServerBackend::RequestHandler {
public:
TestQuicServerStream() : did_complete_(false) {}
~TestQuicServerStream() override {}
quic::QuicConnectionId connection_id() const override { return 123; };
quic::QuicStreamId stream_id() const override { return 5; };
std::string peer_host() const override { return "127.0.0.1"; };
void OnResponseBackendComplete(
const quic::QuicBackendResponse* response,
std::list<quic::QuicBackendResponse::ServerPushInfo> resources) override {
EXPECT_FALSE(did_complete_);
did_complete_ = true;
task_runner_->PostTask(FROM_HERE, run_loop_.QuitClosure());
}
base::RunLoop* run_loop() { return &run_loop_; }
private:
bool did_complete_;
base::test::ScopedTaskEnvironment scoped_task_environment;
const scoped_refptr<base::SingleThreadTaskRunner> task_runner_ =
base::ThreadTaskRunnerHandle::Get();
base::RunLoop run_loop_;
};
class QuicHttpProxyBackendTest : public QuicTest {
public:
QuicHttpProxyBackendTest() {
proxy_stream_map_ = http_proxy_.proxy_backend_streams_map();
}
~QuicHttpProxyBackendTest() override {
EXPECT_EQ(true, proxy_stream_map_->empty());
}
void SendRequestOverBackend(TestQuicServerStream* quic_stream) {
quic_proxy_backend_url_ = "http://www.google.com:80";
http_proxy_.InitializeBackend(quic_proxy_backend_url_);
spdy::SpdyHeaderBlock request_headers;
request_headers[":authority"] = "www.example.org";
request_headers[":method"] = "GET";
std::string body = "Test Body";
http_proxy_.FetchResponseFromBackend(request_headers, body, quic_stream);
quic_stream->run_loop()->Run();
}
protected:
std::string quic_proxy_backend_url_;
QuicHttpProxyBackend http_proxy_;
const QuicHttpProxyBackend::ProxyBackendStreamMap* proxy_stream_map_;
};
TEST_F(QuicHttpProxyBackendTest, InitializeQuicHttpProxyBackend) {
// Test incorrect URLs
quic_proxy_backend_url_ = "http://www.google.com:80--";
http_proxy_.InitializeBackend(quic_proxy_backend_url_);
EXPECT_EQ(false, http_proxy_.IsBackendInitialized());
EXPECT_EQ(nullptr, http_proxy_.GetProxyTaskRunner());
quic_proxy_backend_url_ = "http://192.168.239.257:80";
http_proxy_.InitializeBackend(quic_proxy_backend_url_);
EXPECT_EQ(false, http_proxy_.IsBackendInitialized());
EXPECT_EQ(nullptr, http_proxy_.GetProxyTaskRunner());
quic_proxy_backend_url_ = "http://2555.168.239:80";
http_proxy_.InitializeBackend(quic_proxy_backend_url_);
EXPECT_EQ(false, http_proxy_.IsBackendInitialized());
EXPECT_EQ(nullptr, http_proxy_.GetProxyTaskRunner());
quic_proxy_backend_url_ = "http://192.168.239.237:65537";
http_proxy_.InitializeBackend(quic_proxy_backend_url_);
EXPECT_EQ(false, http_proxy_.IsBackendInitialized());
EXPECT_EQ(nullptr, http_proxy_.GetProxyTaskRunner());
quic_proxy_backend_url_ = "ftp://www.google.com:80";
http_proxy_.InitializeBackend(quic_proxy_backend_url_);
EXPECT_EQ(false, http_proxy_.IsBackendInitialized());
EXPECT_EQ(nullptr, http_proxy_.GetProxyTaskRunner());
// Test initialization with correct URL
quic_proxy_backend_url_ = "http://www.google.com:80";
http_proxy_.InitializeBackend(quic_proxy_backend_url_);
EXPECT_NE(nullptr, http_proxy_.GetProxyTaskRunner());
EXPECT_EQ("http://www.google.com/", http_proxy_.backend_url());
EXPECT_EQ(true, http_proxy_.IsBackendInitialized());
}
TEST_F(QuicHttpProxyBackendTest, CheckProxyStreamManager) {
TestQuicServerStream quic_stream;
SendRequestOverBackend(&quic_stream);
QuicHttpProxyBackend::ProxyBackendStreamMap::const_iterator it_find_success =
proxy_stream_map_->find(&quic_stream);
EXPECT_NE(it_find_success, proxy_stream_map_->end());
http_proxy_.CloseBackendResponseStream(&quic_stream);
/*EXPECT_EQ(true, proxy_stream_map_->empty());
QuicHttpProxyBackend::ProxyBackendStreamMap::const_iterator it_find_fail =
proxy_stream_map_->find(&quic_stream);
EXPECT_EQ(it_find_fail, proxy_stream_map_->end());*/
}
TEST_F(QuicHttpProxyBackendTest, CheckIsOnBackendThread) {
quic_proxy_backend_url_ = "http://www.google.com:80";
http_proxy_.InitializeBackend(quic_proxy_backend_url_);
EXPECT_EQ(false, http_proxy_.GetProxyTaskRunner()->BelongsToCurrentThread());
}
TEST_F(QuicHttpProxyBackendTest, CheckGetBackendTaskRunner) {
EXPECT_EQ(nullptr, http_proxy_.GetProxyTaskRunner());
quic_proxy_backend_url_ = "http://www.google.com:80";
http_proxy_.InitializeBackend(quic_proxy_backend_url_);
EXPECT_NE(nullptr, http_proxy_.GetProxyTaskRunner());
}
} // namespace test
} // namespace net
\ No newline at end of file
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include "net/quic/chromium/crypto/proof_source_chromium.h" #include "net/quic/chromium/crypto/proof_source_chromium.h"
#include "net/third_party/quic/core/quic_packets.h" #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_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_simple_server.h" #include "net/tools/quic/quic_simple_server.h"
// The port the quic server will listen on. // The port the quic server will listen on.
...@@ -29,6 +31,9 @@ std::string FLAGS_quic_mode = "cache"; ...@@ -29,6 +31,9 @@ std::string FLAGS_quic_mode = "cache";
// construction to seed the cache. Cache directory can be // construction to seed the cache. Cache directory can be
// generated using `wget -p --save-headers <url>` // generated using `wget -p --save-headers <url>`
std::string FLAGS_quic_response_cache_dir = ""; std::string FLAGS_quic_response_cache_dir = "";
// URL with http/https, IP address or host name and the port number of the
// backend server
std::string FLAGS_quic_proxy_backend_url = "";
std::unique_ptr<quic::ProofSource> CreateProofSource( std::unique_ptr<quic::ProofSource> CreateProofSource(
const base::FilePath& cert_path, const base::FilePath& cert_path,
...@@ -58,20 +63,26 @@ int main(int argc, char* argv[]) { ...@@ -58,20 +63,26 @@ int main(int argc, char* argv[]) {
"Options:\n" "Options:\n"
"-h, --help show this help message and exit\n" "-h, --help show this help message and exit\n"
"--port=<port> specify the port to listen on\n" "--port=<port> specify the port to listen on\n"
"--mode=<cache> Default: cache\n" "--mode=<cache|proxy> Specify mode of operation: Proxy will "
" Specify mode of operation: Cache will " "serve response from\n"
"serve it " " a backend server and Cache will serve it "
"from a cache dir\n" "from a cache dir\n"
"--quic_response_cache_dir=<directory>\n" "--quic_response_cache_dir=<directory>\n"
" The directory containing cached response " " The directory containing cached response "
"data to load\n" "data to load\n"
"--quic_proxy_backend_url=<http/https>://<hostname_ip>:<port_number> \n"
" The URL for the single backend server "
"hostname \n"
" For example, \"http://xyz.com:80\"\n"
"--certificate_file=<file> path to the certificate chain\n" "--certificate_file=<file> path to the certificate chain\n"
"--key_file=<file> path to the pkcs8 private key\n"; "--key_file=<file> path to the pkcs8 private key\n";
std::cout << help_str; std::cout << help_str;
exit(0); exit(0);
} }
quic::QuicMemoryCacheBackend memory_cache_backend; // Serve the HTTP response from backend: memory cache or http proxy
std::unique_ptr<quic::QuicSimpleServerBackend> quic_simple_server_backend;
if (line->HasSwitch("mode")) { if (line->HasSwitch("mode")) {
FLAGS_quic_mode = line->GetSwitchValueASCII("mode"); FLAGS_quic_mode = line->GetSwitchValueASCII("mode");
} }
...@@ -79,13 +90,28 @@ int main(int argc, char* argv[]) { ...@@ -79,13 +90,28 @@ int main(int argc, char* argv[]) {
if (line->HasSwitch("quic_response_cache_dir")) { if (line->HasSwitch("quic_response_cache_dir")) {
FLAGS_quic_response_cache_dir = FLAGS_quic_response_cache_dir =
line->GetSwitchValueASCII("quic_response_cache_dir"); line->GetSwitchValueASCII("quic_response_cache_dir");
quic_simple_server_backend =
std::make_unique<quic::QuicMemoryCacheBackend>();
if (FLAGS_quic_response_cache_dir.empty() || if (FLAGS_quic_response_cache_dir.empty() ||
memory_cache_backend.InitializeBackend( quic_simple_server_backend->InitializeBackend(
FLAGS_quic_response_cache_dir) != true) { FLAGS_quic_response_cache_dir) != true) {
LOG(ERROR) << "--quic_response_cache_dir is not valid !"; LOG(ERROR) << "--quic_response_cache_dir is not valid !";
return 1; return 1;
} }
} }
} else if (FLAGS_quic_mode.compare("proxy") == 0) {
if (line->HasSwitch("quic_proxy_backend_url")) {
FLAGS_quic_proxy_backend_url =
line->GetSwitchValueASCII("quic_proxy_backend_url");
quic_simple_server_backend =
std::make_unique<net::QuicHttpProxyBackend>();
if (quic_simple_server_backend->InitializeBackend(
FLAGS_quic_proxy_backend_url) != true) {
LOG(ERROR) << "--quic_proxy_backend_url "
<< FLAGS_quic_proxy_backend_url << " is not valid !";
return 1;
}
}
} else { } else {
LOG(ERROR) << "unknown --mode. cache is a valid mode of operation"; LOG(ERROR) << "unknown --mode. cache is a valid mode of operation";
return 1; return 1;
...@@ -115,7 +141,7 @@ int main(int argc, char* argv[]) { ...@@ -115,7 +141,7 @@ int main(int argc, char* argv[]) {
CreateProofSource(line->GetSwitchValuePath("certificate_file"), CreateProofSource(line->GetSwitchValuePath("certificate_file"),
line->GetSwitchValuePath("key_file")), line->GetSwitchValuePath("key_file")),
config, quic::QuicCryptoServerConfig::ConfigOptions(), config, quic::QuicCryptoServerConfig::ConfigOptions(),
quic::AllSupportedVersions(), &memory_cache_backend); quic::AllSupportedVersions(), quic_simple_server_backend.get());
int rc = server.Listen(net::IPEndPoint(ip, FLAGS_port)); int rc = server.Listen(net::IPEndPoint(ip, FLAGS_port));
if (rc < 0) { if (rc < 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment