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

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

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

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

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

Change-Id: I79b7d66eb6bba9628d99181def004c0a5ea2e214
Reviewed-on: https://chromium-review.googlesource.com/1128323
Commit-Queue: Ryan Hamilton <rch@chromium.org>
Reviewed-by: Ryan Hamilton <rch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577650}
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 9c8dee6..957272b 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -3232,6 +3232,10 @@
     "third_party/quic/tools/quic_spdy_client_base.h",
     "tools/quic/quic_client_message_loop_network_helper.cc",
     "tools/quic/quic_client_message_loop_network_helper.h",
+    "tools/quic/quic_http_proxy_backend.cc",
+    "tools/quic/quic_http_proxy_backend.h",
+    "tools/quic/quic_http_proxy_backend_stream.cc",
+    "tools/quic/quic_http_proxy_backend_stream.h",
     "tools/quic/quic_simple_client.cc",
     "tools/quic/quic_simple_client.h",
     "tools/quic/quic_simple_per_connection_packet_writer.cc",
@@ -5283,6 +5287,8 @@
       "third_party/quic/tools/quic_server_test.cc",
       "third_party/quic/tools/quic_simple_server_session_test.cc",
       "third_party/quic/tools/quic_simple_server_stream_test.cc",
+      "tools/quic/quic_http_proxy_backend_stream_test.cc",
+      "tools/quic/quic_http_proxy_backend_test.cc",
       "tools/quic/quic_simple_server_session_helper_test.cc",
       "tools/quic/quic_simple_server_test.cc",
     ]
diff --git a/net/tools/quic/quic_http_proxy_backend.cc b/net/tools/quic/quic_http_proxy_backend.cc
new file mode 100644
index 0000000..610c98f
--- /dev/null
+++ b/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/net/tools/quic/quic_http_proxy_backend.h b/net/tools/quic/quic_http_proxy_backend.h
new file mode 100644
index 0000000..c5811e6
--- /dev/null
+++ b/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/net/tools/quic/quic_http_proxy_backend_stream.cc b/net/tools/quic/quic_http_proxy_backend_stream.cc
new file mode 100644
index 0000000..419ce5b
--- /dev/null
+++ b/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_(new 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/net/tools/quic/quic_http_proxy_backend_stream.h b/net/tools/quic/quic_http_proxy_backend_stream.h
new file mode 100644
index 0000000..a231433
--- /dev/null
+++ b/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/net/tools/quic/quic_http_proxy_backend_stream_test.cc b/net/tools/quic/quic_http_proxy_backend_stream_test.cc
new file mode 100644
index 0000000..ef2d507
--- /dev/null
+++ b/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/net/tools/quic/quic_http_proxy_backend_test.cc b/net/tools/quic/quic_http_proxy_backend_test.cc
new file mode 100644
index 0000000..7aa833b
--- /dev/null
+++ b/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/net/tools/quic/quic_simple_server_bin.cc b/net/tools/quic/quic_simple_server_bin.cc
index 42cc3ca..14f2375 100644
--- a/net/tools/quic/quic_simple_server_bin.cc
+++ b/net/tools/quic/quic_simple_server_bin.cc
@@ -19,6 +19,8 @@
 #include "net/quic/chromium/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 @@
 // 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 @@
         "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 @@
     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 @@
       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) {