per_user_topic_subscription_request.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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. #ifndef COMPONENTS_INVALIDATION_IMPL_PER_USER_TOPIC_SUBSCRIPTION_REQUEST_H_
  5. #define COMPONENTS_INVALIDATION_IMPL_PER_USER_TOPIC_SUBSCRIPTION_REQUEST_H_
  6. #include <memory>
  7. #include <string>
  8. #include <utility>
  9. #include "base/callback.h"
  10. #include "base/memory/weak_ptr.h"
  11. #include "components/invalidation/impl/status.h"
  12. #include "components/invalidation/public/invalidation_util.h"
  13. #include "net/http/http_request_headers.h"
  14. #include "services/data_decoder/public/cpp/data_decoder.h"
  15. #include "services/network/public/cpp/simple_url_loader.h"
  16. #include "services/network/public/mojom/url_loader_factory.mojom.h"
  17. #include "url/gurl.h"
  18. namespace invalidation {
  19. // A single request to subscribe to a topic on the per-user-topic service.
  20. class PerUserTopicSubscriptionRequest {
  21. public:
  22. // The request result consists of the request status and name of the private
  23. // topic. The |topic_name| will be empty in the case of error.
  24. using CompletedCallback =
  25. base::OnceCallback<void(const Status& status,
  26. const std::string& topic_name)>;
  27. enum RequestType { SUBSCRIBE, UNSUBSCRIBE };
  28. // Builds authenticated PerUserTopicSubscriptionRequests.
  29. class Builder {
  30. public:
  31. Builder();
  32. Builder(const Builder& other) = delete;
  33. Builder& operator=(const Builder& other) = delete;
  34. ~Builder();
  35. // Builds a Request object in order to perform the subscription.
  36. std::unique_ptr<PerUserTopicSubscriptionRequest> Build() const;
  37. Builder& SetInstanceIdToken(const std::string& token);
  38. Builder& SetScope(const std::string& scope);
  39. Builder& SetAuthenticationHeader(const std::string& auth_header);
  40. Builder& SetPublicTopicName(const Topic& topic);
  41. Builder& SetProjectId(const std::string& project_id);
  42. Builder& SetType(RequestType type);
  43. Builder& SetTopicIsPublic(bool topic_is_public);
  44. private:
  45. net::HttpRequestHeaders BuildHeaders() const;
  46. std::string BuildBody() const;
  47. std::unique_ptr<network::SimpleURLLoader> BuildURLFetcher(
  48. const net::HttpRequestHeaders& headers,
  49. const std::string& body,
  50. const GURL& url) const;
  51. // GCM subscription token obtained from GCM driver (instanceID::getToken()).
  52. std::string instance_id_token_;
  53. Topic topic_;
  54. std::string project_id_;
  55. std::string scope_;
  56. std::string auth_header_;
  57. RequestType type_;
  58. bool topic_is_public_ = false;
  59. };
  60. PerUserTopicSubscriptionRequest(
  61. const PerUserTopicSubscriptionRequest& other) = delete;
  62. PerUserTopicSubscriptionRequest& operator=(
  63. const PerUserTopicSubscriptionRequest& other) = delete;
  64. ~PerUserTopicSubscriptionRequest();
  65. // Starts an async request. The callback is invoked when the request succeeds
  66. // or fails. The callback is not called if the request is destroyed.
  67. void Start(CompletedCallback callback,
  68. network::mojom::URLLoaderFactory* loader_factory);
  69. GURL GetUrlForTesting() const { return url_; }
  70. private:
  71. PerUserTopicSubscriptionRequest();
  72. // The methods below may end up calling RunCompletedCallbackAndMaybeDie(),
  73. // which potentially lead to destroying |this|. Hence, |this| object must
  74. // assume that it is dead after invoking any of these methods and must not
  75. // run any more code.
  76. void OnURLFetchComplete(std::unique_ptr<std::string> response_body);
  77. void OnURLFetchCompleteInternal(int net_error,
  78. int response_code,
  79. std::unique_ptr<std::string> response_body);
  80. void OnJsonParse(data_decoder::DataDecoder::ValueOrError result);
  81. // Invokes |request_completed_callback_| with (|status|, |topic_name|). Per
  82. // the contract of this class, it is allowed for clients to delete this
  83. // object as part of the invocation of |request_completed_callback_|. Hence,
  84. // this object must assume that it is dead after invoking this method and
  85. // must not run any more code. See crbug.com/1054590 as sample issue for
  86. // violation of this rule.
  87. // |status| and |topic_name| are intentionally taken by value to avoid
  88. // references to members.
  89. void RunCompletedCallbackAndMaybeDie(Status status, std::string topic_name);
  90. // The fetcher for subscribing.
  91. std::unique_ptr<network::SimpleURLLoader> simple_loader_;
  92. // The callback to notify when URLFetcher finished and results are available.
  93. // When the request is finished/aborted/destroyed, it's called in the dtor!
  94. // Note: This callback should only be invoked from
  95. // RunCompletedCallbackAndMaybeDie(), as invoking it has the potential to
  96. // destroy this object per this class's contract.
  97. // TODO(crbug.com/1054759): find a way to avoid this fragile logic.
  98. CompletedCallback request_completed_callback_;
  99. // Full URL. Used in tests only.
  100. GURL url_;
  101. RequestType type_;
  102. std::string topic_;
  103. base::WeakPtrFactory<PerUserTopicSubscriptionRequest> weak_ptr_factory_{this};
  104. };
  105. } // namespace invalidation
  106. #endif // COMPONENTS_INVALIDATION_IMPL_PER_USER_TOPIC_SUBSCRIPTION_REQUEST_H_