123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- // Copyright 2022 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 "ash/components/drivefs/drivefs_http_client.h"
- #include <cstdint>
- #include <memory>
- #include <type_traits>
- #include <utility>
- #include "ash/components/drivefs/mojom/drivefs.mojom.h"
- #include "base/bind.h"
- #include "base/containers/enum_set.h"
- #include "mojo/public/cpp/bindings/pending_receiver.h"
- #include "mojo/public/cpp/bindings/pending_remote.h"
- #include "mojo/public/cpp/bindings/receiver.h"
- #include "mojo/public/cpp/bindings/receiver_set.h"
- #include "mojo/public/cpp/bindings/remote.h"
- #include "services/network/public/cpp/resource_request.h"
- #include "services/network/public/mojom/data_pipe_getter.mojom.h"
- #include "services/network/public/mojom/url_loader.mojom.h"
- #include "services/network/public/mojom/url_loader_factory.mojom.h"
- #include "services/network/public/mojom/url_response_head.mojom.h"
- namespace drivefs {
- namespace {
- constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
- net::DefineNetworkTrafficAnnotation("drivefs_http_client", R"(
- semantics {
- sender: "Files App - Google Drive"
- description: "Files App integrates with Google Drive to provide a "
- "local view of what is available on the Google Drive Web interface. "
- "This allows users to navigate Google Drive as if it was a local "
- "file system."
- trigger: "User navigates through the Google Drive directory in the "
- "Files App. User opens a file in the Google Drive directory in the "
- "Files App. Additionally, the Files App will sync Google Drive data "
- "in the background as changes are made on the web or on other "
- "devices."
- data: "All metadata related to files stored in Google Drive as well "
- "as content of files stored in Google Drive."
- destination: GOOGLE_OWNED_SERVICE
- }
- policy {
- cookies_allowed: NO
- chrome_policy {
- DriveDisabled: {
- DriveDisabled: true
- }
- }
- }
- comments: "There are two policies that control this integration. "
- "DriveDisabled will disable all communications while "
- "DriveDisabledOverCellular will disable communication over cellular "
- "networks"
- )");
- class DriveFsURLLoaderClient : public network::mojom::URLLoaderClient,
- public network::mojom::DataPipeGetter {
- public:
- DriveFsURLLoaderClient(
- mojo::PendingRemote<mojom::HttpDelegate> http_delegate_remote,
- const mojom::HttpRequestPtr& request,
- mojo::PendingReceiver<network::mojom::DataPipeGetter> data_pipe_receiver,
- mojo::PendingRemote<network::mojom::URLLoader> loader_remote)
- : request_body_bytes_(request->request_body_bytes),
- loader_remote_(std::move(loader_remote)),
- http_delegate_remote_(std::move(http_delegate_remote)) {
- Clone(std::move(data_pipe_receiver));
- http_delegate_remote_.set_disconnect_handler(
- base::BindOnce(&DriveFsURLLoaderClient::OnHttpDelegateDisconnect,
- weak_ptr_factory_.GetWeakPtr()));
- }
- private:
- enum class CallbackState : size_t {
- kBodyRequested,
- kResponseReceived,
- kRequestComplete,
- // Add new states above.
- kMin = kBodyRequested,
- kMax = kRequestComplete,
- };
- bool IsFirstCall(CallbackState state) {
- if (callback_state_.Has(state)) {
- return false;
- }
- callback_state_.Put(state);
- return true;
- }
- void OnHttpDelegateDisconnect() {
- // Cancel the request: The DriveFS side disconnected.
- loader_remote_.reset();
- }
- // URLLoaderClient Impl
- void OnReceiveEarlyHints(network::mojom::EarlyHintsPtr early_hints) override {
- }
- void OnReceiveResponse(network::mojom::URLResponseHeadPtr response_head,
- mojo::ScopedDataPipeConsumerHandle body) override {
- DCHECK(IsFirstCall(CallbackState::kResponseReceived));
- std::vector<mojom::HttpHeaderPtr> headers;
- size_t iter = 0;
- std::string name;
- std::string value;
- while (response_head->headers->EnumerateHeaderLines(&iter, &name, &value)) {
- headers.push_back(mojom::HttpHeader::New(name, value));
- }
- http_delegate_remote_->OnReceiveResponse(mojom::HttpResponse::New(
- response_head->headers->response_code(), std::move(headers)));
- if (body) {
- http_delegate_remote_->OnReceiveBody(std::move(body));
- }
- }
- void OnReceiveRedirect(
- const net::RedirectInfo& redirect_info,
- network::mojom::URLResponseHeadPtr response_head) override {
- // Cancel the request: Redirects are not permitted for security reasons.
- loader_remote_.reset();
- }
- void OnUploadProgress(int64_t current_position,
- int64_t total_size,
- OnUploadProgressCallback ack_callback) override {
- std::move(ack_callback).Run();
- }
- void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override {}
- void OnTransferSizeUpdated(int32_t transfer_size_diff) override {}
- void OnComplete(const network::URLLoaderCompletionStatus& status) override {
- DCHECK(IsFirstCall(CallbackState::kRequestComplete));
- http_delegate_remote_->OnRequestComplete(mojom::HttpCompletionStatus::New(
- static_cast<mojom::NetError>(status.error_code),
- status.decoded_body_length));
- }
- // DataPipeGetter Impl
- void Read(mojo::ScopedDataPipeProducerHandle pipe,
- ReadCallback callback) override {
- DCHECK(request_body_bytes_);
- DCHECK(IsFirstCall(CallbackState::kBodyRequested));
- std::move(callback).Run(net::OK, request_body_bytes_);
- http_delegate_remote_->GetRequestBody(std::move(pipe));
- }
- void Clone(
- mojo::PendingReceiver<network::mojom::DataPipeGetter> receiver) override {
- data_pipe_receivers_.Add(this, std::move(receiver));
- }
- const int64_t request_body_bytes_;
- base::EnumSet<CallbackState, CallbackState::kMin, CallbackState::kMax>
- callback_state_;
- mojo::ReceiverSet<network::mojom::DataPipeGetter> data_pipe_receivers_;
- mojo::Remote<network::mojom::URLLoader> loader_remote_;
- mojo::Remote<mojom::HttpDelegate> http_delegate_remote_;
- base::WeakPtrFactory<DriveFsURLLoaderClient> weak_ptr_factory_{this};
- };
- } // namespace
- DriveFsHttpClient::DriveFsHttpClient(
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
- : url_loader_factory_(std::move(url_loader_factory)) {}
- DriveFsHttpClient::~DriveFsHttpClient() = default;
- void DriveFsHttpClient::ExecuteHttpRequest(
- mojom::HttpRequestPtr request,
- mojo::PendingRemote<mojom::HttpDelegate> delegate) {
- // Build a `URLLoaderClient` for the request. This client will bridge
- // communication between DriveFS and Chrome OS.
- mojo::PendingRemote<network::mojom::URLLoaderClient> url_loader_client;
- mojo::PendingRemote<network::mojom::DataPipeGetter> data_pipe_getter;
- mojo::PendingRemote<network::mojom::URLLoader> url_loader;
- mojo::PendingReceiver<network::mojom::URLLoader> url_loader_reciever =
- url_loader.InitWithNewPipeAndPassReceiver();
- mojo::ReceiverId client_id =
- clients_.Add(std::make_unique<DriveFsURLLoaderClient>(
- std::move(delegate), request,
- data_pipe_getter.InitWithNewPipeAndPassReceiver(),
- std::move(url_loader)),
- url_loader_client.InitWithNewPipeAndPassReceiver());
- // Translate the `HttpRequest` from DriveFS into a `network::ResourceRequest`.
- network::ResourceRequest resource_request;
- resource_request.url = GURL(request->url);
- resource_request.method = request->method;
- for (const auto& header : request->headers) {
- resource_request.headers.SetHeader(header->key, header->value);
- }
- if (request->request_body_bytes > 0) {
- resource_request.request_body = new network::ResourceRequestBody();
- resource_request.request_body->AppendDataPipe(std::move(data_pipe_getter));
- }
- // Start execution, the `DriveFsURLLoaderClient` will remove itself from the
- // `clients_` map on completion.
- url_loader_factory_->CreateLoaderAndStart(
- std::move(url_loader_reciever), /*request_id=*/client_id,
- /*options=*/network::mojom::kURLLoadOptionBlockAllCookies,
- std::move(resource_request), std::move(url_loader_client),
- net::MutableNetworkTrafficAnnotationTag(kTrafficAnnotation));
- }
- } // namespace drivefs
|