Commit ffaa6833 authored by Yuwei Huang's avatar Yuwei Huang Committed by Commit Bot

[remoting] Add stream request support to ProtobufHttpStatus

* Add stream request support to ProtobufHttpStatus, which includes some
  refactoring in the code.
* Make ProtobufHttpClient directly own the requests, to make lifetime
  managing less painful.

Bug: 1103416
Change-Id: I9c1f62acb4e02cd968387bc4cc34db8dd6268c25
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2299536
Commit-Queue: Yuwei Huang <yuweih@chromium.org>
Reviewed-by: default avatarJoe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790112}
parent 526a61db
......@@ -33,10 +33,16 @@ source_set("base") {
"protobuf_http_client.h",
"protobuf_http_request.cc",
"protobuf_http_request.h",
"protobuf_http_request_base.cc",
"protobuf_http_request_base.h",
"protobuf_http_request_config.cc",
"protobuf_http_request_config.h",
"protobuf_http_status.cc",
"protobuf_http_status.h",
"protobuf_http_stream_parser.cc",
"protobuf_http_stream_parser.h",
"protobuf_http_stream_request.cc",
"protobuf_http_stream_request.h",
"rate_counter.cc",
"rate_counter.h",
"result.h",
......
......@@ -8,7 +8,8 @@
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "remoting/base/oauth_token_getter.h"
#include "remoting/base/protobuf_http_request.h"
#include "remoting/base/protobuf_http_request_base.h"
#include "remoting/base/protobuf_http_request_config.h"
#include "remoting/base/protobuf_http_status.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
......@@ -19,7 +20,6 @@
namespace {
constexpr char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s";
constexpr int kMaxResponseSizeKb = 512;
} // namespace
......@@ -33,15 +33,15 @@ ProtobufHttpClient::ProtobufHttpClient(
token_getter_(token_getter),
url_loader_factory_(url_loader_factory) {}
ProtobufHttpClient::~ProtobufHttpClient() = default;
ProtobufHttpClient::~ProtobufHttpClient() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void ProtobufHttpClient::ExecuteRequest(
std::unique_ptr<ProtobufHttpRequest> request) {
DCHECK(request->request_message);
DCHECK(!request->path.empty());
DCHECK(request->response_callback_);
std::unique_ptr<ProtobufHttpRequestBase> request) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!request->authenticated) {
if (!request->config().authenticated) {
DoExecuteRequest(std::move(request), OAuthTokenGetter::Status::SUCCESS, {},
{});
return;
......@@ -54,23 +54,37 @@ void ProtobufHttpClient::ExecuteRequest(
}
void ProtobufHttpClient::CancelPendingRequests() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
weak_factory_.InvalidateWeakPtrs();
pending_requests_.clear();
}
bool ProtobufHttpClient::HasPendingRequests() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return !pending_requests_.empty();
}
void ProtobufHttpClient::DoExecuteRequest(
std::unique_ptr<ProtobufHttpRequest> request,
std::unique_ptr<ProtobufHttpRequestBase> request,
OAuthTokenGetter::Status status,
const std::string& user_email,
const std::string& access_token) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (status != OAuthTokenGetter::Status::SUCCESS) {
LOG(ERROR) << "Failed to fetch access token. Status: " << status;
request->OnResponse(
ProtobufHttpStatus(net::HttpStatusCode::HTTP_UNAUTHORIZED), nullptr);
std::string error_message =
base::StringPrintf("Failed to fetch access token. Status: %d", status);
LOG(ERROR) << error_message;
request->OnAuthFailed(ProtobufHttpStatus(
ProtobufHttpStatus::Code::UNAUTHENTICATED, error_message));
return;
}
auto resource_request = std::make_unique<network::ResourceRequest>();
resource_request->url = GURL("https://" + server_endpoint_ + request->path);
resource_request->url =
GURL("https://" + server_endpoint_ + request->config().path);
resource_request->load_flags =
net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE;
resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
......@@ -85,35 +99,28 @@ void ProtobufHttpClient::DoExecuteRequest(
std::unique_ptr<network::SimpleURLLoader> send_url_loader =
network::SimpleURLLoader::Create(std::move(resource_request),
request->traffic_annotation);
send_url_loader->SetTimeoutDuration(request->timeout_duration);
request->config().traffic_annotation);
base::TimeDelta timeout_duration = request->GetRequestTimeoutDuration();
if (!timeout_duration.is_zero()) {
send_url_loader->SetTimeoutDuration(request->GetRequestTimeoutDuration());
}
send_url_loader->AttachStringForUpload(
request->request_message->SerializeAsString(), "application/x-protobuf");
send_url_loader->DownloadToString(
url_loader_factory_.get(),
base::BindOnce(&ProtobufHttpClient::OnResponse,
weak_factory_.GetWeakPtr(), std::move(request),
std::move(send_url_loader)),
kMaxResponseSizeKb);
request->config().request_message->SerializeAsString(),
"application/x-protobuf");
auto* unowned_request = request.get();
base::OnceClosure invalidator = base::BindOnce(
&ProtobufHttpClient::CancelRequest, weak_factory_.GetWeakPtr(),
pending_requests_.insert(pending_requests_.end(), std::move(request)));
unowned_request->StartRequest(url_loader_factory_.get(),
std::move(send_url_loader),
std::move(invalidator));
}
void ProtobufHttpClient::OnResponse(
std::unique_ptr<ProtobufHttpRequest> request,
std::unique_ptr<network::SimpleURLLoader> url_loader,
std::unique_ptr<std::string> response_body) {
net::Error net_error = static_cast<net::Error>(url_loader->NetError());
if (net_error == net::Error::ERR_HTTP_RESPONSE_CODE_FAILURE &&
(!url_loader->ResponseInfo() || !url_loader->ResponseInfo()->headers)) {
LOG(ERROR) << "Can't find response header.";
net_error = net::Error::ERR_INVALID_RESPONSE;
}
ProtobufHttpStatus status =
(net_error == net::Error::ERR_HTTP_RESPONSE_CODE_FAILURE ||
net_error == net::Error::OK)
? ProtobufHttpStatus(static_cast<net::HttpStatusCode>(
url_loader->ResponseInfo()->headers->response_code()))
: ProtobufHttpStatus(net_error);
request->OnResponse(status, std::move(response_body));
void ProtobufHttpClient::CancelRequest(
const PendingRequestListIterator& request_iterator) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
pending_requests_.erase(request_iterator);
}
} // namespace remoting
......@@ -5,22 +5,23 @@
#ifndef REMOTING_BASE_PROTOBUF_HTTP_CLIENT_H_
#define REMOTING_BASE_PROTOBUF_HTTP_CLIENT_H_
#include <list>
#include <memory>
#include <string>
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "remoting/base/oauth_token_getter.h"
namespace network {
class SharedURLLoaderFactory;
class SimpleURLLoader;
} // namespace network
namespace remoting {
struct ProtobufHttpRequest;
class ProtobufHttpRequestBase;
// Helper class for executing REST/Protobuf requests over HTTP.
class ProtobufHttpClient final {
......@@ -38,26 +39,36 @@ class ProtobufHttpClient final {
// Executes a unary request. Caller will not be notified of the result if
// CancelPendingRequests() is called or |this| is destroyed.
void ExecuteRequest(std::unique_ptr<ProtobufHttpRequest> request);
void ExecuteRequest(std::unique_ptr<ProtobufHttpRequestBase> request);
// Tries to cancel all pending requests. Note that this prevents request
// callbacks from being called but does not necessarily stop pending requests
// from being sent.
// Cancel all pending requests.
void CancelPendingRequests();
// Indicates whether the client has any pending requests.
bool HasPendingRequests() const;
private:
void DoExecuteRequest(std::unique_ptr<ProtobufHttpRequest> request,
using PendingRequestList =
std::list<std::unique_ptr<ProtobufHttpRequestBase>>;
// std::list iterators are stable, so they survive list editing and only
// become invalidated when underlying element is deleted.
using PendingRequestListIterator = PendingRequestList::iterator;
void DoExecuteRequest(std::unique_ptr<ProtobufHttpRequestBase> request,
OAuthTokenGetter::Status status,
const std::string& user_email,
const std::string& access_token);
void OnResponse(std::unique_ptr<ProtobufHttpRequest> request,
std::unique_ptr<network::SimpleURLLoader> url_loader,
std::unique_ptr<std::string> response_body);
void CancelRequest(const PendingRequestListIterator& request_iterator);
std::string server_endpoint_;
OAuthTokenGetter* token_getter_;
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
PendingRequestList pending_requests_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<ProtobufHttpClient> weak_factory_{this};
};
......
......@@ -4,19 +4,52 @@
#include "remoting/base/protobuf_http_request.h"
#include "remoting/base/protobuf_http_request_config.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "third_party/protobuf/src/google/protobuf/message_lite.h"
namespace remoting {
namespace {
constexpr int kMaxResponseSizeKb = 512;
} // namespace
ProtobufHttpRequest::ProtobufHttpRequest(
const net::NetworkTrafficAnnotationTag& traffic_annotation)
: traffic_annotation(traffic_annotation) {}
std::unique_ptr<ProtobufHttpRequestConfig> config)
: ProtobufHttpRequestBase(std::move(config)) {}
ProtobufHttpRequest::~ProtobufHttpRequest() = default;
void ProtobufHttpRequest::SetTimeoutDuration(base::TimeDelta timeout_duration) {
timeout_duration_ = timeout_duration;
}
void ProtobufHttpRequest::OnAuthFailed(const ProtobufHttpStatus& status) {
std::move(response_callback_).Run(status);
}
void ProtobufHttpRequest::StartRequestInternal(
network::mojom::URLLoaderFactory* loader_factory) {
DCHECK(response_callback_);
// Safe to use unretained as callback will not be called once |url_loader_| is
// deleted.
url_loader_->DownloadToString(
loader_factory,
base::BindOnce(&ProtobufHttpRequest::OnResponse, base::Unretained(this)),
kMaxResponseSizeKb);
}
base::TimeDelta ProtobufHttpRequest::GetRequestTimeoutDuration() const {
return timeout_duration_;
}
void ProtobufHttpRequest::OnResponse(
const ProtobufHttpStatus& status,
std::unique_ptr<std::string> response_body) {
ProtobufHttpStatus status = GetUrlLoaderStatus();
std::move(response_callback_)
.Run(status.ok() ? ParseResponse(std::move(response_body)) : status);
std::move(invalidator_).Run();
}
ProtobufHttpStatus ProtobufHttpRequest::ParseResponse(
......
......@@ -5,35 +5,34 @@
#ifndef REMOTING_BASE_PROTOBUF_HTTP_REQUEST_H_
#define REMOTING_BASE_PROTOBUF_HTTP_REQUEST_H_
#include <memory>
#include <string>
#include "base/bind.h"
#include "base/callback.h"
#include "base/time/time.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "remoting/base/protobuf_http_status.h"
#include "third_party/protobuf/src/google/protobuf/message_lite.h"
#include "remoting/base/protobuf_http_request_base.h"
namespace google {
namespace protobuf {
class MessageLite;
} // namespace protobuf
} // namespace google
namespace remoting {
// A simple unary request. Caller needs to set all public members and call
// SetResponseCallback() before passing it to ProtobufHttpClient.
struct ProtobufHttpRequest final {
// A simple unary request.
class ProtobufHttpRequest final : public ProtobufHttpRequestBase {
public:
template <typename ResponseType>
using ResponseCallback =
base::OnceCallback<void(const ProtobufHttpStatus& status,
std::unique_ptr<ResponseType> response)>;
explicit ProtobufHttpRequest(
const net::NetworkTrafficAnnotationTag& traffic_annotation);
~ProtobufHttpRequest();
std::unique_ptr<ProtobufHttpRequestConfig> config);
~ProtobufHttpRequest() override;
const net::NetworkTrafficAnnotationTag traffic_annotation;
std::unique_ptr<google::protobuf::MessageLite> request_message;
std::string path;
bool authenticated = true;
base::TimeDelta timeout_duration = base::TimeDelta::FromSeconds(30);
// Sets the amount of time to wait before giving up on a given network request
// and considering it an error. The default value is 30s. Set it to zero to
// disable timeout.
void SetTimeoutDuration(base::TimeDelta timeout_duration);
// Sets the response callback. |ResponseType| needs to be a protobuf message
// type.
......@@ -54,15 +53,19 @@ struct ProtobufHttpRequest final {
}
private:
friend class ProtobufHttpClient;
// ProtobufHttpRequestBase implementations.
void OnAuthFailed(const ProtobufHttpStatus& status) override;
void StartRequestInternal(
network::mojom::URLLoaderFactory* loader_factory) override;
base::TimeDelta GetRequestTimeoutDuration() const override;
// To be called by ProtobufHttpClient.
void OnResponse(const ProtobufHttpStatus& status,
std::unique_ptr<std::string> response_body);
void OnResponse(std::unique_ptr<std::string> response_body);
// Parses |response_body| and writes it to |response_message_|.
ProtobufHttpStatus ParseResponse(std::unique_ptr<std::string> response_body);
base::TimeDelta timeout_duration_ = base::TimeDelta::FromSeconds(30);
// This is owned by |response_callback_|.
google::protobuf::MessageLite* response_message_;
base::OnceCallback<void(const ProtobufHttpStatus&)> response_callback_;
......
// Copyright 2020 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.
#include "remoting/base/protobuf_http_request_base.h"
#include "net/base/net_errors.h"
#include "remoting/base/protobuf_http_request_config.h"
#include "services/network/public/cpp/simple_url_loader.h"
namespace remoting {
ProtobufHttpRequestBase::ProtobufHttpRequestBase(
std::unique_ptr<ProtobufHttpRequestConfig> config)
: config_(std::move(config)) {
config_->Validate();
}
ProtobufHttpRequestBase::~ProtobufHttpRequestBase() {
#if DCHECK_IS_ON()
DCHECK(request_deadline_.is_null() ||
request_deadline_ >= base::TimeTicks::Now())
<< "The request must have been deleted before the deadline.";
#endif // DCHECK_IS_ON()
}
ProtobufHttpStatus ProtobufHttpRequestBase::GetUrlLoaderStatus() const {
net::Error net_error = static_cast<net::Error>(url_loader_->NetError());
if (net_error == net::Error::ERR_HTTP_RESPONSE_CODE_FAILURE &&
(!url_loader_->ResponseInfo() || !url_loader_->ResponseInfo()->headers)) {
LOG(ERROR) << "Can't find response header.";
net_error = net::Error::ERR_INVALID_RESPONSE;
}
return (net_error == net::Error::ERR_HTTP_RESPONSE_CODE_FAILURE ||
net_error == net::Error::OK)
? ProtobufHttpStatus(static_cast<net::HttpStatusCode>(
url_loader_->ResponseInfo()->headers->response_code()))
: ProtobufHttpStatus(net_error);
}
void ProtobufHttpRequestBase::StartRequest(
network::mojom::URLLoaderFactory* loader_factory,
std::unique_ptr<network::SimpleURLLoader> url_loader,
base::OnceClosure invalidator) {
DCHECK(!url_loader_);
DCHECK(!invalidator_);
url_loader_ = std::move(url_loader);
invalidator_ = std::move(invalidator);
StartRequestInternal(loader_factory);
#if DCHECK_IS_ON()
base::TimeDelta timeout_duration = GetRequestTimeoutDuration();
if (!timeout_duration.is_zero()) {
// Add a 500ms fuzz to account for task dispatching delay and other stuff.
request_deadline_ = base::TimeTicks::Now() + timeout_duration +
base::TimeDelta::FromMilliseconds(500);
}
#endif // DCHECK_IS_ON()
}
} // namespace remoting
// Copyright 2020 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 REMOTING_BASE_PROTOBUF_HTTP_REQUEST_BASE_H_
#define REMOTING_BASE_PROTOBUF_HTTP_REQUEST_BASE_H_
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/dcheck_is_on.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "remoting/base/protobuf_http_status.h"
namespace network {
namespace mojom {
class URLLoaderFactory;
} // namespace mojom
class SimpleURLLoader;
} // namespace network
namespace remoting {
class ProtobufHttpClient;
struct ProtobufHttpRequestConfig;
// Base request class for unary and server streaming requests.
class ProtobufHttpRequestBase {
public:
explicit ProtobufHttpRequestBase(
std::unique_ptr<ProtobufHttpRequestConfig> config);
virtual ~ProtobufHttpRequestBase();
const ProtobufHttpRequestConfig& config() const { return *config_; }
protected:
virtual void OnAuthFailed(const ProtobufHttpStatus& status) = 0;
virtual void StartRequestInternal(
network::mojom::URLLoaderFactory* loader_factory) = 0;
// Returns a deadline for when the request has to be finished. Returns zero
// if the request doesn't timeout. This is generally only useful for unary
// requests.
virtual base::TimeDelta GetRequestTimeoutDuration() const = 0;
// Returns the http status from |url_loader_|. Only useful when |url_loader_|
// informs that the request has been completed.
ProtobufHttpStatus GetUrlLoaderStatus() const;
std::unique_ptr<network::SimpleURLLoader> url_loader_;
// Subclass should run this closure whenever its lifetime ends, e.g. response
// is received or stream is closed. This will delete |this| from the parent
// ProtobufHttpClient.
base::OnceClosure invalidator_;
private:
friend class ProtobufHttpClient;
// Called by ProtobufHttpClient.
void StartRequest(network::mojom::URLLoaderFactory* loader_factory,
std::unique_ptr<network::SimpleURLLoader> url_loader,
base::OnceClosure invalidator);
std::unique_ptr<ProtobufHttpRequestConfig> config_;
#if DCHECK_IS_ON()
base::TimeTicks request_deadline_;
#endif // DCHECK_IS_ON()
};
} // namespace remoting
#endif // REMOTING_BASE_PROTOBUF_HTTP_REQUEST_BASE_H_
// Copyright 2020 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.
#include "remoting/base/protobuf_http_request_config.h"
#include "third_party/protobuf/src/google/protobuf/message_lite.h"
namespace remoting {
ProtobufHttpRequestConfig::ProtobufHttpRequestConfig(
const net::NetworkTrafficAnnotationTag& traffic_annotation)
: traffic_annotation(traffic_annotation) {}
ProtobufHttpRequestConfig::~ProtobufHttpRequestConfig() = default;
void ProtobufHttpRequestConfig::Validate() const {
DCHECK(request_message);
DCHECK(!path.empty());
}
} // namespace remoting
// Copyright 2020 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 REMOTING_BASE_PROTOBUF_HTTP_REQUEST_CONFIG_H_
#define REMOTING_BASE_PROTOBUF_HTTP_REQUEST_CONFIG_H_
#include <memory>
#include <string>
#include "net/traffic_annotation/network_traffic_annotation.h"
namespace google {
namespace protobuf {
class MessageLite;
} // namespace protobuf
} // namespace google
namespace remoting {
// Common configurations for unary and stream protobuf http requests. Caller
// needs to set all fields in this struct.
struct ProtobufHttpRequestConfig {
explicit ProtobufHttpRequestConfig(
const net::NetworkTrafficAnnotationTag& traffic_annotation);
~ProtobufHttpRequestConfig();
// Runs DCHECK's on the fields to make sure all fields have been set up.
void Validate() const;
const net::NetworkTrafficAnnotationTag traffic_annotation;
std::unique_ptr<google::protobuf::MessageLite> request_message;
std::string path;
bool authenticated = true;
};
} // namespace remoting
#endif // REMOTING_BASE_PROTOBUF_HTTP_REQUEST_CONFIG_H_
// Copyright 2020 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.
#include "remoting/base/protobuf_http_stream_request.h"
#include "base/bind.h"
#include "base/logging.h"
#include "remoting/base/protobuf_http_client.h"
#include "remoting/base/protobuf_http_request_config.h"
#include "remoting/base/protobuf_http_status.h"
#include "remoting/base/protobuf_http_stream_parser.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "third_party/protobuf/src/google/protobuf/message_lite.h"
namespace remoting {
ProtobufHttpStreamRequest::ProtobufHttpStreamRequest(
std::unique_ptr<ProtobufHttpRequestConfig> config)
: ProtobufHttpRequestBase(std::move(config)) {}
ProtobufHttpStreamRequest::~ProtobufHttpStreamRequest() = default;
void ProtobufHttpStreamRequest::SetStreamReadyCallback(
base::OnceClosure callback) {
stream_ready_callback_ = std::move(callback);
}
void ProtobufHttpStreamRequest::SetStreamClosedCallback(
StreamClosedCallback callback) {
stream_closed_callback_ = std::move(callback);
}
void ProtobufHttpStreamRequest::OnMessage(const std::string& message) {
std::unique_ptr<google::protobuf::MessageLite> protobuf_message(
default_message_->New());
if (protobuf_message->ParseFromString(message)) {
message_callback_.Run(std::move(protobuf_message));
} else {
LOG(ERROR) << "Failed to parse a stream message.";
}
}
void ProtobufHttpStreamRequest::OnStreamClosed(
const ProtobufHttpStatus& status) {
DCHECK(stream_closed_callback_);
DCHECK(invalidator_);
std::move(stream_closed_callback_).Run(status);
std::move(invalidator_).Run();
}
void ProtobufHttpStreamRequest::OnAuthFailed(const ProtobufHttpStatus& status) {
OnStreamClosed(status);
}
void ProtobufHttpStreamRequest::StartRequestInternal(
network::mojom::URLLoaderFactory* loader_factory) {
DCHECK(default_message_);
DCHECK(stream_ready_callback_);
DCHECK(stream_closed_callback_);
DCHECK(message_callback_);
// Safe to use unretained, as callbacks won't be called after |stream_parser_|
// is deleted.
stream_parser_ = std::make_unique<ProtobufHttpStreamParser>(
base::BindRepeating(&ProtobufHttpStreamRequest::OnMessage,
base::Unretained(this)),
base::BindRepeating(&ProtobufHttpStreamRequest::OnStreamClosed,
base::Unretained(this)));
url_loader_->DownloadAsStream(loader_factory, this);
}
base::TimeDelta ProtobufHttpStreamRequest::GetRequestTimeoutDuration() const {
return base::TimeDelta();
}
void ProtobufHttpStreamRequest::OnDataReceived(base::StringPiece string_piece,
base::OnceClosure resume) {
if (stream_ready_callback_) {
std::move(stream_ready_callback_).Run();
}
DCHECK(stream_parser_);
stream_parser_->Append(string_piece);
std::move(resume).Run();
}
void ProtobufHttpStreamRequest::OnComplete(bool success) {
OnStreamClosed(success ? ProtobufHttpStatus::OK : GetUrlLoaderStatus());
}
void ProtobufHttpStreamRequest::OnRetry(base::OnceClosure start_retry) {
NOTIMPLEMENTED();
}
} // namespace remoting
// Copyright 2020 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 REMOTING_BASE_PROTOBUF_HTTP_STREAM_REQUEST_H_
#define REMOTING_BASE_PROTOBUF_HTTP_STREAM_REQUEST_H_
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "remoting/base/protobuf_http_request_base.h"
#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
namespace google {
namespace protobuf {
class MessageLite;
} // namespace protobuf
} // namespace google
namespace remoting {
class ProtobufHttpClient;
class ProtobufHttpStatus;
class ProtobufHttpStreamParser;
// A server streaming request.
class ProtobufHttpStreamRequest final
: public ProtobufHttpRequestBase,
public network::SimpleURLLoaderStreamConsumer {
public:
template <typename MessageType>
using MessageCallback =
base::RepeatingCallback<void(std::unique_ptr<MessageType> message)>;
using StreamClosedCallback =
base::OnceCallback<void(const ProtobufHttpStatus& status)>;
explicit ProtobufHttpStreamRequest(
std::unique_ptr<ProtobufHttpRequestConfig> config);
~ProtobufHttpStreamRequest() override;
// Sets a callback that gets called when the stream is ready to receive data.
void SetStreamReadyCallback(base::OnceClosure callback);
// Sets a callback that gets called when the stream is closed.
void SetStreamClosedCallback(StreamClosedCallback callback);
// Sets the callback to be called every time a new message is received.
// |MessageType| needs to be a protobuf message type.
template <typename MessageType>
void SetMessageCallback(const MessageCallback<MessageType>& callback) {
default_message_ = &MessageType::default_instance();
message_callback_ = base::BindRepeating(
[](MessageCallback<MessageType> callback,
std::unique_ptr<google::protobuf::MessageLite> generic_message) {
std::move(callback).Run(std::unique_ptr<MessageType>(
static_cast<MessageType*>(generic_message.release())));
},
callback);
}
// TODO(yuweih): Consider adding an option to set timeout for
// |stream_ready_callback_|.
private:
friend class ProtobufHttpClient;
// ProtobufHttpStreamParser callbacks.
void OnMessage(const std::string& message);
void OnStreamClosed(const ProtobufHttpStatus& status);
// ProtobufHttpRequestBase implementations.
void OnAuthFailed(const ProtobufHttpStatus& status) override;
void StartRequestInternal(
network::mojom::URLLoaderFactory* loader_factory) override;
base::TimeDelta GetRequestTimeoutDuration() const override;
// network::SimpleURLLoaderStreamConsumer implementations.
void OnDataReceived(base::StringPiece string_piece,
base::OnceClosure resume) override;
void OnComplete(bool success) override;
void OnRetry(base::OnceClosure start_retry) override;
// Used to create new response message instances.
const google::protobuf::MessageLite* default_message_;
std::unique_ptr<ProtobufHttpStreamParser> stream_parser_;
base::OnceClosure stream_ready_callback_;
StreamClosedCallback stream_closed_callback_;
base::RepeatingCallback<void(std::unique_ptr<google::protobuf::MessageLite>)>
message_callback_;
};
} // namespace remoting
#endif // REMOTING_BASE_PROTOBUF_HTTP_STREAM_REQUEST_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment