| // 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. |
| |
| #ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_LOADER_MIME_SNIFFING_URL_LOADER_H_ |
| #define THIRD_PARTY_BLINK_PUBLIC_COMMON_LOADER_MIME_SNIFFING_URL_LOADER_H_ |
| |
| #include <tuple> |
| |
| #include "base/callback.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/strings/string_piece.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/remote.h" |
| #include "mojo/public/cpp/system/data_pipe.h" |
| #include "mojo/public/cpp/system/simple_watcher.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| #include "services/network/public/mojom/url_loader.mojom.h" |
| #include "services/network/public/mojom/url_loader_factory.mojom-forward.h" |
| #include "services/network/public/mojom/url_response_head.mojom-forward.h" |
| #include "third_party/blink/public/common/common_export.h" |
| #include "third_party/blink/public/common/loader/url_loader_throttle.h" |
| |
| namespace blink { |
| |
| class MimeSniffingThrottle; |
| |
| // Reads the response body and determines its mime type. This url loader buffers |
| // the response body until the mime type is decided. MimeSniffingURLLoader |
| // is expected to be created just after receiving OnReceiveResponse(), so this |
| // handles only OnStartLoadingResponseBody() and OnComplete() as a |
| // network::mojom::URLLoaderClient. |
| // |
| // This loader has five states: |
| // kWaitForBody: The initial state until the body is received (= |
| // OnStartLoadingResponseBody() is called) or the response is |
| // finished (= OnComplete() is called). When body is provided, the |
| // state is changed to kSniffing. Otherwise the state goes to |
| // kCompleted. |
| // kSniffing: Receives the body from the source loader and estimate the mime |
| // type. The received body is kept in this loader until the mime type |
| // is decided. When the mime type is decided or all body has been |
| // received, this loader will dispatch queued messages like |
| // OnStartLoadingResponseBody() to the destination |
| // loader client, and then the state is changed to kSending. |
| // kSending: Receives the body and sends it to the destination loader client. |
| // The state changes to kCompleted after all data is sent. |
| // kCompleted: All data has been sent to the destination loader. |
| // kAborted: Unexpected behavior happens. Watchers, pipes and the binding from |
| // the source loader to |this| are stopped. All incoming messages from |
| // the destination (through network::mojom::URLLoader) are ignored in |
| // this state. |
| class BLINK_COMMON_EXPORT MimeSniffingURLLoader |
| : public network::mojom::URLLoaderClient, |
| public network::mojom::URLLoader { |
| public: |
| ~MimeSniffingURLLoader() override; |
| |
| // Start waiting for the body. |
| void Start( |
| mojo::PendingRemote<network::mojom::URLLoader> source_url_loader_remote, |
| mojo::PendingReceiver<network::mojom::URLLoaderClient> |
| source_url_client_receiver); |
| |
| // mojo::PendingRemote<network::mojom::URLLoader> controls the lifetime of the |
| // loader. |
| static std::tuple<mojo::PendingRemote<network::mojom::URLLoader>, |
| mojo::PendingReceiver<network::mojom::URLLoaderClient>, |
| MimeSniffingURLLoader*> |
| CreateLoader(base::WeakPtr<MimeSniffingThrottle> throttle, |
| const GURL& response_url, |
| network::mojom::URLResponseHeadPtr response_head, |
| scoped_refptr<base::SequencedTaskRunner> task_runner); |
| |
| private: |
| MimeSniffingURLLoader(base::WeakPtr<MimeSniffingThrottle> throttle, |
| const GURL& response_url, |
| network::mojom::URLResponseHeadPtr response_head, |
| mojo::PendingRemote<network::mojom::URLLoaderClient> |
| destination_url_loader_client, |
| scoped_refptr<base::SequencedTaskRunner> task_runner); |
| |
| // network::mojom::URLLoaderClient implementation (called from the source of |
| // the response): |
| void OnReceiveResponse( |
| network::mojom::URLResponseHeadPtr response_head) override; |
| void OnReceiveRedirect( |
| const net::RedirectInfo& redirect_info, |
| network::mojom::URLResponseHeadPtr response_head) override; |
| void OnUploadProgress(int64_t current_position, |
| int64_t total_size, |
| OnUploadProgressCallback ack_callback) override; |
| void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override; |
| void OnTransferSizeUpdated(int32_t transfer_size_diff) override; |
| void OnStartLoadingResponseBody( |
| mojo::ScopedDataPipeConsumerHandle body) override; |
| void OnComplete(const network::URLLoaderCompletionStatus& status) override; |
| |
| // network::mojom::URLLoader implementation (called from the destination of |
| // the response): |
| void FollowRedirect( |
| const std::vector<std::string>& removed_headers, |
| const net::HttpRequestHeaders& modified_headers, |
| const net::HttpRequestHeaders& modified_cors_exempt_headers, |
| const base::Optional<GURL>& new_url) override; |
| void SetPriority(net::RequestPriority priority, |
| int32_t intra_priority_value) override; |
| void PauseReadingBodyFromNet() override; |
| void ResumeReadingBodyFromNet() override; |
| |
| void OnBodyReadable(MojoResult); |
| void OnBodyWritable(MojoResult); |
| void CompleteSniffing(); |
| void CompleteSending(); |
| void SendReceivedBodyToClient(); |
| void ForwardBodyToClient(); |
| |
| void Abort(); |
| |
| static const char kDefaultMimeType[]; |
| |
| base::WeakPtr<MimeSniffingThrottle> throttle_; |
| |
| mojo::Receiver<network::mojom::URLLoaderClient> source_url_client_receiver_{ |
| this}; |
| mojo::Remote<network::mojom::URLLoader> source_url_loader_; |
| mojo::Remote<network::mojom::URLLoaderClient> destination_url_loader_client_; |
| |
| GURL response_url_; |
| |
| // Capture the response head to defer to send it to the destination until the |
| // mime type is decided. |
| network::mojom::URLResponseHeadPtr response_head_; |
| |
| scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| |
| enum class State { kWaitForBody, kSniffing, kSending, kCompleted, kAborted }; |
| State state_ = State::kWaitForBody; |
| |
| // Set if OnComplete() is called during sniffing. |
| base::Optional<network::URLLoaderCompletionStatus> complete_status_; |
| |
| std::vector<char> buffered_body_; |
| size_t bytes_remaining_in_buffer_; |
| |
| mojo::ScopedDataPipeConsumerHandle body_consumer_handle_; |
| mojo::ScopedDataPipeProducerHandle body_producer_handle_; |
| mojo::SimpleWatcher body_consumer_watcher_; |
| mojo::SimpleWatcher body_producer_watcher_; |
| |
| DISALLOW_COPY_AND_ASSIGN(MimeSniffingURLLoader); |
| }; |
| |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_LOADER_MIME_SNIFFING_URL_LOADER_H_ |