File: android_stream_reader_url_loader.h

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (182 lines) | stat: -rw-r--r-- 7,577 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_EMBEDDER_SUPPORT_ANDROID_UTIL_ANDROID_STREAM_READER_URL_LOADER_H_
#define COMPONENTS_EMBEDDER_SUPPORT_ANDROID_UTIL_ANDROID_STREAM_READER_URL_LOADER_H_

#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "net/http/http_byte_range.h"
#include "services/network/public/cpp/net_adapters.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"

namespace embedder_support {
class InputStream;
class InputStreamReaderWrapper;

// Custom URLLoader implementation for loading responses from Android
// InputStreams. Although this works generally for implementers of the
// ResponseDelegate interface, this specifically aims to support:
//
//  - shouldInterceptRequest callback
//  - content:// URLs, which load content from Android ContentProviders (which
//    could be in-app or come from other apps)
//  - file:///android_asset/ & file:///android_res/ URLs, which load in-app
//    content from the app's asset/ and res/ folders
class AndroidStreamReaderURLLoader : public network::mojom::URLLoader {
 public:
  // Delegate abstraction for obtaining input streams.
  class ResponseDelegate {
   public:
    virtual ~ResponseDelegate() = default;

    // This method is called from a worker thread, not from the IO thread.
    virtual std::unique_ptr<embedder_support::InputStream> OpenInputStream(
        JNIEnv* env) = 0;

    // All the methods below are called on the URLLoader thread (IO thread).

    // This method is called if the result of calling OpenInputStream was null.
    // Returns true if the request was restarted with a new loader or
    // was completed, false otherwise.
    virtual bool OnInputStreamOpenFailed() = 0;

    // Allows the delegate to update the mime type, by setting |mime_type| and
    // returning true.
    virtual bool GetMimeType(JNIEnv* env,
                             const GURL& url,
                             embedder_support::InputStream* stream,
                             std::string* mime_type) = 0;

    // Allows the delegate to set the charset of the response by setting
    // |charset|.
    virtual void GetCharset(JNIEnv* env,
                            const GURL& url,
                            embedder_support::InputStream* stream,
                            std::string* charset) = 0;

    // Allows the delegate to add extra response headers.
    virtual void AppendResponseHeaders(JNIEnv* env,
                                       net::HttpResponseHeaders* headers) = 0;

    // Called right before URLLoaderClient::OnReceiveResponse is called. If this
    // method returns true then a copy of the response is made and returned in
    // OnResponseCache.
    virtual bool ShouldCacheResponse(network::mojom::URLResponseHead* response);

    // Called if ShouldCacheResponse returned true and the response was
    // successful.
    virtual void OnResponseCache(const std::string& data) {}
  };

  struct SecurityOptions {
    bool disable_web_security = false;
    bool allow_cors_to_same_scheme = false;
  };

  // Delegate that ensures that the provided `value` is set as a Set-Cookie
  // response to the given `request`.
  using SetCookieHeader = base::RepeatingCallback<void(
      const network::ResourceRequest& request,
      std::string_view value,
      const std::optional<base::Time>& server_time)>;

  AndroidStreamReaderURLLoader(
      const network::ResourceRequest& resource_request,
      mojo::PendingRemote<network::mojom::URLLoaderClient> client,
      const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
      std::unique_ptr<ResponseDelegate> response_delegate,
      std::optional<SecurityOptions> security_options,
      std::optional<SetCookieHeader> set_cookie_header = std::nullopt);

  AndroidStreamReaderURLLoader(const AndroidStreamReaderURLLoader&) = delete;
  AndroidStreamReaderURLLoader& operator=(const AndroidStreamReaderURLLoader&) =
      delete;

  ~AndroidStreamReaderURLLoader() override;

  void Start(std::unique_ptr<InputStream> input_stream);

  // network::mojom::URLLoader overrides:
  void FollowRedirect(
      const std::vector<std::string>& removed_headers,
      const net::HttpRequestHeaders& modified_headers,
      const net::HttpRequestHeaders& modified_cors_exempt_headers,
      const std::optional<GURL>& new_url) override;
  void SetPriority(net::RequestPriority priority,
                   int intra_priority_value) override;

 private:
  bool ParseRange(const net::HttpRequestHeaders& headers);
  void OnInputStreamOpened(
      std::unique_ptr<AndroidStreamReaderURLLoader::ResponseDelegate>
          returned_delegate,
      std::unique_ptr<embedder_support::InputStream> input_stream);
  void OnReaderSeekCompleted(int result);
  void HeadersComplete(int status_code, const std::string& status_text);
  void RequestCompleteWithStatus(
      const network::URLLoaderCompletionStatus& status);
  void RequestComplete(int status_code);
  void SendBody();

  void OnDataPipeWritable(MojoResult result);
  void CleanUp();

  // Called after trying to read some bytes from the stream. |result| can be a
  // positive number (the number of bytes read), zero (no bytes were read
  // because the stream is finished), or negative (error condition).
  void DidRead(int result);
  // Reads some bytes from the stream. Calls |DidRead| after each read (also, in
  // the case where it fails to read due to an error).
  void ReadMore();
  // The Set-Cookie header can't be sent over IPC. Because this stream reader
  // bypasses the network stack, the Set-Cookie is ignored entirely.
  // This is called before sending the response to give the embedder
  // an opportunity to save headers.
  void SetCookies();
  // Send response headers and the data pipe consumer handle (for the body) to
  // the URLLoaderClient. Requires |consumer_handle_| to be valid, and will make
  // |consumer_handle_| invalid after running.
  void SendResponseToClient();

  // Expected content size
  int64_t expected_content_size_ = -1;
  mojo::ScopedDataPipeConsumerHandle consumer_handle_;

  net::HttpByteRange byte_range_;
  network::ResourceRequest resource_request_;
  network::mojom::URLResponseHeadPtr response_head_;
  bool reject_cors_request_;
  mojo::Remote<network::mojom::URLLoaderClient> client_;
  const net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
  std::unique_ptr<ResponseDelegate> response_delegate_;
  scoped_refptr<InputStreamReaderWrapper> input_stream_reader_wrapper_;

  // If true, a copy of the response is made.
  bool cache_response_ = false;
  std::string cached_response_;

  mojo::ScopedDataPipeProducerHandle producer_handle_;
  scoped_refptr<network::NetToMojoPendingBuffer> pending_buffer_;
  mojo::SimpleWatcher writable_handle_watcher_;
  base::Time start_time_;
  std::optional<SetCookieHeader> set_cookie_header_;
  base::ThreadChecker thread_checker_;

  base::WeakPtrFactory<AndroidStreamReaderURLLoader> weak_factory_{this};
};

}  // namespace embedder_support

#endif  // COMPONENTS_EMBEDDER_SUPPORT_ANDROID_UTIL_ANDROID_STREAM_READER_URL_LOADER_H_