mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-25 06:46:09 +03:00
192 lines
6.7 KiB
C++
192 lines
6.7 KiB
C++
|
// 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
|