summaryrefslogtreecommitdiff
path: root/chromium/net/tools
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-10-24 11:30:15 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-10-30 12:56:19 +0000
commit6036726eb981b6c4b42047513b9d3f4ac865daac (patch)
tree673593e70678e7789766d1f732eb51f613a2703b /chromium/net/tools
parent466052c4e7c052268fd931888cd58961da94c586 (diff)
downloadqtwebengine-chromium-6036726eb981b6c4b42047513b9d3f4ac865daac.tar.gz
BASELINE: Update Chromium to 70.0.3538.78
Change-Id: Ie634710bf039e26c1957f4ae45e101bd4c434ae7 Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/net/tools')
-rw-r--r--chromium/net/tools/cachetool/cachetool.cc16
-rw-r--r--chromium/net/tools/cert_verify_tool/cert_verify_tool.cc51
-rw-r--r--chromium/net/tools/content_decoder_tool/content_decoder_tool.cc3
-rw-r--r--chromium/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc23
-rw-r--r--chromium/net/tools/gdig/file_net_log.cc50
-rw-r--r--chromium/net/tools/gdig/file_net_log.h36
-rw-r--r--chromium/net/tools/gdig/gdig.cc523
-rw-r--r--chromium/net/tools/quic/quic_client_message_loop_network_helper.cc10
-rw-r--r--chromium/net/tools/quic/quic_client_message_loop_network_helper.h4
-rw-r--r--chromium/net/tools/quic/quic_http_proxy_backend.cc191
-rw-r--r--chromium/net/tools/quic/quic_http_proxy_backend.h110
-rw-r--r--chromium/net/tools/quic/quic_http_proxy_backend_stream.cc401
-rw-r--r--chromium/net/tools/quic/quic_http_proxy_backend_stream.h162
-rw-r--r--chromium/net/tools/quic/quic_http_proxy_backend_stream_test.cc482
-rw-r--r--chromium/net/tools/quic/quic_http_proxy_backend_test.cc139
-rw-r--r--chromium/net/tools/quic/quic_simple_client.cc10
-rw-r--r--chromium/net/tools/quic/quic_simple_client.h4
-rw-r--r--chromium/net/tools/quic/quic_simple_client_bin.cc8
-rw-r--r--chromium/net/tools/quic/quic_simple_server.cc3
-rw-r--r--chromium/net/tools/quic/quic_simple_server.h4
-rw-r--r--chromium/net/tools/quic/quic_simple_server_bin.cc42
-rw-r--r--chromium/net/tools/quic/quic_simple_server_packet_writer.cc4
-rw-r--r--chromium/net/tools/quic/quic_simple_server_session_helper.h2
-rw-r--r--chromium/net/tools/quic/quic_simple_server_test.cc1
-rw-r--r--chromium/net/tools/stress_cache/stress_cache.cc2
-rwxr-xr-xchromium/net/tools/testserver/testserver.py63
26 files changed, 1652 insertions, 692 deletions
diff --git a/chromium/net/tools/cachetool/cachetool.cc b/chromium/net/tools/cachetool/cachetool.cc
index 3a6468f0138..1b94ba844b9 100644
--- a/chromium/net/tools/cachetool/cachetool.cc
+++ b/chromium/net/tools/cachetool/cachetool.cc
@@ -18,7 +18,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
-#include "base/task_scheduler/task_scheduler.h"
+#include "base/task/task_scheduler/task_scheduler.h"
#include "net/base/io_buffer.h"
#include "net/base/test_completion_callback.h"
#include "net/disk_cache/disk_cache.h"
@@ -322,7 +322,8 @@ bool GetResponseInfoForEntry(disk_cache::Entry* entry,
int size = entry->GetDataSize(kResponseInfoIndex);
if (size == 0)
return false;
- scoped_refptr<net::IOBuffer> buffer = new net::IOBufferWithSize(size);
+ scoped_refptr<net::IOBuffer> buffer =
+ base::MakeRefCounted<net::IOBufferWithSize>(size);
net::TestCompletionCallback cb;
int bytes_read = 0;
@@ -357,7 +358,7 @@ std::string GetMD5ForResponseBody(disk_cache::Entry* entry) {
const int kInitBufferSize = 80 * 1024;
scoped_refptr<net::IOBuffer> buffer =
- new net::IOBufferWithSize(kInitBufferSize);
+ base::MakeRefCounted<net::IOBufferWithSize>(kInitBufferSize);
net::TestCompletionCallback cb;
base::MD5Context ctx;
@@ -482,7 +483,8 @@ scoped_refptr<net::GrowableIOBuffer> GetStreamForKeyBuffer(
}
const int kInitBufferSize = 8192;
- scoped_refptr<net::GrowableIOBuffer> buffer(new net::GrowableIOBuffer());
+ scoped_refptr<net::GrowableIOBuffer> buffer =
+ base::MakeRefCounted<net::GrowableIOBuffer>();
buffer->SetCapacity(kInitBufferSize);
while (true) {
rv = cache_entry->ReadData(index, buffer->offset(), buffer.get(),
@@ -555,7 +557,8 @@ void UpdateRawResponseHeaders(CommandMarshal* command_marshal) {
std::cerr << "WARNING: Truncated HTTP response." << std::endl;
response_info.headers = new net::HttpResponseHeaders(raw_headers);
- scoped_refptr<net::PickledIOBuffer> data(new net::PickledIOBuffer());
+ scoped_refptr<net::PickledIOBuffer> data =
+ base::MakeRefCounted<net::PickledIOBuffer>();
response_info.Persist(data->pickle(), false, false);
data->Done();
Entry* cache_entry;
@@ -585,7 +588,8 @@ void DeleteStreamForKey(CommandMarshal* command_marshal) {
if (cb.GetResult(rv) != net::OK)
return command_marshal->ReturnFailure("Couldn't find key's entry.");
- scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer(""));
+ scoped_refptr<net::StringIOBuffer> buffer =
+ base::MakeRefCounted<net::StringIOBuffer>("");
rv = cache_entry->WriteData(index, 0, buffer.get(), 0, cb.callback(), true);
if (cb.GetResult(rv) != net::OK)
return command_marshal->ReturnFailure("Couldn't delete key stream.");
diff --git a/chromium/net/tools/cert_verify_tool/cert_verify_tool.cc b/chromium/net/tools/cert_verify_tool/cert_verify_tool.cc
index 3b3904d44a1..14c39b02a7d 100644
--- a/chromium/net/tools/cert_verify_tool/cert_verify_tool.cc
+++ b/chromium/net/tools/cert_verify_tool/cert_verify_tool.cc
@@ -9,8 +9,9 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "base/strings/string_split.h"
#include "base/synchronization/waitable_event.h"
-#include "base/task_scheduler/task_scheduler.h"
+#include "base/task/task_scheduler/task_scheduler.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -158,6 +159,25 @@ class CertVerifyImplUsingPathBuilder : public CertVerifyImpl {
}
};
+// Creates an subclass of CertVerifyImpl based on its name, or returns nullptr.
+std::unique_ptr<CertVerifyImpl> CreateCertVerifyImplFromName(
+ base::StringPiece impl_name) {
+ if (impl_name == "platform")
+ return std::make_unique<CertVerifyImplUsingProc>(
+ "CertVerifyProc (default)", net::CertVerifyProc::CreateDefault());
+
+ if (impl_name == "builtin") {
+ return std::make_unique<CertVerifyImplUsingProc>(
+ "CertVerifyProcBuiltin", net::CreateCertVerifyProcBuiltin());
+ }
+
+ if (impl_name == "pathbuilder")
+ return std::make_unique<CertVerifyImplUsingPathBuilder>();
+
+ std::cerr << "WARNING: Unrecognized impl: " << impl_name << "\n";
+ return nullptr;
+}
+
const char kUsage[] =
" [flags] <target/chain>\n"
"\n"
@@ -180,6 +200,12 @@ const char kUsage[] =
" <certs path> is a file containing certificates [1] for use when\n"
" path building is looking for intermediates.\n"
"\n"
+ " --impls=<ordered list of implementations>\n"
+ " Ordered list of the verifier implementations to run. If omitted,\n"
+ " will default to: \"platform,builtin,pathbuilder\".\n"
+ " Changing this can lead to different results in cases where the\n"
+ " platform verifier affects global caches (as in the case of NSS).\n"
+ "\n"
" --trust-last-cert\n"
" Removes the final intermediate from the chain and instead adds it\n"
" as a root. This is useful when providing a <target/chain>\n"
@@ -318,16 +344,25 @@ int main(int argc, char** argv) {
&initialization_complete_event));
initialization_complete_event.Wait();
- // Sequentially run each of the certificate verifier implementations.
std::vector<std::unique_ptr<CertVerifyImpl>> impls;
- impls.push_back(
- std::unique_ptr<CertVerifyImplUsingProc>(new CertVerifyImplUsingProc(
- "CertVerifyProc (default)", net::CertVerifyProc::CreateDefault())));
- impls.push_back(std::make_unique<CertVerifyImplUsingProc>(
- "CertVerifyProcBuiltin", net::CreateCertVerifyProcBuiltin()));
- impls.push_back(std::make_unique<CertVerifyImplUsingPathBuilder>());
+ // Parse the ordered list of CertVerifyImpl passed via command line flags into
+ // |impls|.
+ std::string impls_str = command_line.GetSwitchValueASCII("impls");
+ if (impls_str.empty())
+ impls_str = "platform,builtin,pathbuilder"; // Default value.
+
+ std::vector<std::string> impl_names = base::SplitString(
+ impls_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+ for (const std::string& impl_name : impl_names) {
+ auto verify_impl = CreateCertVerifyImplFromName(impl_name);
+ if (verify_impl)
+ impls.push_back(std::move(verify_impl));
+ }
+ // Sequentially run the chain with each of the selected verifier
+ // implementations.
bool all_impls_success = true;
for (size_t i = 0; i < impls.size(); ++i) {
diff --git a/chromium/net/tools/content_decoder_tool/content_decoder_tool.cc b/chromium/net/tools/content_decoder_tool/content_decoder_tool.cc
index 97e345ba805..94cd33606a4 100644
--- a/chromium/net/tools/content_decoder_tool/content_decoder_tool.cc
+++ b/chromium/net/tools/content_decoder_tool/content_decoder_tool.cc
@@ -91,7 +91,8 @@ bool ContentDecoderToolProcessInput(std::vector<std::string> content_encodings,
LOG(ERROR) << "Couldn't create the decoder.";
return false;
}
- scoped_refptr<IOBuffer> read_buffer = new IOBufferWithSize(kBufferLen);
+ scoped_refptr<IOBuffer> read_buffer =
+ base::MakeRefCounted<IOBufferWithSize>(kBufferLen);
while (true) {
TestCompletionCallback callback;
int bytes_read =
diff --git a/chromium/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc b/chromium/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc
index 0f92b938de6..a27d939b915 100644
--- a/chromium/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc
+++ b/chromium/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc
@@ -22,10 +22,9 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
-#include "base/task_scheduler/task_scheduler.h"
+#include "base/task/task_scheduler/task_scheduler.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/cache_type.h"
-#include "net/base/completion_callback.h"
#include "net/base/net_errors.h"
#include "net/disk_cache/disk_cache.h"
#include "net/disk_cache/simple/simple_backend_impl.h"
@@ -93,15 +92,13 @@ std::unique_ptr<Backend> CreateAndInitBackend(const CacheSpec& spec) {
std::unique_ptr<Backend> backend;
bool succeeded = false;
base::RunLoop run_loop;
- const net::CompletionCallback callback = base::Bind(
- &SetSuccessCodeOnCompletion,
- base::Unretained(&run_loop),
- base::Unretained(&succeeded));
+ net::CompletionOnceCallback callback =
+ base::BindOnce(&SetSuccessCodeOnCompletion, &run_loop, &succeeded);
const int net_error =
CreateCacheBackend(spec.cache_type, spec.backend_type, spec.path, 0,
- false, nullptr, &backend, callback);
+ false, nullptr, &backend, std::move(callback));
if (net_error == net::OK)
- callback.Run(net::OK);
+ SetSuccessCodeOnCompletion(&run_loop, &succeeded, net::OK);
else
run_loop.Run();
if (!succeeded) {
@@ -112,16 +109,14 @@ std::unique_ptr<Backend> CreateAndInitBackend(const CacheSpec& spec) {
// For the simple cache, the index may not be initialized yet.
if (spec.backend_type == net::CACHE_BACKEND_SIMPLE) {
base::RunLoop index_run_loop;
- const net::CompletionCallback index_callback = base::Bind(
- &SetSuccessCodeOnCompletion,
- base::Unretained(&index_run_loop),
- base::Unretained(&succeeded));
+ net::CompletionOnceCallback index_callback = base::BindOnce(
+ &SetSuccessCodeOnCompletion, &index_run_loop, &succeeded);
SimpleBackendImpl* simple_backend =
static_cast<SimpleBackendImpl*>(backend.get());
const int index_net_error =
- simple_backend->index()->ExecuteWhenReady(index_callback);
+ simple_backend->index()->ExecuteWhenReady(std::move(index_callback));
if (index_net_error == net::OK)
- index_callback.Run(net::OK);
+ SetSuccessCodeOnCompletion(&index_run_loop, &succeeded, net::OK);
else
index_run_loop.Run();
if (!succeeded) {
diff --git a/chromium/net/tools/gdig/file_net_log.cc b/chromium/net/tools/gdig/file_net_log.cc
deleted file mode 100644
index c160ae377a1..00000000000
--- a/chromium/net/tools/gdig/file_net_log.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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/tools/gdig/file_net_log.h"
-
-#include <stdio.h>
-
-#include <memory>
-
-#include "base/json/json_string_value_serializer.h"
-#include "base/logging.h"
-#include "base/values.h"
-#include "net/log/net_log_entry.h"
-
-namespace net {
-
-FileNetLogObserver::FileNetLogObserver(FILE* destination)
- : destination_(destination) {
- DCHECK(destination != NULL);
-}
-
-FileNetLogObserver::~FileNetLogObserver() = default;
-
-void FileNetLogObserver::OnAddEntry(const net::NetLogEntry& entry) {
- // Only NetLogWithSources without a NetLog should have an invalid source.
- DCHECK(entry.source().IsValid());
-
- const char* source = NetLog::SourceTypeToString(entry.source().type);
- const char* type = NetLog::EventTypeToString(entry.type());
-
- std::unique_ptr<base::Value> param_value(entry.ParametersToValue());
- std::string params;
- if (param_value.get() != NULL) {
- JSONStringValueSerializer serializer(&params);
- bool ret = serializer.Serialize(*param_value);
- DCHECK(ret);
- }
- base::Time now = base::Time::NowFromSystemTime();
- base::AutoLock lock(lock_);
- if (first_event_time_.is_null()) {
- first_event_time_ = now;
- }
- base::TimeDelta elapsed_time = now - first_event_time_;
- fprintf(destination_ , "%u\t%u\t%s\t%s\t%s\n",
- static_cast<unsigned>(elapsed_time.InMilliseconds()),
- entry.source().id, source, type, params.c_str());
-}
-
-} // namespace net
diff --git a/chromium/net/tools/gdig/file_net_log.h b/chromium/net/tools/gdig/file_net_log.h
deleted file mode 100644
index 4d52f1807a3..00000000000
--- a/chromium/net/tools/gdig/file_net_log.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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_TOOLS_GDIG_FILE_NET_LOG_H_
-#define NET_TOOLS_GDIG_FILE_NET_LOG_H_
-
-#include <string>
-
-#include "base/synchronization/lock.h"
-#include "base/time/time.h"
-#include "net/log/net_log.h"
-
-namespace net {
-
-// FileNetLogObserver is a simple implementation of NetLog::ThreadSafeObserver
-// that prints out all the events received into the stream passed
-// to the constructor.
-class FileNetLogObserver : public NetLog::ThreadSafeObserver {
- public:
- explicit FileNetLogObserver(FILE* destination);
- ~FileNetLogObserver() override;
-
- // NetLog::ThreadSafeObserver implementation:
- void OnAddEntry(const net::NetLogEntry& entry) override;
-
- private:
- FILE* const destination_;
- base::Lock lock_;
-
- base::Time first_event_time_;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_GDIG_FILE_NET_LOG_H_
diff --git a/chromium/net/tools/gdig/gdig.cc b/chromium/net/tools/gdig/gdig.cc
deleted file mode 100644
index 491744b1789..00000000000
--- a/chromium/net/tools/gdig/gdig.cc
+++ /dev/null
@@ -1,523 +0,0 @@
-// 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 <stdio.h>
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/at_exit.h"
-#include "base/bind.h"
-#include "base/cancelable_callback.h"
-#include "base/command_line.h"
-#include "base/files/file_util.h"
-#include "base/location.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_current.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "net/base/address_list.h"
-#include "net/base/ip_address.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_errors.h"
-#include "net/base/url_util.h"
-#include "net/dns/dns_client.h"
-#include "net/dns/dns_config_service.h"
-#include "net/dns/dns_protocol.h"
-#include "net/dns/host_cache.h"
-#include "net/dns/host_resolver_impl.h"
-#include "net/log/net_log.h"
-#include "net/log/net_log_capture_mode.h"
-#include "net/log/net_log_source_type.h"
-#include "net/log/net_log_with_source.h"
-#include "net/tools/gdig/file_net_log.h"
-
-#if defined(OS_MACOSX)
-#include "base/mac/scoped_nsautorelease_pool.h"
-#endif
-
-namespace net {
-
-namespace {
-
-bool StringToIPEndPoint(const std::string& ip_address_and_port,
- IPEndPoint* ip_end_point) {
- DCHECK(ip_end_point);
-
- std::string ip;
- int port;
- if (!ParseHostAndPort(ip_address_and_port, &ip, &port))
- return false;
- if (port == -1)
- port = dns_protocol::kDefaultPort;
-
- net::IPAddress ip_address;
- if (!ip_address.AssignFromIPLiteral(ip))
- return false;
-
- *ip_end_point = net::IPEndPoint(ip_address, static_cast<uint16_t>(port));
- return true;
-}
-
-// Convert DnsConfig to human readable text omitting the hosts member.
-std::string DnsConfigToString(const DnsConfig& dns_config) {
- std::string output;
- output.append("search ");
- for (size_t i = 0; i < dns_config.search.size(); ++i) {
- output.append(dns_config.search[i] + " ");
- }
- output.append("\n");
-
- for (size_t i = 0; i < dns_config.nameservers.size(); ++i) {
- output.append("nameserver ");
- output.append(dns_config.nameservers[i].ToString()).append("\n");
- }
-
- base::StringAppendF(&output, "options ndots:%d\n", dns_config.ndots);
- base::StringAppendF(&output, "options timeout:%d\n",
- static_cast<int>(dns_config.timeout.InMilliseconds()));
- base::StringAppendF(&output, "options attempts:%d\n", dns_config.attempts);
- if (dns_config.rotate)
- output.append("options rotate\n");
- return output;
-}
-
-// Convert DnsConfig hosts member to a human readable text.
-std::string DnsHostsToString(const DnsHosts& dns_hosts) {
- std::string output;
- for (DnsHosts::const_iterator i = dns_hosts.begin();
- i != dns_hosts.end();
- ++i) {
- const DnsHostsKey& key = i->first;
- std::string host_name = key.first;
- output.append(IPEndPoint(i->second, 0).ToStringWithoutPort());
- output.append(" ").append(host_name).append("\n");
- }
- return output;
-}
-
-struct ReplayLogEntry {
- base::TimeDelta start_time;
- std::string domain_name;
-};
-
-typedef std::vector<ReplayLogEntry> ReplayLog;
-
-// Loads and parses a replay log file and fills |replay_log| with a structured
-// representation. Returns whether the operation was successful. If not, the
-// contents of |replay_log| are undefined.
-//
-// The replay log is a text file where each line contains
-//
-// timestamp_in_milliseconds domain_name
-//
-// The timestamp_in_milliseconds needs to be an integral delta from start of
-// resolution and is in milliseconds. domain_name is the name to be resolved.
-//
-// The file should be sorted by timestamp in ascending time.
-bool LoadReplayLog(const base::FilePath& file_path, ReplayLog* replay_log) {
- std::string original_replay_log_contents;
- if (!base::ReadFileToString(file_path, &original_replay_log_contents)) {
- fprintf(stderr, "Unable to open replay file %s\n",
- file_path.MaybeAsASCII().c_str());
- return false;
- }
-
- // Strip out \r characters for Windows files. This isn't as efficient as a
- // smarter line splitter, but this particular use does not need to target
- // efficiency.
- std::string replay_log_contents;
- base::RemoveChars(original_replay_log_contents, "\r", &replay_log_contents);
-
- std::vector<std::string> lines = base::SplitString(
- replay_log_contents, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- base::TimeDelta previous_delta;
- bool bad_parse = false;
- for (unsigned i = 0; i < lines.size(); ++i) {
- if (lines[i].empty())
- continue;
- std::vector<std::string> time_and_name = base::SplitString(
- lines[i], " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- if (time_and_name.size() != 2) {
- fprintf(
- stderr,
- "[%s %u] replay log should have format 'timestamp domain_name\\n'\n",
- file_path.MaybeAsASCII().c_str(),
- i + 1);
- bad_parse = true;
- continue;
- }
-
- int64_t delta_in_milliseconds;
- if (!base::StringToInt64(time_and_name[0], &delta_in_milliseconds)) {
- fprintf(
- stderr,
- "[%s %u] replay log should have format 'timestamp domain_name\\n'\n",
- file_path.MaybeAsASCII().c_str(),
- i + 1);
- bad_parse = true;
- continue;
- }
-
- base::TimeDelta delta =
- base::TimeDelta::FromMilliseconds(delta_in_milliseconds);
- if (delta < previous_delta) {
- fprintf(
- stderr,
- "[%s %u] replay log should be sorted by time\n",
- file_path.MaybeAsASCII().c_str(),
- i + 1);
- bad_parse = true;
- continue;
- }
-
- previous_delta = delta;
- ReplayLogEntry entry;
- entry.start_time = delta;
- entry.domain_name = time_and_name[1];
- replay_log->push_back(entry);
- }
- return !bad_parse;
-}
-
-class GDig {
- public:
- GDig();
- ~GDig();
-
- enum Result {
- RESULT_NO_RESOLVE = -3,
- RESULT_NO_CONFIG = -2,
- RESULT_WRONG_USAGE = -1,
- RESULT_OK = 0,
- RESULT_PENDING = 1,
- };
-
- Result Main(int argc, const char* argv[]);
-
- private:
- bool ParseCommandLine(int argc, const char* argv[]);
-
- void Start();
- void Finish(Result);
-
- void OnDnsConfig(const DnsConfig& dns_config_const);
- void OnResolveComplete(unsigned index, AddressList* address_list,
- base::TimeDelta time_since_start, int val);
- void OnTimeout();
- void ReplayNextEntry();
-
- base::TimeDelta config_timeout_;
- bool print_config_;
- bool print_hosts_;
- net::IPEndPoint nameserver_;
- base::TimeDelta timeout_;
- int parallellism_;
- ReplayLog replay_log_;
- unsigned replay_log_index_;
- base::Time start_time_;
- int active_resolves_;
- Result result_;
-
- base::CancelableClosure timeout_closure_;
- std::unique_ptr<DnsConfigService> dns_config_service_;
- std::unique_ptr<FileNetLogObserver> log_observer_;
- std::unique_ptr<NetLog> log_;
- std::unique_ptr<HostResolver> resolver_;
- std::unique_ptr<HostResolver::Request> request_;
-
-#if defined(OS_MACOSX)
- // Without this there will be a mem leak on osx.
- base::mac::ScopedNSAutoreleasePool scoped_pool_;
-#endif
-
- // Need AtExitManager to support AsWeakPtr (in NetLog).
- base::AtExitManager exit_manager_;
-};
-
-GDig::GDig()
- : config_timeout_(base::TimeDelta::FromSeconds(5)),
- print_config_(false),
- print_hosts_(false),
- parallellism_(6),
- replay_log_index_(0u),
- active_resolves_(0) {
-}
-
-GDig::~GDig() {
- if (log_)
- log_->RemoveObserver(log_observer_.get());
-}
-
-GDig::Result GDig::Main(int argc, const char* argv[]) {
- if (!ParseCommandLine(argc, argv)) {
- fprintf(stderr,
- "usage: %s [--net_log[=<basic|no_bytes|all>]]"
- " [--print_config] [--print_hosts]"
- " [--nameserver=<ip_address[:port]>]"
- " [--timeout=<milliseconds>]"
- " [--config_timeout=<seconds>]"
- " [--j=<parallel resolves>]"
- " [--replay_file=<path>]"
- " [domain_name]\n",
- argv[0]);
- return RESULT_WRONG_USAGE;
- }
-
- base::MessageLoopForIO loop;
-
- result_ = RESULT_PENDING;
- Start();
- if (result_ == RESULT_PENDING)
- base::RunLoop().Run();
-
- // Destroy it while MessageLoopForIO is alive.
- dns_config_service_.reset();
- return result_;
-}
-
-bool GDig::ParseCommandLine(int argc, const char* argv[]) {
- base::CommandLine::Init(argc, argv);
- const base::CommandLine& parsed_command_line =
- *base::CommandLine::ForCurrentProcess();
-
- if (parsed_command_line.HasSwitch("config_timeout")) {
- int timeout_seconds = 0;
- bool parsed = base::StringToInt(
- parsed_command_line.GetSwitchValueASCII("config_timeout"),
- &timeout_seconds);
- if (parsed && timeout_seconds > 0) {
- config_timeout_ = base::TimeDelta::FromSeconds(timeout_seconds);
- } else {
- fprintf(stderr, "Invalid config_timeout parameter\n");
- return false;
- }
- }
-
- if (parsed_command_line.HasSwitch("net_log")) {
- std::string log_param = parsed_command_line.GetSwitchValueASCII("net_log");
- NetLogCaptureMode capture_mode =
- NetLogCaptureMode::IncludeCookiesAndCredentials();
-
- if (log_param.length() > 0) {
- std::map<std::string, NetLogCaptureMode> capture_modes;
- capture_modes["all"] = NetLogCaptureMode::IncludeSocketBytes();
- capture_modes["no_bytes"] =
- NetLogCaptureMode::IncludeCookiesAndCredentials();
-
- if (capture_modes.find(log_param) != capture_modes.end()) {
- capture_mode = capture_modes[log_param];
- } else {
- fprintf(stderr, "Invalid net_log parameter\n");
- return false;
- }
- }
- log_.reset(new NetLog);
- log_observer_.reset(new FileNetLogObserver(stderr));
- log_->AddObserver(log_observer_.get(), capture_mode);
- }
-
- print_config_ = parsed_command_line.HasSwitch("print_config");
- print_hosts_ = parsed_command_line.HasSwitch("print_hosts");
-
- if (parsed_command_line.HasSwitch("nameserver")) {
- std::string nameserver =
- parsed_command_line.GetSwitchValueASCII("nameserver");
- if (!StringToIPEndPoint(nameserver, &nameserver_)) {
- fprintf(stderr,
- "Cannot parse the nameserver string into an IPEndPoint\n");
- return false;
- }
- }
-
- if (parsed_command_line.HasSwitch("timeout")) {
- int timeout_millis = 0;
- bool parsed = base::StringToInt(
- parsed_command_line.GetSwitchValueASCII("timeout"),
- &timeout_millis);
- if (parsed && timeout_millis > 0) {
- timeout_ = base::TimeDelta::FromMilliseconds(timeout_millis);
- } else {
- fprintf(stderr, "Invalid timeout parameter\n");
- return false;
- }
- }
-
- if (parsed_command_line.HasSwitch("replay_file")) {
- base::FilePath replay_path =
- parsed_command_line.GetSwitchValuePath("replay_file");
- if (!LoadReplayLog(replay_path, &replay_log_))
- return false;
- }
-
- if (parsed_command_line.HasSwitch("j")) {
- int parallellism = 0;
- bool parsed = base::StringToInt(
- parsed_command_line.GetSwitchValueASCII("j"),
- &parallellism);
- if (parsed && parallellism > 0) {
- parallellism_ = parallellism;
- } else {
- fprintf(stderr, "Invalid parallellism parameter\n");
- }
- }
-
- if (parsed_command_line.GetArgs().size() == 1) {
- ReplayLogEntry entry;
- entry.start_time = base::TimeDelta();
-#if defined(OS_WIN)
- entry.domain_name = base::UTF16ToASCII(parsed_command_line.GetArgs()[0]);
-#else
- entry.domain_name = parsed_command_line.GetArgs()[0];
-#endif
- replay_log_.push_back(entry);
- } else if (parsed_command_line.GetArgs().size() != 0) {
- return false;
- }
- return print_config_ || print_hosts_ || !replay_log_.empty();
-}
-
-void GDig::Start() {
- if (nameserver_.address().size() > 0) {
- DnsConfig dns_config;
- dns_config.attempts = 1;
- dns_config.nameservers.push_back(nameserver_);
- OnDnsConfig(dns_config);
- } else {
- dns_config_service_ = DnsConfigService::CreateSystemService();
- dns_config_service_->ReadConfig(base::Bind(&GDig::OnDnsConfig,
- base::Unretained(this)));
- timeout_closure_.Reset(base::Bind(&GDig::OnTimeout,
- base::Unretained(this)));
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, timeout_closure_.callback(), config_timeout_);
- }
-}
-
-void GDig::Finish(Result result) {
- DCHECK_NE(RESULT_PENDING, result);
- result_ = result;
- if (base::MessageLoopCurrent::Get())
- base::RunLoop::QuitCurrentWhenIdleDeprecated();
-}
-
-void GDig::OnDnsConfig(const DnsConfig& dns_config_const) {
- timeout_closure_.Cancel();
- DCHECK(dns_config_const.IsValid());
- DnsConfig dns_config = dns_config_const;
-
- if (timeout_.InMilliseconds() > 0)
- dns_config.timeout = timeout_;
- if (print_config_) {
- printf("# Dns Configuration\n"
- "%s", DnsConfigToString(dns_config).c_str());
- }
- if (print_hosts_) {
- printf("# Host Database\n"
- "%s", DnsHostsToString(dns_config.hosts).c_str());
- }
-
- if (replay_log_.empty()) {
- Finish(RESULT_OK);
- return;
- }
-
- std::unique_ptr<DnsClient> dns_client(DnsClient::CreateClient(NULL));
- dns_client->SetConfig(dns_config);
- HostResolver::Options options;
- options.max_concurrent_resolves = parallellism_;
- options.max_retry_attempts = 1u;
- std::unique_ptr<HostResolverImpl> resolver(
- new HostResolverImpl(options, log_.get()));
- resolver->SetDnsClient(std::move(dns_client));
- resolver_ = std::move(resolver);
-
- start_time_ = base::Time::Now();
-
- ReplayNextEntry();
-}
-
-void GDig::ReplayNextEntry() {
- DCHECK_LT(replay_log_index_, replay_log_.size());
-
- base::TimeDelta time_since_start = base::Time::Now() - start_time_;
- while (replay_log_index_ < replay_log_.size()) {
- const ReplayLogEntry& entry = replay_log_[replay_log_index_];
- if (time_since_start < entry.start_time) {
- // Delay call to next time and return.
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&GDig::ReplayNextEntry, base::Unretained(this)),
- entry.start_time - time_since_start);
- return;
- }
-
- HostResolver::RequestInfo info(HostPortPair(entry.domain_name.c_str(), 80));
- AddressList* addrlist = new AddressList();
- unsigned current_index = replay_log_index_;
- CompletionCallback callback = base::Bind(&GDig::OnResolveComplete,
- base::Unretained(this),
- current_index,
- base::Owned(addrlist),
- time_since_start);
- ++active_resolves_;
- ++replay_log_index_;
- int ret = resolver_->Resolve(
- info, DEFAULT_PRIORITY, addrlist, callback, &request_,
- NetLogWithSource::Make(log_.get(), net::NetLogSourceType::NONE));
- if (ret != ERR_IO_PENDING)
- callback.Run(ret);
- }
-}
-
-void GDig::OnResolveComplete(unsigned entry_index,
- AddressList* address_list,
- base::TimeDelta resolve_start_time,
- int val) {
- DCHECK_GT(active_resolves_, 0);
- DCHECK(address_list);
- DCHECK_LT(entry_index, replay_log_.size());
- --active_resolves_;
- base::TimeDelta resolve_end_time = base::Time::Now() - start_time_;
- base::TimeDelta resolve_time = resolve_end_time - resolve_start_time;
- printf("%u %d %d %s %d ",
- entry_index,
- static_cast<int>(resolve_end_time.InMilliseconds()),
- static_cast<int>(resolve_time.InMilliseconds()),
- replay_log_[entry_index].domain_name.c_str(), val);
- if (val != OK) {
- std::string error_string = ErrorToString(val);
- printf("%s", error_string.c_str());
- } else {
- for (size_t i = 0; i < address_list->size(); ++i) {
- if (i != 0)
- printf(" ");
- printf("%s", (*address_list)[i].ToStringWithoutPort().c_str());
- }
- }
- printf("\n");
- if (active_resolves_ == 0 && replay_log_index_ >= replay_log_.size())
- Finish(RESULT_OK);
-}
-
-void GDig::OnTimeout() {
- fprintf(stderr, "Timed out waiting to load the dns config\n");
- Finish(RESULT_NO_CONFIG);
-}
-
-} // empty namespace
-
-} // namespace net
-
-int main(int argc, const char* argv[]) {
- net::GDig dig;
- return dig.Main(argc, argv);
-}
diff --git a/chromium/net/tools/quic/quic_client_message_loop_network_helper.cc b/chromium/net/tools/quic/quic_client_message_loop_network_helper.cc
index c6154dea784..995ad4f75e5 100644
--- a/chromium/net/tools/quic/quic_client_message_loop_network_helper.cc
+++ b/chromium/net/tools/quic/quic_client_message_loop_network_helper.cc
@@ -14,17 +14,17 @@
#include "net/http/http_response_info.h"
#include "net/log/net_log_source.h"
#include "net/log/net_log_with_source.h"
-#include "net/quic/chromium/quic_chromium_alarm_factory.h"
-#include "net/quic/chromium/quic_chromium_connection_helper.h"
-#include "net/quic/chromium/quic_chromium_packet_reader.h"
-#include "net/quic/chromium/quic_chromium_packet_writer.h"
+#include "net/quic/quic_chromium_alarm_factory.h"
+#include "net/quic/quic_chromium_connection_helper.h"
+#include "net/quic/quic_chromium_packet_reader.h"
+#include "net/quic/quic_chromium_packet_writer.h"
#include "net/socket/udp_client_socket.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/third_party/quic/core/crypto/quic_random.h"
+#include "net/third_party/quic/core/http/spdy_utils.h"
#include "net/third_party/quic/core/quic_connection.h"
#include "net/third_party/quic/core/quic_packets.h"
#include "net/third_party/quic/core/quic_server_id.h"
-#include "net/third_party/quic/core/spdy_utils.h"
#include "net/third_party/quic/platform/api/quic_flags.h"
#include "net/third_party/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/spdy/core/spdy_header_block.h"
diff --git a/chromium/net/tools/quic/quic_client_message_loop_network_helper.h b/chromium/net/tools/quic/quic_client_message_loop_network_helper.h
index a41f7fd3a39..58788ce6558 100644
--- a/chromium/net/tools/quic/quic_client_message_loop_network_helper.h
+++ b/chromium/net/tools/quic/quic_client_message_loop_network_helper.h
@@ -19,9 +19,9 @@
#include "net/base/ip_endpoint.h"
#include "net/http/http_response_headers.h"
#include "net/log/net_log.h"
-#include "net/quic/chromium/quic_chromium_packet_reader.h"
+#include "net/quic/quic_chromium_packet_reader.h"
+#include "net/third_party/quic/core/http/quic_spdy_stream.h"
#include "net/third_party/quic/core/quic_config.h"
-#include "net/third_party/quic/core/quic_spdy_stream.h"
#include "net/third_party/quic/platform/impl/quic_chromium_clock.h"
#include "net/third_party/quic/tools/quic_spdy_client_base.h"
diff --git a/chromium/net/tools/quic/quic_http_proxy_backend.cc b/chromium/net/tools/quic/quic_http_proxy_backend.cc
new file mode 100644
index 00000000000..610c98fd4b5
--- /dev/null
+++ b/chromium/net/tools/quic/quic_http_proxy_backend.cc
@@ -0,0 +1,191 @@
+// 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
diff --git a/chromium/net/tools/quic/quic_http_proxy_backend.h b/chromium/net/tools/quic/quic_http_proxy_backend.h
new file mode 100644
index 00000000000..c5811e6d86d
--- /dev/null
+++ b/chromium/net/tools/quic/quic_http_proxy_backend.h
@@ -0,0 +1,110 @@
+// 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
diff --git a/chromium/net/tools/quic/quic_http_proxy_backend_stream.cc b/chromium/net/tools/quic/quic_http_proxy_backend_stream.cc
new file mode 100644
index 00000000000..5d1595319a7
--- /dev/null
+++ b/chromium/net/tools/quic/quic_http_proxy_backend_stream.cc
@@ -0,0 +1,401 @@
+// 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/strings/string_number_conversions.h"
+#include "net/base/elements_upload_data_stream.h"
+#include "net/base/net_errors.h"
+#include "net/base/request_priority.h"
+#include "net/base/upload_bytes_element_reader.h"
+#include "net/cert/cert_status_flags.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/http/http_util.h"
+#include "net/ssl/ssl_info.h"
+#include "net/url_request/redirect_info.h"
+#include "net/url_request/url_request_context.h"
+
+#include "net/tools/quic/quic_http_proxy_backend_stream.h"
+
+namespace net {
+
+// This is the Size of the buffer that consumes the response from the Backend
+// The response is consumed upto 64KB at a time to avoid a large response
+// from hogging resources from smaller responses.
+const int QuicHttpProxyBackendStream::kBufferSize = 64000;
+/*502 Bad Gateway
+ The server was acting as a gateway or proxy and received an
+ invalid response from the upstream server.*/
+const int QuicHttpProxyBackendStream::kProxyHttpBackendError = 502;
+// Hop-by-hop headers (small-caps). These are removed when sent to the backend.
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
+// not Trailers per URL above;
+// http://www.rfc-editor.org/errata_search.php?eid=4522
+const std::set<std::string> QuicHttpProxyBackendStream::kHopHeaders = {
+ "connection",
+ "proxy-connection", // non-standard but still sent by libcurl and rejected
+ // by e.g. google
+ "keep-alive", "proxy-authenticate", "proxy-authorization",
+ "te", // canonicalized version of "TE"
+ "trailer", // not Trailers per URL above;
+ // http://www.rfc-editor.org/errata_search.php?eid=4522
+ "transfer-encoding", "upgrade",
+};
+const std::string QuicHttpProxyBackendStream::kDefaultQuicPeerIP = "Unknown";
+
+QuicHttpProxyBackendStream::QuicHttpProxyBackendStream(
+ QuicHttpProxyBackend* proxy_context)
+ : proxy_context_(proxy_context),
+ delegate_(nullptr),
+ quic_peer_ip_(kDefaultQuicPeerIP),
+ url_request_(nullptr),
+ buf_(base::MakeRefCounted<IOBuffer>(kBufferSize)),
+ response_completed_(false),
+ headers_set_(false),
+ quic_response_(new quic::QuicBackendResponse()),
+ weak_factory_(this) {}
+
+QuicHttpProxyBackendStream::~QuicHttpProxyBackendStream() {}
+
+void QuicHttpProxyBackendStream::Initialize(
+ quic::QuicConnectionId quic_connection_id,
+ quic::QuicStreamId quic_stream_id,
+ std::string quic_peer_ip) {
+ quic_connection_id_ = quic_connection_id;
+ quic_stream_id_ = quic_stream_id;
+ quic_peer_ip_ = quic_peer_ip;
+ if (!quic_proxy_task_runner_.get()) {
+ quic_proxy_task_runner_ = proxy_context_->GetProxyTaskRunner();
+ } else {
+ DCHECK_EQ(quic_proxy_task_runner_, proxy_context_->GetProxyTaskRunner());
+ }
+
+ quic_response_->set_response_type(
+ quic::QuicBackendResponse::BACKEND_ERR_RESPONSE);
+}
+
+void QuicHttpProxyBackendStream::set_delegate(
+ quic::QuicSimpleServerBackend::RequestHandler* delegate) {
+ delegate_ = delegate;
+ delegate_task_runner_ = base::SequencedTaskRunnerHandle::Get();
+}
+
+bool QuicHttpProxyBackendStream::SendRequestToBackend(
+ const spdy::SpdyHeaderBlock* incoming_request_headers,
+ const std::string& incoming_body) {
+ DCHECK(proxy_context_->IsBackendInitialized())
+ << " The quic-backend-proxy-context should be initialized";
+
+ // Get Path From the Incoming Header Block
+ spdy::SpdyHeaderBlock::const_iterator it =
+ incoming_request_headers->find(":path");
+
+ GURL url = proxy_context_->backend_url();
+ std::string backend_spec = url.spec();
+ if (it != incoming_request_headers->end()) {
+ if (url.path().compare("/") == 0) {
+ backend_spec.pop_back();
+ }
+ backend_spec.append(it->second.as_string());
+ }
+
+ url_ = GURL(backend_spec.c_str());
+ if (!url_.is_valid()) {
+ LOG(ERROR) << "Invalid URL received from QUIC client " << backend_spec;
+ return false;
+ }
+ LOG(INFO) << "QUIC Proxy Making a request to the Backed URL: " + url_.spec();
+
+ // Set the Method From the Incoming Header Block
+ std::string method = "";
+ it = incoming_request_headers->find(":method");
+ if (it != incoming_request_headers->end()) {
+ method.append(it->second.as_string());
+ }
+ if (ValidateHttpMethod(method) != true) {
+ LOG(INFO) << "Unknown Request Type received from QUIC client " << method;
+ return false;
+ }
+ CopyHeaders(incoming_request_headers);
+ if (method_type_ == "POST" || method_type_ == "PUT" ||
+ method_type_ == "PATCH") {
+ // Upload content must be set
+ if (!incoming_body.empty()) {
+ std::unique_ptr<UploadElementReader> reader(new UploadBytesElementReader(
+ incoming_body.data(), incoming_body.size()));
+ SetUpload(
+ ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
+ }
+ }
+ // Start the request on the backend thread
+ bool posted = quic_proxy_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&QuicHttpProxyBackendStream::SendRequestOnBackendThread,
+ weak_factory_.GetWeakPtr()));
+ return posted;
+}
+
+void QuicHttpProxyBackendStream::CopyHeaders(
+ const spdy::SpdyHeaderBlock* incoming_request_headers) {
+ // Set all the request headers
+ // Add or append the X-Forwarded-For Header and X-Real-IP
+ for (spdy::SpdyHeaderBlock::const_iterator it =
+ incoming_request_headers->begin();
+ it != incoming_request_headers->end(); ++it) {
+ std::string key = it->first.as_string();
+ std::string value = it->second.as_string();
+ // Ignore the spdy headers
+ if (!key.empty() && key[0] != ':') {
+ // Remove hop-by-hop headers
+ if (base::ContainsKey(kHopHeaders, key)) {
+ LOG(INFO) << "QUIC Proxy Ignoring Hop-by-hop Request Header: " << key
+ << ":" << value;
+ } else {
+ LOG(INFO) << "QUIC Proxy Copying to backend Request Header: " << key
+ << ":" << value;
+ AddRequestHeader(key, value);
+ }
+ }
+ }
+ // ToDo append proxy ip when x_forwarded_for header already present
+ AddRequestHeader("X-Forwarded-For", quic_peer_ip_);
+}
+
+bool QuicHttpProxyBackendStream::ValidateHttpMethod(std::string method) {
+ // Http method is a token, just as header name.
+ if (!net::HttpUtil::IsValidHeaderName(method))
+ return false;
+ method_type_ = method;
+ return true;
+}
+
+bool QuicHttpProxyBackendStream::AddRequestHeader(std::string name,
+ std::string value) {
+ if (!net::HttpUtil::IsValidHeaderName(name) ||
+ !net::HttpUtil::IsValidHeaderValue(value)) {
+ return false;
+ }
+ request_headers_.SetHeader(name, value);
+ return true;
+}
+
+void QuicHttpProxyBackendStream::SetUpload(
+ std::unique_ptr<net::UploadDataStream> upload) {
+ DCHECK(!upload_);
+ upload_ = std::move(upload);
+}
+
+void QuicHttpProxyBackendStream::SendRequestOnBackendThread() {
+ DCHECK(quic_proxy_task_runner_->BelongsToCurrentThread());
+ url_request_ = proxy_context_->GetURLRequestContext()->CreateRequest(
+ url_, net::DEFAULT_PRIORITY, this);
+ url_request_->set_method(method_type_);
+ url_request_->SetExtraRequestHeaders(request_headers_);
+ if (upload_) {
+ url_request_->set_upload(std::move(upload_));
+ }
+ url_request_->Start();
+ VLOG(1) << "Quic Proxy Sending Request to Backend for quic_conn_id: "
+ << quic_connection_id_ << " quic_stream_id: " << quic_stream_id_
+ << " backend_req_id: " << url_request_->identifier()
+ << " url: " << url_;
+}
+
+void QuicHttpProxyBackendStream::OnReceivedRedirect(
+ net::URLRequest* request,
+ const net::RedirectInfo& redirect_info,
+ bool* defer_redirect) {
+ DCHECK_EQ(request, url_request_.get());
+ DCHECK(quic_proxy_task_runner_->BelongsToCurrentThread());
+ // Do not defer redirect, retry again from the proxy with the new url
+ *defer_redirect = false;
+ LOG(ERROR) << "Received Redirect from Backend "
+ << " BackendReqId: " << request->identifier() << " redirectUrl: "
+ << redirect_info.new_url.possibly_invalid_spec().c_str()
+ << " RespCode " << request->GetResponseCode();
+}
+
+void QuicHttpProxyBackendStream::OnCertificateRequested(
+ net::URLRequest* request,
+ net::SSLCertRequestInfo* cert_request_info) {
+ DCHECK_EQ(request, url_request_.get());
+ DCHECK(quic_proxy_task_runner_->BelongsToCurrentThread());
+ // Continue the SSL handshake without a client certificate.
+ request->ContinueWithCertificate(nullptr, nullptr);
+}
+
+void QuicHttpProxyBackendStream::OnSSLCertificateError(
+ net::URLRequest* request,
+ const net::SSLInfo& ssl_info,
+ bool fatal) {
+ request->Cancel();
+ OnResponseCompleted();
+}
+
+void QuicHttpProxyBackendStream::OnResponseStarted(net::URLRequest* request,
+ int net_error) {
+ DCHECK_EQ(request, url_request_.get());
+ DCHECK(quic_proxy_task_runner_->BelongsToCurrentThread());
+ // It doesn't make sense for the request to have IO pending at this point.
+ DCHECK_NE(net::ERR_IO_PENDING, net_error);
+ if (net_error != net::OK) {
+ LOG(ERROR) << "OnResponseStarted Error from Backend "
+ << url_request_->identifier() << " url: "
+ << url_request_->url().possibly_invalid_spec().c_str()
+ << " RespError " << net::ErrorToString(net_error);
+ OnResponseCompleted();
+ return;
+ }
+ // Initialite the first read
+ ReadOnceTask();
+}
+
+void QuicHttpProxyBackendStream::ReadOnceTask() {
+ // Initiate a read for a max of kBufferSize
+ // This avoids a request with a large response from starving
+ // requests with smaller responses
+ int bytes_read = url_request_->Read(buf_.get(), kBufferSize);
+ OnReadCompleted(url_request_.get(), bytes_read);
+}
+
+// In the case of net::ERR_IO_PENDING,
+// OnReadCompleted callback will be called by URLRequest
+void QuicHttpProxyBackendStream::OnReadCompleted(net::URLRequest* unused,
+ int bytes_read) {
+ DCHECK_EQ(url_request_.get(), unused);
+ LOG(INFO) << "OnReadCompleted Backend with"
+ << " ReqId: " << url_request_->identifier() << " RespCode "
+ << url_request_->GetResponseCode() << " RcvdBytesCount "
+ << bytes_read << " RcvdTotalBytes " << data_received_.size();
+
+ if (bytes_read > 0) {
+ data_received_.append(buf_->data(), bytes_read);
+ // More data to be read, send a task to self
+ quic_proxy_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&QuicHttpProxyBackendStream::ReadOnceTask,
+ weak_factory_.GetWeakPtr()));
+ } else if (bytes_read != net::ERR_IO_PENDING) {
+ quic_response_->set_response_type(
+ quic::QuicBackendResponse::REGULAR_RESPONSE);
+ OnResponseCompleted();
+ }
+}
+
+/* Response from Backend complete, send the last chunk of data with fin=true to
+ * the corresponding quic stream */
+void QuicHttpProxyBackendStream::OnResponseCompleted() {
+ DCHECK(!response_completed_);
+ LOG(INFO) << "Quic Proxy Received Response from Backend for quic_conn_id: "
+ << quic_connection_id_ << " quic_stream_id: " << quic_stream_id_
+ << " backend_req_id: " << url_request_->identifier()
+ << " url: " << url_;
+
+ // ToDo Stream the response
+ spdy::SpdyHeaderBlock response_headers;
+ if (quic_response_->response_type() !=
+ quic::QuicBackendResponse::BACKEND_ERR_RESPONSE) {
+ response_headers = getAsQuicHeaders(url_request_->response_headers(),
+ url_request_->GetResponseCode(),
+ data_received_.size());
+ quic_response_->set_headers(std::move(response_headers));
+ quic_response_->set_body(std::move(data_received_));
+ } else {
+ response_headers =
+ getAsQuicHeaders(url_request_->response_headers(),
+ kProxyHttpBackendError, data_received_.size());
+ quic_response_->set_headers(std::move(response_headers));
+ }
+ response_completed_ = true;
+ ReleaseRequest();
+
+ // Send the response back to the quic client on the quic/main thread
+ if (delegate_ != nullptr) {
+ delegate_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &QuicHttpProxyBackendStream::SendResponseOnDelegateThread,
+ base::Unretained(this)));
+ }
+}
+
+void QuicHttpProxyBackendStream::SendResponseOnDelegateThread() {
+ DCHECK(delegate_ != nullptr);
+ // Proxy currently does not support push resources
+ std::list<quic::QuicBackendResponse::ServerPushInfo> empty_resources;
+ delegate_->OnResponseBackendComplete(quic_response_.get(), empty_resources);
+}
+
+void QuicHttpProxyBackendStream::CancelRequest() {
+ DCHECK(quic_proxy_task_runner_->BelongsToCurrentThread());
+ if (quic_proxy_task_runner_.get())
+ DCHECK(quic_proxy_task_runner_->BelongsToCurrentThread());
+ delegate_ = nullptr;
+ if (url_request_.get()) {
+ url_request_->CancelWithError(ERR_ABORTED);
+ ReleaseRequest();
+ }
+}
+
+void QuicHttpProxyBackendStream::ReleaseRequest() {
+ url_request_.reset();
+ buf_ = nullptr;
+}
+
+quic::QuicBackendResponse* QuicHttpProxyBackendStream::GetBackendResponse()
+ const {
+ return quic_response_.get();
+}
+
+// Copy Backend Response headers to Quic response headers
+spdy::SpdyHeaderBlock QuicHttpProxyBackendStream::getAsQuicHeaders(
+ net::HttpResponseHeaders* resp_headers,
+ int response_code,
+ uint64_t response_decoded_body_size) {
+ DCHECK(!headers_set_);
+ bool response_body_encoded = false;
+ spdy::SpdyHeaderBlock quic_response_headers;
+ // Add spdy headers: Status, version need : before the header
+ quic_response_headers[":status"] = base::NumberToString(response_code);
+ headers_set_ = true;
+ // Returns an empty array if |headers| is nullptr.
+ if (resp_headers != nullptr) {
+ size_t iter = 0;
+ std::string header_name;
+ std::string header_value;
+ while (resp_headers->EnumerateHeaderLines(&iter, &header_name,
+ &header_value)) {
+ header_name = base::ToLowerASCII(header_name);
+ // Do not copy status again since status needs a ":" before the header
+ // name
+ if (header_name.compare("status") != 0) {
+ if (header_name.compare("content-encoding") != 0) {
+ // Remove hop-by-hop headers
+ if (base::ContainsKey(kHopHeaders, header_name)) {
+ LOG(INFO) << "Quic Proxy Ignoring Hop-by-hop Response Header: "
+ << header_name << ":" << header_value;
+ } else {
+ LOG(INFO) << " Quic Proxy Copying Response Header: " << header_name
+ << ":" << header_value;
+ quic_response_headers.AppendValueOrAddHeader(header_name,
+ header_value);
+ }
+ } else {
+ response_body_encoded = true;
+ }
+ }
+ } // while
+ // Currently URLRequest class does not support ability to disable decoding,
+ // response body (gzip, deflate etc. )
+ // Instead of re-encoding the body, we send decode body to the quic client
+ // and re-write the content length to the original body size
+ if (response_body_encoded) {
+ LOG(INFO) << " Quic Proxy Rewriting the Content-Length Header since "
+ "the response was encoded : "
+ << response_decoded_body_size;
+ quic_response_headers["content-length"] =
+ base::NumberToString(response_decoded_body_size);
+ }
+ }
+ return quic_response_headers;
+}
+} // namespace net \ No newline at end of file
diff --git a/chromium/net/tools/quic/quic_http_proxy_backend_stream.h b/chromium/net/tools/quic/quic_http_proxy_backend_stream.h
new file mode 100644
index 00000000000..a231433430a
--- /dev/null
+++ b/chromium/net/tools/quic/quic_http_proxy_backend_stream.h
@@ -0,0 +1,162 @@
+// 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
diff --git a/chromium/net/tools/quic/quic_http_proxy_backend_stream_test.cc b/chromium/net/tools/quic/quic_http_proxy_backend_stream_test.cc
new file mode 100644
index 00000000000..ef2d507f484
--- /dev/null
+++ b/chromium/net/tools/quic/quic_http_proxy_backend_stream_test.cc
@@ -0,0 +1,482 @@
+// 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 "net/tools/quic/quic_http_proxy_backend_stream.h"
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/scoped_task_environment.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/test/embedded_test_server/request_handler_util.h"
+#include "net/third_party/quic/platform/api/quic_test.h"
+#include "net/third_party/quic/tools/quic_backend_response.h"
+#include "net/tools/quic/quic_http_proxy_backend.h"
+
+namespace net {
+namespace test {
+
+// Test server path and response body for the default URL used by many of the
+// tests.
+const char kDefaultResponsePath[] = "/defaultresponse";
+const char kDefaultResponseBody[] =
+ "Default response given for path: /defaultresponse";
+std::string kLargeResponseBody(
+ "Default response given for path: /defaultresponselarge");
+const char* const kHttp2StatusHeader = ":status";
+
+// To test uploading the contents of a file
+base::FilePath GetUploadFileTestPath() {
+ base::FilePath path;
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ return path.Append(
+ FILE_PATH_LITERAL("net/data/url_request_unittest/BullRunSpeech.txt"));
+}
+
+// /defaultresponselarge
+// Returns a valid 10 MB response.
+std::unique_ptr<test_server::HttpResponse> HandleDefaultResponseLarge(
+ const test_server::HttpRequest& request) {
+ std::unique_ptr<test_server::BasicHttpResponse> http_response(
+ new test_server::BasicHttpResponse);
+ http_response->set_content_type("text/html");
+ // return 10 MB
+ for (int i = 0; i < 200000; ++i)
+ kLargeResponseBody += "01234567890123456789012345678901234567890123456789";
+ http_response->set_content(kLargeResponseBody);
+
+ return std::move(http_response);
+}
+
+int ParseHeaderStatusCode(const spdy::SpdyHeaderBlock& header) {
+ int status_code;
+ spdy::SpdyHeaderBlock::const_iterator it = header.find(kHttp2StatusHeader);
+ if (it == header.end()) {
+ return -1;
+ }
+ const base::StringPiece status(it->second);
+ if (status.size() != 3) {
+ return -1;
+ }
+ // First character must be an integer in range [1,5].
+ if (status[0] < '1' || status[0] > '5') {
+ return -1;
+ }
+ // The remaining two characters must be integers.
+ if (!isdigit(status[1]) || !isdigit(status[2])) {
+ return -1;
+ }
+ if (base::StringToInt(status, &status_code)) {
+ return status_code;
+ } else {
+ return -1;
+ }
+}
+
+class TestQuicServerStreamDelegate
+ : public quic::QuicSimpleServerBackend::RequestHandler {
+ public:
+ TestQuicServerStreamDelegate()
+ : send_success_(false),
+ did_complete_(false),
+ quic_backend_stream_(nullptr) {}
+
+ ~TestQuicServerStreamDelegate() override {}
+
+ void CreateProxyBackendResponseStreamForTest(
+ QuicHttpProxyBackend* proxy_backend) {
+ quic_backend_stream_ =
+ std::make_unique<QuicHttpProxyBackendStream>(proxy_backend);
+ quic_backend_stream_->set_delegate(this);
+ quic_backend_stream_->Initialize(connection_id(), stream_id(), peer_host());
+ }
+
+ QuicHttpProxyBackendStream* get_proxy_backend_stream() const {
+ return quic_backend_stream_.get();
+ }
+
+ const net::HttpRequestHeaders& get_request_headers() const {
+ return quic_backend_stream_->request_headers();
+ }
+
+ void StartHttpRequestToBackendAndWait(
+ spdy::SpdyHeaderBlock* incoming_request_headers,
+ const std::string& incoming_body) {
+ send_success_ = quic_backend_stream_->SendRequestToBackend(
+ incoming_request_headers, incoming_body);
+ EXPECT_TRUE(send_success_);
+ WaitForComplete();
+ }
+
+ void WaitForComplete() {
+ EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
+ run_loop_.Run();
+ }
+
+ 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_TRUE(task_runner_->BelongsToCurrentThread());
+ EXPECT_FALSE(did_complete_);
+ EXPECT_TRUE(quic_backend_stream_);
+ did_complete_ = true;
+ task_runner_->PostTask(FROM_HERE, run_loop_.QuitClosure());
+ }
+
+ private:
+ bool send_success_;
+ bool did_complete_;
+ std::unique_ptr<QuicHttpProxyBackendStream> quic_backend_stream_;
+ base::test::ScopedTaskEnvironment scoped_task_environment;
+ const scoped_refptr<base::SingleThreadTaskRunner> task_runner_ =
+ base::ThreadTaskRunnerHandle::Get();
+ base::RunLoop run_loop_;
+};
+
+class QuicHttpProxyBackendStreamTest : public QuicTest {
+ public:
+ QuicHttpProxyBackendStreamTest() {}
+
+ ~QuicHttpProxyBackendStreamTest() override {}
+
+ // testing::Test:
+ void SetUp() override {
+ SetUpServer();
+ ASSERT_TRUE(test_server_->Start());
+
+ backend_url_ = base::StringPrintf("http://127.0.0.1:%d",
+ test_server_->host_port_pair().port());
+ CreateTestBackendProxy();
+ CreateTestBackendProxyToTestFailure();
+ }
+
+ void CreateTestBackendProxy() {
+ ASSERT_TRUE(GURL(backend_url_).is_valid());
+ proxy_backend_ = std::make_unique<QuicHttpProxyBackend>();
+ proxy_backend_->InitializeBackend(backend_url_);
+ }
+
+ void CreateTestBackendProxyToTestFailure() {
+ // To test against a non-running backend http server
+ std::string backend_fail_url =
+ base::StringPrintf("http://127.0.0.1:%d", 52);
+ ASSERT_TRUE(GURL(backend_fail_url).is_valid());
+ proxy_backend_fail_ = std::make_unique<QuicHttpProxyBackend>();
+ proxy_backend_fail_->InitializeBackend(backend_fail_url);
+ }
+
+ // Initializes |test_server_| without starting it. Allows subclasses to use
+ // their own server configuration.
+ void SetUpServer() {
+ test_server_.reset(new EmbeddedTestServer);
+ test_server_->AddDefaultHandlers(base::FilePath());
+ test_server_->RegisterDefaultHandler(base::BindRepeating(
+ &net::test_server::HandlePrefixedRequest, "/defaultresponselarge",
+ base::BindRepeating(&HandleDefaultResponseLarge)));
+ }
+
+ protected:
+ std::string backend_url_;
+ std::unique_ptr<QuicHttpProxyBackend> proxy_backend_;
+ std::unique_ptr<QuicHttpProxyBackend> proxy_backend_fail_;
+ std::unique_ptr<EmbeddedTestServer> test_server_;
+};
+
+TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendGetDefault) {
+ spdy::SpdyHeaderBlock request_headers;
+ request_headers[":path"] = kDefaultResponsePath;
+ request_headers[":authority"] = "www.example.org";
+ request_headers[":version"] = "HTTP/1.1";
+ request_headers[":method"] = "GET";
+
+ TestQuicServerStreamDelegate delegate;
+ delegate.CreateProxyBackendResponseStreamForTest(proxy_backend_.get());
+ delegate.StartHttpRequestToBackendAndWait(&request_headers, "");
+
+ quic::QuicBackendResponse* quic_response =
+ delegate.get_proxy_backend_stream()->GetBackendResponse();
+ EXPECT_EQ(quic::QuicBackendResponse::REGULAR_RESPONSE,
+ quic_response->response_type());
+ EXPECT_EQ(200, ParseHeaderStatusCode(quic_response->headers()));
+ EXPECT_EQ(kDefaultResponseBody, quic_response->body());
+}
+
+TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendGetLarge) {
+ spdy::SpdyHeaderBlock request_headers;
+ request_headers[":path"] = "/defaultresponselarge";
+ request_headers[":authority"] = "www.example.org";
+ request_headers[":version"] = "HTTP/1.1";
+ request_headers[":method"] = "GET";
+
+ TestQuicServerStreamDelegate delegate;
+ delegate.CreateProxyBackendResponseStreamForTest(proxy_backend_.get());
+ delegate.StartHttpRequestToBackendAndWait(&request_headers, "");
+
+ quic::QuicBackendResponse* quic_response =
+ delegate.get_proxy_backend_stream()->GetBackendResponse();
+ EXPECT_EQ(quic::QuicBackendResponse::REGULAR_RESPONSE,
+ quic_response->response_type());
+ EXPECT_EQ(200, ParseHeaderStatusCode(quic_response->headers()));
+ // kLargeResponseBody should be populated with huge response
+ // already in HandleDefaultResponseLarge()
+ EXPECT_EQ(kLargeResponseBody, quic_response->body());
+}
+
+TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendPostBody) {
+ const char kUploadData[] = "bobsyeruncle";
+ spdy::SpdyHeaderBlock request_headers;
+ request_headers[":path"] = "/echo";
+ request_headers[":version"] = "HTTP/2.0";
+ request_headers[":version"] = "HTTP/1.1";
+ request_headers[":method"] = "POST";
+ request_headers["content-length"] = "12";
+ request_headers["content-type"] = "application/x-www-form-urlencoded";
+
+ TestQuicServerStreamDelegate delegate;
+ delegate.CreateProxyBackendResponseStreamForTest(proxy_backend_.get());
+ delegate.StartHttpRequestToBackendAndWait(&request_headers, kUploadData);
+
+ quic::QuicBackendResponse* quic_response =
+ delegate.get_proxy_backend_stream()->GetBackendResponse();
+
+ EXPECT_EQ(quic::QuicBackendResponse::REGULAR_RESPONSE,
+ quic_response->response_type());
+ EXPECT_EQ(200, ParseHeaderStatusCode(quic_response->headers()));
+ EXPECT_EQ(kUploadData, quic_response->body());
+}
+
+TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendPostEmptyString) {
+ const char kUploadData[] = "";
+ spdy::SpdyHeaderBlock request_headers;
+ request_headers[":path"] = "/echo";
+ request_headers[":authority"] = "www.example.org";
+ request_headers[":version"] = "HTTP/2.0";
+ request_headers[":method"] = "POST";
+ request_headers["content-length"] = "0";
+ request_headers["content-type"] = "application/x-www-form-urlencoded";
+
+ TestQuicServerStreamDelegate delegate;
+ delegate.CreateProxyBackendResponseStreamForTest(proxy_backend_.get());
+ delegate.StartHttpRequestToBackendAndWait(&request_headers, kUploadData);
+
+ quic::QuicBackendResponse* quic_response =
+ delegate.get_proxy_backend_stream()->GetBackendResponse();
+
+ EXPECT_EQ(quic::QuicBackendResponse::REGULAR_RESPONSE,
+ quic_response->response_type());
+ EXPECT_EQ(200, ParseHeaderStatusCode(quic_response->headers()));
+ EXPECT_EQ(kUploadData, quic_response->body());
+}
+
+TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendPostFile) {
+ std::string kUploadData;
+ base::FilePath upload_path = GetUploadFileTestPath();
+ ASSERT_TRUE(base::ReadFileToString(upload_path, &kUploadData));
+
+ spdy::SpdyHeaderBlock request_headers;
+ request_headers[":path"] = "/echo";
+ request_headers[":authority"] = "www.example.org";
+ request_headers[":version"] = "HTTP/2.0";
+ request_headers[":method"] = "POST";
+ request_headers["content-type"] = "application/x-www-form-urlencoded";
+
+ TestQuicServerStreamDelegate delegate;
+ delegate.CreateProxyBackendResponseStreamForTest(proxy_backend_.get());
+ delegate.StartHttpRequestToBackendAndWait(&request_headers, kUploadData);
+
+ quic::QuicBackendResponse* quic_response =
+ delegate.get_proxy_backend_stream()->GetBackendResponse();
+
+ EXPECT_EQ(quic::QuicBackendResponse::REGULAR_RESPONSE,
+ quic_response->response_type());
+ EXPECT_EQ(200, ParseHeaderStatusCode(quic_response->headers()));
+ EXPECT_EQ(kUploadData, quic_response->body());
+}
+
+TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendResponse500) {
+ const char kUploadData[] = "bobsyeruncle";
+ spdy::SpdyHeaderBlock request_headers;
+ request_headers[":path"] = "/echo?status=500";
+ request_headers[":authority"] = "www.example.org";
+ request_headers[":version"] = "HTTP/2.0";
+ request_headers[":method"] = "POST";
+
+ TestQuicServerStreamDelegate delegate;
+ delegate.CreateProxyBackendResponseStreamForTest(proxy_backend_.get());
+ delegate.StartHttpRequestToBackendAndWait(&request_headers, kUploadData);
+
+ quic::QuicBackendResponse* quic_response =
+ delegate.get_proxy_backend_stream()->GetBackendResponse();
+
+ EXPECT_EQ(quic::QuicBackendResponse::REGULAR_RESPONSE,
+ quic_response->response_type());
+ EXPECT_EQ(500, ParseHeaderStatusCode(quic_response->headers()));
+}
+
+TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendFail) {
+ const char kUploadData[] = "bobsyeruncle";
+ spdy::SpdyHeaderBlock request_headers;
+ request_headers[":path"] = "/echo";
+ request_headers[":authority"] = "www.example.org";
+ request_headers[":version"] = "HTTP/2.0";
+ request_headers[":method"] = "POST";
+
+ TestQuicServerStreamDelegate delegate;
+ delegate.CreateProxyBackendResponseStreamForTest(proxy_backend_fail_.get());
+ delegate.StartHttpRequestToBackendAndWait(&request_headers, kUploadData);
+
+ quic::QuicBackendResponse* quic_response =
+ delegate.get_proxy_backend_stream()->GetBackendResponse();
+
+ EXPECT_EQ(quic::QuicBackendResponse::BACKEND_ERR_RESPONSE,
+ quic_response->response_type());
+}
+
+TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendOnRedirect) {
+ const std::string kRedirectTarget = backend_url_.append("/echo");
+ spdy::SpdyHeaderBlock request_headers;
+ request_headers[":path"] = std::string("/server-redirect?") + kRedirectTarget;
+ request_headers[":authority"] = "www.example.org";
+ request_headers[":version"] = "HTTP/2.0";
+ request_headers[":method"] = "GET";
+
+ TestQuicServerStreamDelegate delegate;
+ delegate.CreateProxyBackendResponseStreamForTest(proxy_backend_.get());
+ delegate.StartHttpRequestToBackendAndWait(&request_headers, "");
+
+ quic::QuicBackendResponse* quic_response =
+ delegate.get_proxy_backend_stream()->GetBackendResponse();
+
+ EXPECT_EQ(quic::QuicBackendResponse::REGULAR_RESPONSE,
+ quic_response->response_type());
+ EXPECT_EQ(200, ParseHeaderStatusCode(quic_response->headers()));
+}
+
+// Ensure that the proxy rewrites the content-length when receiving a Gzipped
+// response
+TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendHandleGzip) {
+ const char kGzipData[] =
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!!";
+ uint64_t rawBodyLength = strlen(kGzipData);
+ spdy::SpdyHeaderBlock request_headers;
+ request_headers[":path"] = std::string("/gzip-body?") + kGzipData;
+ request_headers[":authority"] = "www.example.org";
+ request_headers[":version"] = "HTTP/2.0";
+ request_headers[":method"] = "GET";
+
+ TestQuicServerStreamDelegate delegate;
+ delegate.CreateProxyBackendResponseStreamForTest(proxy_backend_.get());
+ delegate.StartHttpRequestToBackendAndWait(&request_headers, "");
+
+ quic::QuicBackendResponse* quic_response =
+ delegate.get_proxy_backend_stream()->GetBackendResponse();
+
+ EXPECT_EQ(quic::QuicBackendResponse::REGULAR_RESPONSE,
+ quic_response->response_type());
+ EXPECT_EQ(200, ParseHeaderStatusCode(quic_response->headers()));
+ EXPECT_EQ(kGzipData, quic_response->body());
+ spdy::SpdyHeaderBlock quic_response_headers =
+ quic_response->headers().Clone();
+
+ // Ensure that the content length is set to the raw body size (unencoded)
+ auto responseLength = quic_response_headers.find("content-length");
+ uint64_t response_header_content_length = 0;
+ if (responseLength != quic_response_headers.end()) {
+ base::StringToUint64(responseLength->second,
+ &response_header_content_length);
+ }
+ EXPECT_EQ(rawBodyLength, response_header_content_length);
+
+ // Ensure the content-encoding header is removed for the quic response
+ EXPECT_EQ(quic_response_headers.end(),
+ quic_response_headers.find("content-encoding"));
+}
+
+// Ensure cookies are not saved/updated at the proxy
+TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendCookiesNotSaved) {
+ spdy::SpdyHeaderBlock request_headers;
+ request_headers[":authority"] = "www.example.org";
+ request_headers[":method"] = "GET";
+
+ {
+ TestQuicServerStreamDelegate delegate;
+ request_headers[":path"] =
+ "/set-cookie?CookieToNotSave=1&CookieToNotUpdate=1";
+ delegate.CreateProxyBackendResponseStreamForTest(proxy_backend_.get());
+ delegate.StartHttpRequestToBackendAndWait(&request_headers, "");
+
+ quic::QuicBackendResponse* quic_response =
+ delegate.get_proxy_backend_stream()->GetBackendResponse();
+
+ EXPECT_EQ(200, ParseHeaderStatusCode(quic_response->headers()));
+ spdy::SpdyHeaderBlock quic_response_headers =
+ quic_response->headers().Clone();
+ EXPECT_TRUE(quic_response_headers.end() !=
+ quic_response_headers.find("set-cookie"));
+ auto cookie = quic_response_headers.find("set-cookie");
+ EXPECT_TRUE(cookie->second.find("CookieToNotSave=1") != std::string::npos);
+ EXPECT_TRUE(cookie->second.find("CookieToNotUpdate=1") !=
+ std::string::npos);
+ }
+ {
+ TestQuicServerStreamDelegate delegate;
+ request_headers[":path"] = "/echoheader?Cookie";
+ delegate.CreateProxyBackendResponseStreamForTest(proxy_backend_.get());
+ delegate.StartHttpRequestToBackendAndWait(&request_headers, "");
+
+ quic::QuicBackendResponse* quic_response =
+ delegate.get_proxy_backend_stream()->GetBackendResponse();
+
+ EXPECT_EQ(200, ParseHeaderStatusCode(quic_response->headers()));
+ EXPECT_TRUE(quic_response->body().find("CookieToNotSave=1") ==
+ std::string::npos);
+ EXPECT_TRUE(quic_response->body().find("CookieToNotUpdate=1") ==
+ std::string::npos);
+ }
+}
+
+// Ensure hop-by-hop headers are removed from the request and response to the
+// backend
+TEST_F(QuicHttpProxyBackendStreamTest, SendRequestToBackendHopHeaders) {
+ spdy::SpdyHeaderBlock request_headers;
+ request_headers[":path"] = "/echoall";
+ request_headers[":authority"] = "www.example.org";
+ request_headers[":method"] = "GET";
+ std::set<std::string>::iterator it;
+ for (it = QuicHttpProxyBackendStream::kHopHeaders.begin();
+ it != QuicHttpProxyBackendStream::kHopHeaders.end(); ++it) {
+ request_headers[*it] = "SomeString";
+ }
+
+ TestQuicServerStreamDelegate delegate;
+ delegate.CreateProxyBackendResponseStreamForTest(proxy_backend_.get());
+ delegate.StartHttpRequestToBackendAndWait(&request_headers, "");
+ const net::HttpRequestHeaders& actual_request_headers =
+ delegate.get_request_headers();
+ for (it = QuicHttpProxyBackendStream::kHopHeaders.begin();
+ it != QuicHttpProxyBackendStream::kHopHeaders.end(); ++it) {
+ EXPECT_FALSE(actual_request_headers.HasHeader(*it));
+ }
+
+ quic::QuicBackendResponse* quic_response =
+ delegate.get_proxy_backend_stream()->GetBackendResponse();
+ EXPECT_EQ(200, ParseHeaderStatusCode(quic_response->headers()));
+ spdy::SpdyHeaderBlock quic_response_headers =
+ quic_response->headers().Clone();
+ for (it = QuicHttpProxyBackendStream::kHopHeaders.begin();
+ it != QuicHttpProxyBackendStream::kHopHeaders.end(); ++it) {
+ EXPECT_EQ(quic_response_headers.end(), quic_response_headers.find(*it));
+ }
+}
+
+} // namespace test
+} // namespace net \ No newline at end of file
diff --git a/chromium/net/tools/quic/quic_http_proxy_backend_test.cc b/chromium/net/tools/quic/quic_http_proxy_backend_test.cc
new file mode 100644
index 00000000000..7aa833b2171
--- /dev/null
+++ b/chromium/net/tools/quic/quic_http_proxy_backend_test.cc
@@ -0,0 +1,139 @@
+// 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
diff --git a/chromium/net/tools/quic/quic_simple_client.cc b/chromium/net/tools/quic/quic_simple_client.cc
index ac17ee6c6a9..40f2f8d9992 100644
--- a/chromium/net/tools/quic/quic_simple_client.cc
+++ b/chromium/net/tools/quic/quic_simple_client.cc
@@ -14,17 +14,17 @@
#include "net/http/http_response_info.h"
#include "net/log/net_log_source.h"
#include "net/log/net_log_with_source.h"
-#include "net/quic/chromium/quic_chromium_alarm_factory.h"
-#include "net/quic/chromium/quic_chromium_connection_helper.h"
-#include "net/quic/chromium/quic_chromium_packet_reader.h"
-#include "net/quic/chromium/quic_chromium_packet_writer.h"
+#include "net/quic/quic_chromium_alarm_factory.h"
+#include "net/quic/quic_chromium_connection_helper.h"
+#include "net/quic/quic_chromium_packet_reader.h"
+#include "net/quic/quic_chromium_packet_writer.h"
#include "net/socket/udp_client_socket.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/third_party/quic/core/crypto/quic_random.h"
+#include "net/third_party/quic/core/http/spdy_utils.h"
#include "net/third_party/quic/core/quic_connection.h"
#include "net/third_party/quic/core/quic_packets.h"
#include "net/third_party/quic/core/quic_server_id.h"
-#include "net/third_party/quic/core/spdy_utils.h"
#include "net/third_party/quic/platform/api/quic_flags.h"
#include "net/third_party/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/spdy/core/spdy_header_block.h"
diff --git a/chromium/net/tools/quic/quic_simple_client.h b/chromium/net/tools/quic/quic_simple_client.h
index d9144b369b7..27ba483da50 100644
--- a/chromium/net/tools/quic/quic_simple_client.h
+++ b/chromium/net/tools/quic/quic_simple_client.h
@@ -19,9 +19,9 @@
#include "net/base/ip_endpoint.h"
#include "net/http/http_response_headers.h"
#include "net/log/net_log.h"
-#include "net/quic/chromium/quic_chromium_packet_reader.h"
+#include "net/quic/quic_chromium_packet_reader.h"
+#include "net/third_party/quic/core/http/quic_spdy_stream.h"
#include "net/third_party/quic/core/quic_config.h"
-#include "net/third_party/quic/core/quic_spdy_stream.h"
#include "net/third_party/quic/platform/impl/quic_chromium_clock.h"
#include "net/third_party/quic/tools/quic_spdy_client_base.h"
#include "net/tools/quic/quic_client_message_loop_network_helper.h"
diff --git a/chromium/net/tools/quic/quic_simple_client_bin.cc b/chromium/net/tools/quic/quic_simple_client_bin.cc
index aeb533651f0..956b612e012 100644
--- a/chromium/net/tools/quic/quic_simple_client_bin.cc
+++ b/chromium/net/tools/quic/quic_simple_client_bin.cc
@@ -44,7 +44,7 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
-#include "base/task_scheduler/task_scheduler.h"
+#include "base/task/task_scheduler/task_scheduler.h"
#include "net/base/net_errors.h"
#include "net/base/privacy_mode.h"
#include "net/cert/cert_verifier.h"
@@ -52,7 +52,7 @@
#include "net/cert/ct_policy_enforcer.h"
#include "net/cert/multi_log_ct_verifier.h"
#include "net/http/transport_security_state.h"
-#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/crypto/proof_verifier_chromium.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/third_party/quic/core/quic_error_codes.h"
#include "net/third_party/quic/core/quic_packets.h"
@@ -132,6 +132,10 @@ class FakeProofVerifier : public quic::ProofVerifier {
std::unique_ptr<quic::ProofVerifierCallback> callback) override {
return quic::QUIC_SUCCESS;
}
+
+ std::unique_ptr<quic::ProofVerifyContext> CreateDefaultContext() override {
+ return nullptr;
+ }
};
int main(int argc, char* argv[]) {
diff --git a/chromium/net/tools/quic/quic_simple_server.cc b/chromium/net/tools/quic/quic_simple_server.cc
index 2d1c7042d84..327fd42299c 100644
--- a/chromium/net/tools/quic/quic_simple_server.cc
+++ b/chromium/net/tools/quic/quic_simple_server.cc
@@ -55,10 +55,11 @@ QuicSimpleServer::QuicSimpleServer(
crypto_config_(kSourceAddressTokenSecret,
quic::QuicRandom::GetInstance(),
std::move(proof_source),
+ quic::KeyExchangeSource::Default(),
quic::TlsServerHandshaker::CreateSslCtx()),
read_pending_(false),
synchronous_read_count_(0),
- read_buffer_(new IOBufferWithSize(kReadBufferSize)),
+ read_buffer_(base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize)),
quic_simple_server_backend_(quic_simple_server_backend),
weak_factory_(this) {
Initialize();
diff --git a/chromium/net/tools/quic/quic_simple_server.h b/chromium/net/tools/quic/quic_simple_server.h
index 9e6fde1826e..1ce6eafcc44 100644
--- a/chromium/net/tools/quic/quic_simple_server.h
+++ b/chromium/net/tools/quic/quic_simple_server.h
@@ -14,8 +14,8 @@
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
#include "net/log/net_log.h"
-#include "net/quic/chromium/quic_chromium_alarm_factory.h"
-#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/quic_chromium_alarm_factory.h"
+#include "net/quic/quic_chromium_connection_helper.h"
#include "net/third_party/quic/core/crypto/quic_crypto_server_config.h"
#include "net/third_party/quic/core/quic_config.h"
#include "net/third_party/quic/core/quic_version_manager.h"
diff --git a/chromium/net/tools/quic/quic_simple_server_bin.cc b/chromium/net/tools/quic/quic_simple_server_bin.cc
index 42cc3cada44..55f73865708 100644
--- a/chromium/net/tools/quic/quic_simple_server_bin.cc
+++ b/chromium/net/tools/quic/quic_simple_server_bin.cc
@@ -13,12 +13,14 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
-#include "base/task_scheduler/task_scheduler.h"
+#include "base/task/task_scheduler/task_scheduler.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/chromium/crypto/proof_source_chromium.h"
+#include "net/quic/crypto/proof_source_chromium.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_simple_server_backend.h"
+#include "net/tools/quic/quic_http_proxy_backend.h"
#include "net/tools/quic/quic_simple_server.h"
// The port the quic server will listen on.
@@ -29,6 +31,9 @@ std::string FLAGS_quic_mode = "cache";
// construction to seed the cache. Cache directory can be
// generated using `wget -p --save-headers <url>`
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(
const base::FilePath& cert_path,
@@ -58,20 +63,26 @@ int main(int argc, char* argv[]) {
"Options:\n"
"-h, --help show this help message and exit\n"
"--port=<port> specify the port to listen on\n"
- "--mode=<cache> Default: cache\n"
- " Specify mode of operation: Cache will "
- "serve it "
+ "--mode=<cache|proxy> Specify mode of operation: Proxy will "
+ "serve response from\n"
+ " a backend server and Cache will serve it "
"from a cache dir\n"
"--quic_response_cache_dir=<directory>\n"
" The directory containing cached response "
"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"
"--key_file=<file> path to the pkcs8 private key\n";
std::cout << help_str;
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")) {
FLAGS_quic_mode = line->GetSwitchValueASCII("mode");
}
@@ -79,13 +90,28 @@ int main(int argc, char* argv[]) {
if (line->HasSwitch("quic_response_cache_dir")) {
FLAGS_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() ||
- memory_cache_backend.InitializeBackend(
+ quic_simple_server_backend->InitializeBackend(
FLAGS_quic_response_cache_dir) != true) {
LOG(ERROR) << "--quic_response_cache_dir is not valid !";
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 {
LOG(ERROR) << "unknown --mode. cache is a valid mode of operation";
return 1;
@@ -115,7 +141,7 @@ int main(int argc, char* argv[]) {
CreateProofSource(line->GetSwitchValuePath("certificate_file"),
line->GetSwitchValuePath("key_file")),
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));
if (rc < 0) {
diff --git a/chromium/net/tools/quic/quic_simple_server_packet_writer.cc b/chromium/net/tools/quic/quic_simple_server_packet_writer.cc
index 803751b656e..24e538d44e2 100644
--- a/chromium/net/tools/quic/quic_simple_server_packet_writer.cc
+++ b/chromium/net/tools/quic/quic_simple_server_packet_writer.cc
@@ -72,8 +72,8 @@ quic::WriteResult QuicSimpleServerPacketWriter::WritePacket(
const quic::QuicIpAddress& self_address,
const quic::QuicSocketAddress& peer_address,
quic::PerPacketOptions* options) {
- scoped_refptr<StringIOBuffer> buf(
- new StringIOBuffer(std::string(buffer, buf_len)));
+ scoped_refptr<StringIOBuffer> buf =
+ base::MakeRefCounted<StringIOBuffer>(std::string(buffer, buf_len));
DCHECK(!IsWriteBlocked());
int rv;
if (buf_len <= static_cast<size_t>(std::numeric_limits<int>::max())) {
diff --git a/chromium/net/tools/quic/quic_simple_server_session_helper.h b/chromium/net/tools/quic/quic_simple_server_session_helper.h
index b176e26816c..46f3b6597e2 100644
--- a/chromium/net/tools/quic/quic_simple_server_session_helper.h
+++ b/chromium/net/tools/quic/quic_simple_server_session_helper.h
@@ -6,7 +6,7 @@
#define NET_TOOLS_QUIC_QUIC_SIMPLE_SERVER_SESSION_HELPER_H_
#include "net/third_party/quic/core/crypto/quic_random.h"
-#include "net/third_party/quic/core/quic_server_session_base.h"
+#include "net/third_party/quic/core/http/quic_server_session_base.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_simple_server_test.cc b/chromium/net/tools/quic/quic_simple_server_test.cc
index 0b64733af8a..50151f89a96 100644
--- a/chromium/net/tools/quic/quic_simple_server_test.cc
+++ b/chromium/net/tools/quic/quic_simple_server_test.cc
@@ -28,6 +28,7 @@ class QuicChromeServerDispatchPacketTest : public QuicTest {
: crypto_config_("blah",
quic::QuicRandom::GetInstance(),
quic::test::crypto_test_utils::ProofSourceForTesting(),
+ quic::KeyExchangeSource::Default(),
quic::TlsServerHandshaker::CreateSslCtx()),
version_manager_(quic::AllSupportedVersions()),
dispatcher_(config_,
diff --git a/chromium/net/tools/stress_cache/stress_cache.cc b/chromium/net/tools/stress_cache/stress_cache.cc
index 414047ed0ad..76446e48774 100644
--- a/chromium/net/tools/stress_cache/stress_cache.cc
+++ b/chromium/net/tools/stress_cache/stress_cache.cc
@@ -123,7 +123,7 @@ enum Operation { NONE, OPEN, CREATE, READ, WRITE, DOOM };
class EntryWrapper {
public:
EntryWrapper() : entry_(nullptr), state_(NONE) {
- buffer_ = new net::IOBuffer(kBufferSize);
+ buffer_ = base::MakeRefCounted<net::IOBuffer>(kBufferSize);
memset(buffer_->data(), 'k', kBufferSize);
}
diff --git a/chromium/net/tools/testserver/testserver.py b/chromium/net/tools/testserver/testserver.py
index 92ca87cc703..cf55990a24f 100755
--- a/chromium/net/tools/testserver/testserver.py
+++ b/chromium/net/tools/testserver/testserver.py
@@ -3,8 +3,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""This is a simple HTTP/FTP/TCP/UDP/BASIC_AUTH_PROXY/WEBSOCKET server used for
-testing Chrome.
+"""This is a simple HTTP/FTP/TCP/UDP/PROXY/BASIC_AUTH_PROXY/WEBSOCKET server
+used for testing Chrome.
It supports several test URLs, as specified by the handlers in TestPageHandler.
By default, it listens on an ephemeral port and sends the port number back to
@@ -64,6 +64,7 @@ SERVER_TCP_ECHO = 2
SERVER_UDP_ECHO = 3
SERVER_BASIC_AUTH_PROXY = 4
SERVER_WEBSOCKET = 5
+SERVER_PROXY = 6
# Default request queue size for WebSocketServer.
_DEFAULT_REQUEST_QUEUE_SIZE = 128
@@ -1759,29 +1760,13 @@ class UDPEchoHandler(SocketServer.BaseRequestHandler):
request_socket.sendto(return_data, self.client_address)
-class BasicAuthProxyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- """A request handler that behaves as a proxy server which requires
- basic authentication. Only CONNECT, GET and HEAD is supported for now.
+class ProxyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ """A request handler that behaves as a proxy server. Only CONNECT, GET and
+ HEAD methods are supported.
"""
- _AUTH_CREDENTIAL = 'Basic Zm9vOmJhcg==' # foo:bar
redirect_connect_to_localhost = False;
- def parse_request(self):
- """Overrides parse_request to check credential."""
-
- if not BaseHTTPServer.BaseHTTPRequestHandler.parse_request(self):
- return False
-
- auth = self.headers.getheader('Proxy-Authorization')
- if auth != self._AUTH_CREDENTIAL:
- self.send_response(407)
- self.send_header('Proxy-Authenticate', 'Basic realm="MyRealm1"')
- self.end_headers()
- return False
-
- return True
-
def _start_read_write(self, sock):
sock.setblocking(0)
self.request.setblocking(0)
@@ -1860,7 +1845,7 @@ class BasicAuthProxyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
self.send_response(400)
self.end_headers()
- if BasicAuthProxyRequestHandler.redirect_connect_to_localhost:
+ if ProxyRequestHandler.redirect_connect_to_localhost:
host = "127.0.0.1"
sock = None
@@ -1883,6 +1868,28 @@ class BasicAuthProxyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_HEAD(self):
self._do_common_method()
+class BasicAuthProxyRequestHandler(ProxyRequestHandler):
+ """A request handler that behaves as a proxy server which requires
+ basic authentication.
+ """
+
+ _AUTH_CREDENTIAL = 'Basic Zm9vOmJhcg==' # foo:bar
+
+ def parse_request(self):
+ """Overrides parse_request to check credential."""
+
+ if not ProxyRequestHandler.parse_request(self):
+ return False
+
+ auth = self.headers.getheader('Proxy-Authorization')
+ if auth != self._AUTH_CREDENTIAL:
+ self.send_response(407)
+ self.send_header('Proxy-Authenticate', 'Basic realm="MyRealm1"')
+ self.end_headers()
+ return False
+
+ return True
+
class ServerRunner(testserver_base.TestServerRunner):
"""TestServerRunner for the net test servers."""
@@ -2172,8 +2179,14 @@ class ServerRunner(testserver_base.TestServerRunner):
server = UDPEchoServer((host, port), UDPEchoHandler)
print 'Echo UDP server started on port %d...' % server.server_port
server_data['port'] = server.server_port
+ elif self.options.server_type == SERVER_PROXY:
+ ProxyRequestHandler.redirect_connect_to_localhost = \
+ self.options.redirect_connect_to_localhost
+ server = ThreadingHTTPServer((host, port), ProxyRequestHandler)
+ print 'Proxy server started on port %d...' % server.server_port
+ server_data['port'] = server.server_port
elif self.options.server_type == SERVER_BASIC_AUTH_PROXY:
- BasicAuthProxyRequestHandler.redirect_connect_to_localhost = \
+ ProxyRequestHandler.redirect_connect_to_localhost = \
self.options.redirect_connect_to_localhost
server = ThreadingHTTPServer((host, port), BasicAuthProxyRequestHandler)
print 'BasicAuthProxy server started on port %d...' % server.server_port
@@ -2232,6 +2245,10 @@ class ServerRunner(testserver_base.TestServerRunner):
const=SERVER_UDP_ECHO, default=SERVER_HTTP,
dest='server_type',
help='start up a udp echo server.')
+ self.option_parser.add_option('--proxy', action='store_const',
+ const=SERVER_PROXY,
+ default=SERVER_HTTP, dest='server_type',
+ help='start up a proxy server.')
self.option_parser.add_option('--basic-auth-proxy', action='store_const',
const=SERVER_BASIC_AUTH_PROXY,
default=SERVER_HTTP, dest='server_type',