blob: 7f0a8b0b8c6e47ef7a1c00f5d66312ca5973b180 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/masque/masque_server_backend.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
namespace quic {
namespace {
std::string GetRequestHandlerKey(
const QuicSimpleServerBackend::RequestHandler* request_handler) {
return QuicStrCat(request_handler->connection_id().ToString(), "_",
request_handler->stream_id(), "_",
request_handler->peer_host());
}
} // namespace
MasqueServerBackend::MasqueServerBackend(const std::string& server_authority,
const std::string& cache_directory)
: server_authority_(server_authority) {
if (!cache_directory.empty()) {
QuicMemoryCacheBackend::InitializeBackend(cache_directory);
}
}
bool MasqueServerBackend::MaybeHandleMasqueRequest(
const spdy::SpdyHeaderBlock& request_headers,
const std::string& request_body,
QuicSimpleServerBackend::RequestHandler* request_handler) {
auto path_pair = request_headers.find(":path");
auto method_pair = request_headers.find(":method");
auto scheme_pair = request_headers.find(":scheme");
if (path_pair == request_headers.end() ||
method_pair == request_headers.end() ||
scheme_pair == request_headers.end()) {
// This request is missing required headers.
return false;
}
spdy::SpdyStringPiece path = path_pair->second;
spdy::SpdyStringPiece scheme = scheme_pair->second;
spdy::SpdyStringPiece method = method_pair->second;
if (scheme != "https" || method != "POST" || request_body.empty()) {
// MASQUE requests MUST be a non-empty https POST.
return false;
}
if (path.rfind("/.well-known/masque/", 0) != 0) {
// This request is not a MASQUE path.
return false;
}
std::string masque_path(path.substr(sizeof("/.well-known/masque/") - 1));
if (!server_authority_.empty()) {
auto authority_pair = request_headers.find(":authority");
if (authority_pair == request_headers.end()) {
// Cannot enforce missing authority.
return false;
}
spdy::SpdyStringPiece authority = authority_pair->second;
if (server_authority_ != authority) {
// This request does not match server_authority.
return false;
}
}
auto backend_client_pair =
backend_clients_.find(request_handler->connection_id());
if (backend_client_pair == backend_clients_.end()) {
QUIC_LOG(ERROR) << "Could not find backend client for "
<< GetRequestHandlerKey(request_handler) << " "
<< masque_path << request_headers.DebugString();
return false;
}
BackendClient* backend_client = backend_client_pair->second;
std::unique_ptr<QuicBackendResponse> response =
backend_client->HandleMasqueRequest(masque_path, request_headers,
request_body, request_handler);
if (response == nullptr) {
QUIC_LOG(ERROR) << "Backend client did not process request for "
<< GetRequestHandlerKey(request_handler) << " "
<< masque_path << request_headers.DebugString();
return false;
}
QUIC_DLOG(INFO) << "Sending MASQUE response for "
<< GetRequestHandlerKey(request_handler) << " " << masque_path
<< request_headers.DebugString();
request_handler->OnResponseBackendComplete(response.get(), {});
active_response_map_[GetRequestHandlerKey(request_handler)] =
std::move(response);
return true;
}
void MasqueServerBackend::FetchResponseFromBackend(
const spdy::SpdyHeaderBlock& request_headers,
const std::string& request_body,
QuicSimpleServerBackend::RequestHandler* request_handler) {
if (MaybeHandleMasqueRequest(request_headers, request_body,
request_handler)) {
// Request was handled as a MASQUE request.
return;
}
QUIC_DLOG(INFO) << "Fetching non-MASQUE response for "
<< GetRequestHandlerKey(request_handler)
<< request_headers.DebugString();
QuicMemoryCacheBackend::FetchResponseFromBackend(
request_headers, request_body, request_handler);
}
void MasqueServerBackend::CloseBackendResponseStream(
QuicSimpleServerBackend::RequestHandler* request_handler) {
QUIC_DLOG(INFO) << "Closing response stream for "
<< GetRequestHandlerKey(request_handler);
active_response_map_.erase(GetRequestHandlerKey(request_handler));
QuicMemoryCacheBackend::CloseBackendResponseStream(request_handler);
}
void MasqueServerBackend::RegisterBackendClient(QuicConnectionId connection_id,
BackendClient* backend_client) {
QUIC_BUG_IF(backend_clients_.find(connection_id) != backend_clients_.end())
<< connection_id << " already in backend clients map";
backend_clients_[connection_id] = backend_client;
QUIC_DLOG(INFO) << "Registering backend client for " << connection_id;
}
void MasqueServerBackend::RemoveBackendClient(QuicConnectionId connection_id) {
backend_clients_.erase(connection_id);
QUIC_DLOG(INFO) << "Removing backend client for " << connection_id;
}
} // namespace quic