1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_LOADER_MIME_SNIFFING_URL_LOADER_H_ 6 #define THIRD_PARTY_BLINK_PUBLIC_COMMON_LOADER_MIME_SNIFFING_URL_LOADER_H_ 7 8 #include <tuple> 9 10 #include "base/callback.h" 11 #include "base/memory/ref_counted.h" 12 #include "base/memory/weak_ptr.h" 13 #include "base/strings/string_piece.h" 14 #include "mojo/public/cpp/bindings/pending_receiver.h" 15 #include "mojo/public/cpp/bindings/pending_remote.h" 16 #include "mojo/public/cpp/bindings/receiver.h" 17 #include "mojo/public/cpp/bindings/remote.h" 18 #include "mojo/public/cpp/system/data_pipe.h" 19 #include "mojo/public/cpp/system/simple_watcher.h" 20 #include "services/network/public/cpp/shared_url_loader_factory.h" 21 #include "services/network/public/mojom/url_loader.mojom.h" 22 #include "services/network/public/mojom/url_loader_factory.mojom-forward.h" 23 #include "services/network/public/mojom/url_response_head.mojom-forward.h" 24 #include "third_party/blink/public/common/common_export.h" 25 #include "third_party/blink/public/common/loader/url_loader_throttle.h" 26 27 namespace blink { 28 29 class MimeSniffingThrottle; 30 31 // Reads the response body and determines its mime type. This url loader buffers 32 // the response body until the mime type is decided. MimeSniffingURLLoader 33 // is expected to be created just after receiving OnReceiveResponse(), so this 34 // handles only OnStartLoadingResponseBody() and OnComplete() as a 35 // network::mojom::URLLoaderClient. 36 // 37 // This loader has five states: 38 // kWaitForBody: The initial state until the body is received (= 39 // OnStartLoadingResponseBody() is called) or the response is 40 // finished (= OnComplete() is called). When body is provided, the 41 // state is changed to kSniffing. Otherwise the state goes to 42 // kCompleted. 43 // kSniffing: Receives the body from the source loader and estimate the mime 44 // type. The received body is kept in this loader until the mime type 45 // is decided. When the mime type is decided or all body has been 46 // received, this loader will dispatch queued messages like 47 // OnStartLoadingResponseBody() to the destination 48 // loader client, and then the state is changed to kSending. 49 // kSending: Receives the body and sends it to the destination loader client. 50 // The state changes to kCompleted after all data is sent. 51 // kCompleted: All data has been sent to the destination loader. 52 // kAborted: Unexpected behavior happens. Watchers, pipes and the binding from 53 // the source loader to |this| are stopped. All incoming messages from 54 // the destination (through network::mojom::URLLoader) are ignored in 55 // this state. 56 class BLINK_COMMON_EXPORT MimeSniffingURLLoader 57 : public network::mojom::URLLoaderClient, 58 public network::mojom::URLLoader { 59 public: 60 ~MimeSniffingURLLoader() override; 61 62 // Start waiting for the body. 63 void Start( 64 mojo::PendingRemote<network::mojom::URLLoader> source_url_loader_remote, 65 mojo::PendingReceiver<network::mojom::URLLoaderClient> 66 source_url_client_receiver); 67 68 // mojo::PendingRemote<network::mojom::URLLoader> controls the lifetime of the 69 // loader. 70 static std::tuple<mojo::PendingRemote<network::mojom::URLLoader>, 71 mojo::PendingReceiver<network::mojom::URLLoaderClient>, 72 MimeSniffingURLLoader*> 73 CreateLoader(base::WeakPtr<MimeSniffingThrottle> throttle, 74 const GURL& response_url, 75 network::mojom::URLResponseHeadPtr response_head, 76 scoped_refptr<base::SequencedTaskRunner> task_runner); 77 78 private: 79 MimeSniffingURLLoader(base::WeakPtr<MimeSniffingThrottle> throttle, 80 const GURL& response_url, 81 network::mojom::URLResponseHeadPtr response_head, 82 mojo::PendingRemote<network::mojom::URLLoaderClient> 83 destination_url_loader_client, 84 scoped_refptr<base::SequencedTaskRunner> task_runner); 85 86 // network::mojom::URLLoaderClient implementation (called from the source of 87 // the response): 88 void OnReceiveResponse( 89 network::mojom::URLResponseHeadPtr response_head) override; 90 void OnReceiveRedirect( 91 const net::RedirectInfo& redirect_info, 92 network::mojom::URLResponseHeadPtr response_head) override; 93 void OnUploadProgress(int64_t current_position, 94 int64_t total_size, 95 OnUploadProgressCallback ack_callback) override; 96 void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override; 97 void OnTransferSizeUpdated(int32_t transfer_size_diff) override; 98 void OnStartLoadingResponseBody( 99 mojo::ScopedDataPipeConsumerHandle body) override; 100 void OnComplete(const network::URLLoaderCompletionStatus& status) override; 101 102 // network::mojom::URLLoader implementation (called from the destination of 103 // the response): 104 void FollowRedirect( 105 const std::vector<std::string>& removed_headers, 106 const net::HttpRequestHeaders& modified_headers, 107 const net::HttpRequestHeaders& modified_cors_exempt_headers, 108 const base::Optional<GURL>& new_url) override; 109 void SetPriority(net::RequestPriority priority, 110 int32_t intra_priority_value) override; 111 void PauseReadingBodyFromNet() override; 112 void ResumeReadingBodyFromNet() override; 113 114 void OnBodyReadable(MojoResult); 115 void OnBodyWritable(MojoResult); 116 void CompleteSniffing(); 117 void CompleteSending(); 118 void SendReceivedBodyToClient(); 119 void ForwardBodyToClient(); 120 121 void Abort(); 122 123 static const char kDefaultMimeType[]; 124 125 base::WeakPtr<MimeSniffingThrottle> throttle_; 126 127 mojo::Receiver<network::mojom::URLLoaderClient> source_url_client_receiver_{ 128 this}; 129 mojo::Remote<network::mojom::URLLoader> source_url_loader_; 130 mojo::Remote<network::mojom::URLLoaderClient> destination_url_loader_client_; 131 132 GURL response_url_; 133 134 // Capture the response head to defer to send it to the destination until the 135 // mime type is decided. 136 network::mojom::URLResponseHeadPtr response_head_; 137 138 scoped_refptr<base::SequencedTaskRunner> task_runner_; 139 140 enum class State { kWaitForBody, kSniffing, kSending, kCompleted, kAborted }; 141 State state_ = State::kWaitForBody; 142 143 // Set if OnComplete() is called during sniffing. 144 base::Optional<network::URLLoaderCompletionStatus> complete_status_; 145 146 std::vector<char> buffered_body_; 147 size_t bytes_remaining_in_buffer_; 148 149 mojo::ScopedDataPipeConsumerHandle body_consumer_handle_; 150 mojo::ScopedDataPipeProducerHandle body_producer_handle_; 151 mojo::SimpleWatcher body_consumer_watcher_; 152 mojo::SimpleWatcher body_producer_watcher_; 153 154 DISALLOW_COPY_AND_ASSIGN(MimeSniffingURLLoader); 155 }; 156 157 } // namespace blink 158 159 #endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_LOADER_MIME_SNIFFING_URL_LOADER_H_ 160