mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2024-12-14 18:44:56 +01:00
fa5268fa2d
The behavior has changed as follows with NetworkService enabled: - All pending and in-progress requests will now be aborted when the CEF context or associated browser is destroyed. The OnResourceLoadComplete callback will now also be called in this case for in-progress requests that have a handler. - The CefResourceHandler::Cancel method will now always be called when resource handling is complete, irrespective of whether handling completed successfully. - Request callbacks that arrive after the OnBeforeClose callback for the associated browser (which may happen for in-progress requests that are aborted on browser destruction) will now always have a non-nullptr CefBrowser parameter. - Allow empty parameters to CefRequest and CefResponse methods where it makes sense (e.g. resetting default response state, or clearing a referrer value). - Fixed a reference loop that was keeping CefResourceHandler objects from being destroyed if they were holding a callback reference (from ProcessRequest, ReadResponse, etc.) during CEF context or associated browser destruction. - Fixed an issue where the main frame was not detached on browser destruction which could cause a crash due to RFH use-after-free (see issue #2498). To test: All unit tests pass as expected.
238 lines
9.3 KiB
C++
238 lines
9.3 KiB
C++
// Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions
|
|
// Copyright (c) 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 CEF_LIBCEF_BROWSER_NET_SERVICE_STREAM_READER_URL_LOADER_H_
|
|
#define CEF_LIBCEF_BROWSER_NET_SERVICE_STREAM_READER_URL_LOADER_H_
|
|
|
|
#include <map>
|
|
|
|
#include "base/callback.h"
|
|
#include "base/threading/thread_checker.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/mojom/network_context.mojom.h"
|
|
#include "services/network/public/mojom/url_loader.mojom.h"
|
|
|
|
namespace net_service {
|
|
|
|
class InputStreamReader;
|
|
|
|
// Abstract class representing an input stream. All methods are called in
|
|
// sequence on a worker thread, but not necessarily on the same thread.
|
|
class InputStream {
|
|
public:
|
|
virtual ~InputStream() {}
|
|
|
|
// Callback for asynchronous continuation of Skip(). If |bytes_skipped| > 0
|
|
// then either Skip() will be called again until the requested number of
|
|
// bytes have been skipped or the request will proceed. If |bytes_skipped|
|
|
// <= 0 the request will fail with net::ERR_REQUEST_RANGE_NOT_SATISFIABLE.
|
|
using SkipCallback = base::OnceCallback<void(int64_t /* bytes_skipped */)>;
|
|
|
|
// Skip over and discard |n| bytes of data from this input stream. If data
|
|
// is available immediately set |bytes_skipped| to the number of of bytes
|
|
// skipped and return true. To read the data at a later time set
|
|
// |bytes_skipped| to 0, return true and execute |callback| when the data is
|
|
// available. To indicate failure set |bytes_skipped| to < 0 (e.g.
|
|
// net::ERR_FAILED) and return false.
|
|
virtual bool Skip(int64_t n,
|
|
int64_t* bytes_skipped,
|
|
SkipCallback callback) = 0;
|
|
|
|
// Callback for asynchronous continuation of Read(). If |bytes_read| == 0
|
|
// the response will be considered complete. If |bytes_read| > 0 then Read()
|
|
// will be called again until the request is complete (based on either the
|
|
// result or the expected content length). If |bytes_read| < 0 then the
|
|
// request will fail and the |bytes_read| value will be treated as the error
|
|
// code.
|
|
using ReadCallback = base::OnceCallback<void(int /* bytes_read */)>;
|
|
|
|
// Read response data. If data is available immediately copy up to |length|
|
|
// bytes into |dest|, set |bytes_read| to the number of bytes copied, and
|
|
// return true. To read the data at a later time set |bytes_read| to 0, return
|
|
// true and execute |callback| when the data is available. To indicate
|
|
// response completion set |bytes_read| to 0 and return false. To indicate
|
|
// failure set |bytes_read| to < 0 (e.g. net::ERR_FAILED) and return false.
|
|
virtual bool Read(net::IOBuffer* dest,
|
|
int length,
|
|
int* bytes_read,
|
|
ReadCallback callback) = 0;
|
|
};
|
|
|
|
// Unique identifier for RequestHandler callbacks.
|
|
// Based on components/viz/common/surfaces/frame_sink_id.h
|
|
class RequestId {
|
|
public:
|
|
constexpr RequestId() : request_id_(0), routing_id_(0) {}
|
|
|
|
constexpr RequestId(const RequestId& other)
|
|
: request_id_(other.request_id_), routing_id_(other.routing_id_) {}
|
|
|
|
constexpr RequestId(uint32_t request_id, uint32_t routing_id)
|
|
: request_id_(request_id), routing_id_(routing_id) {}
|
|
|
|
constexpr bool is_valid() const {
|
|
return request_id_ != 0 || routing_id_ != 0;
|
|
}
|
|
|
|
constexpr uint32_t request_id() const { return request_id_; }
|
|
|
|
constexpr uint32_t routing_id() const { return routing_id_; }
|
|
|
|
bool operator==(const RequestId& other) const {
|
|
return request_id_ == other.request_id_ && routing_id_ == other.routing_id_;
|
|
}
|
|
|
|
bool operator!=(const RequestId& other) const { return !(*this == other); }
|
|
|
|
bool operator<(const RequestId& other) const {
|
|
return std::tie(request_id_, routing_id_) <
|
|
std::tie(other.request_id_, other.routing_id_);
|
|
}
|
|
|
|
size_t hash() const { return base::HashInts(request_id_, routing_id_); }
|
|
|
|
std::string ToString() const;
|
|
|
|
std::string ToString(base::StringPiece debug_label) const;
|
|
|
|
private:
|
|
uint32_t request_id_;
|
|
uint32_t routing_id_;
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& out, const RequestId& request_id);
|
|
|
|
struct RequestIdHash {
|
|
size_t operator()(const RequestId& key) const { return key.hash(); }
|
|
};
|
|
|
|
// Abstract class for handling intercepted resource responses. All methods are
|
|
// called on the IO thread unless otherwise indicated.
|
|
class ResourceResponse {
|
|
public:
|
|
virtual ~ResourceResponse() {}
|
|
|
|
// Callback for asynchronous continuation of Open(). If the InputStream is
|
|
// null the request will be canceled.
|
|
using OpenCallback = base::OnceCallback<void(std::unique_ptr<InputStream>)>;
|
|
|
|
// This method is called on a worker thread. Return true and execute
|
|
// |callback| to continue the request. Return false to cancel the request.
|
|
// |request| may be different from the request used to create the
|
|
// StreamReaderURLLoader if a redirect was followed.
|
|
virtual bool OpenInputStream(const RequestId& id,
|
|
const network::ResourceRequest& request,
|
|
OpenCallback callback) = 0;
|
|
|
|
// This method is called to populate the response headers.
|
|
using HeaderMap = std::multimap<std::string, std::string>;
|
|
virtual void GetResponseHeaders(const RequestId& id,
|
|
int* status_code,
|
|
std::string* reason_phrase,
|
|
std::string* mime_type,
|
|
std::string* charset,
|
|
int64_t* content_length,
|
|
HeaderMap* extra_headers) = 0;
|
|
};
|
|
|
|
// Custom URLLoader implementation for loading network responses from stream.
|
|
// Methods are called on the IO thread unless otherwise indicated.
|
|
// Based on android_webview/browser/network_service/
|
|
// android_stream_reader_url_loader.h
|
|
class StreamReaderURLLoader : public network::mojom::URLLoader {
|
|
public:
|
|
// Delegate abstraction for obtaining input streams. All methods are called
|
|
// on the IO thread unless otherwise indicated.
|
|
class Delegate : public ResourceResponse {
|
|
public:
|
|
// This method is called if the result of calling OpenInputStream was null.
|
|
// The |restarted| parameter is set to true if the request was restarted
|
|
// with a new loader.
|
|
virtual void OnInputStreamOpenFailed(const RequestId& id,
|
|
bool* restarted) = 0;
|
|
};
|
|
|
|
StreamReaderURLLoader(
|
|
const RequestId& request_id,
|
|
const network::ResourceRequest& request,
|
|
network::mojom::URLLoaderClientPtr client,
|
|
network::mojom::TrustedHeaderClientPtr header_client,
|
|
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
|
|
std::unique_ptr<Delegate> response_delegate);
|
|
~StreamReaderURLLoader() override;
|
|
|
|
void Start();
|
|
|
|
void ContinueResponse(bool was_redirected);
|
|
|
|
// network::mojom::URLLoader methods:
|
|
void FollowRedirect(const std::vector<std::string>& removed_headers,
|
|
const net::HttpRequestHeaders& modified_headers,
|
|
const base::Optional<GURL>& new_url) override;
|
|
void ProceedWithResponse() override;
|
|
void SetPriority(net::RequestPriority priority,
|
|
int intra_priority_value) override;
|
|
void PauseReadingBodyFromNet() override;
|
|
void ResumeReadingBodyFromNet() override;
|
|
|
|
private:
|
|
void ContinueWithRequestHeaders(
|
|
int32_t result,
|
|
const base::Optional<net::HttpRequestHeaders>& headers);
|
|
void OnInputStreamOpened(std::unique_ptr<Delegate> returned_delegate,
|
|
std::unique_ptr<InputStream> input_stream);
|
|
|
|
void OnReaderSkipCompleted(int64_t bytes_skipped);
|
|
void HeadersComplete(int status_code, int64_t expected_content_length);
|
|
void ContinueWithResponseHeaders(int32_t result,
|
|
const base::Optional<std::string>& headers,
|
|
const GURL& redirect_url);
|
|
|
|
void SendBody();
|
|
void ReadMore();
|
|
void OnDataPipeWritable(MojoResult result);
|
|
void OnReaderReadCompleted(int bytes_read);
|
|
void RequestComplete(int status_code);
|
|
|
|
void CleanUp();
|
|
|
|
bool ParseRange(const net::HttpRequestHeaders& headers);
|
|
bool byte_range_valid() const;
|
|
|
|
const RequestId request_id_;
|
|
|
|
network::ResourceResponseHead pending_response_;
|
|
|
|
size_t header_length_ = 0;
|
|
int64_t total_bytes_read_ = 0;
|
|
|
|
net::HttpByteRange byte_range_;
|
|
network::ResourceRequest request_;
|
|
network::mojom::URLLoaderClientPtr client_;
|
|
network::mojom::TrustedHeaderClientPtr header_client_;
|
|
const net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
|
|
std::unique_ptr<Delegate> response_delegate_;
|
|
scoped_refptr<InputStreamReader> input_stream_reader_;
|
|
|
|
mojo::ScopedDataPipeProducerHandle producer_handle_;
|
|
scoped_refptr<network::NetToMojoPendingBuffer> pending_buffer_;
|
|
mojo::SimpleWatcher writable_handle_watcher_;
|
|
base::ThreadChecker thread_checker_;
|
|
|
|
scoped_refptr<base::SequencedTaskRunner> stream_work_task_runner_;
|
|
|
|
base::OnceClosure open_cancel_callback_;
|
|
|
|
base::WeakPtrFactory<StreamReaderURLLoader> weak_factory_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(StreamReaderURLLoader);
|
|
};
|
|
|
|
} // namespace net_service
|
|
|
|
#endif // CEF_LIBCEF_BROWSER_NET_SERVICE_STREAM_READER_URL_LOADER_H_
|