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