1// Copyright 2014 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 COMPONENTS_INVALIDATION_GCM_NETWORK_CHANNEL_H_
6#define COMPONENTS_INVALIDATION_GCM_NETWORK_CHANNEL_H_
7
8#include <string>
9
10#include "base/basictypes.h"
11#include "base/compiler_specific.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/threading/non_thread_safe.h"
14#include "components/invalidation/gcm_network_channel_delegate.h"
15#include "components/invalidation/invalidation_export.h"
16#include "components/invalidation/sync_system_resources.h"
17#include "net/base/backoff_entry.h"
18#include "net/base/network_change_notifier.h"
19#include "net/url_request/url_fetcher_delegate.h"
20#include "url/gurl.h"
21
22class GoogleServiceAuthError;
23
24namespace syncer {
25class GCMNetworkChannel;
26
27// POD with copy of some statuses for debugging purposes.
28struct GCMNetworkChannelDiagnostic {
29  explicit GCMNetworkChannelDiagnostic(GCMNetworkChannel* parent);
30
31  // Collect all the internal variables in a single readable dictionary.
32  scoped_ptr<base::DictionaryValue> CollectDebugData() const;
33
34  // TODO(pavely): Move this toString to a more appropiate place in GCMClient.
35  std::string GCMClientResultToString(
36      const gcm::GCMClient::Result result) const;
37
38  GCMNetworkChannel* parent_;
39  bool last_message_empty_echo_token_;
40  base::Time last_message_received_time_;
41  int last_post_response_code_;
42  std::string registration_id_;
43  gcm::GCMClient::Result registration_result_;
44  int sent_messages_count_;
45};
46
47// GCMNetworkChannel is an implementation of SyncNetworkChannel that routes
48// messages through GCMService.
49class INVALIDATION_EXPORT_PRIVATE GCMNetworkChannel
50    : public SyncNetworkChannel,
51      public net::URLFetcherDelegate,
52      public net::NetworkChangeNotifier::NetworkChangeObserver,
53      public base::NonThreadSafe {
54 public:
55  GCMNetworkChannel(
56      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
57      scoped_ptr<GCMNetworkChannelDelegate> delegate);
58
59  virtual ~GCMNetworkChannel();
60
61  // invalidation::NetworkChannel implementation.
62  virtual void SendMessage(const std::string& message) OVERRIDE;
63  virtual void SetMessageReceiver(
64      invalidation::MessageCallback* incoming_receiver) OVERRIDE;
65
66  // SyncNetworkChannel implementation.
67  virtual void UpdateCredentials(const std::string& email,
68                                 const std::string& token) OVERRIDE;
69  virtual int GetInvalidationClientType() OVERRIDE;
70  virtual void RequestDetailedStatus(
71      base::Callback<void(const base::DictionaryValue&)> callback) OVERRIDE;
72
73  // URLFetcherDelegate implementation.
74  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
75
76  // NetworkChangeObserver implementation.
77  virtual void OnNetworkChanged(
78      net::NetworkChangeNotifier::ConnectionType connection_type) OVERRIDE;
79
80 protected:
81  void ResetRegisterBackoffEntryForTest(
82      const net::BackoffEntry::Policy* policy);
83
84  virtual GURL BuildUrl(const std::string& registration_id);
85
86 private:
87  friend class GCMNetworkChannelTest;
88  void Register();
89  void OnRegisterComplete(const std::string& registration_id,
90                          gcm::GCMClient::Result result);
91  void RequestAccessToken();
92  void OnGetTokenComplete(const GoogleServiceAuthError& error,
93                          const std::string& token);
94  void OnIncomingMessage(const std::string& message,
95                         const std::string& echo_token);
96  void OnConnectionStateChanged(bool online);
97  void UpdateGcmChannelState(bool online);
98  void UpdateHttpChannelState(bool online);
99  // Base64 encoding/decoding with URL safe alphabet.
100  // http://tools.ietf.org/html/rfc4648#page-7
101  static void Base64EncodeURLSafe(const std::string& input,
102                                  std::string* output);
103  static bool Base64DecodeURLSafe(const std::string& input,
104                                  std::string* output);
105
106  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
107  scoped_ptr<GCMNetworkChannelDelegate> delegate_;
108
109  // Message is saved until all conditions are met: there is valid
110  // registration_id and access_token.
111  std::string cached_message_;
112
113  // Access token is saved because in case of auth failure from server we need
114  // to invalidate it.
115  std::string access_token_;
116
117  // GCM registration_id is requested one at startup and never refreshed until
118  // next restart.
119  std::string registration_id_;
120  scoped_ptr<net::BackoffEntry> register_backoff_entry_;
121
122  scoped_ptr<net::URLFetcher> fetcher_;
123
124  // cacheinvalidation client receives echo_token with incoming message from
125  // GCM and shuld include it in headers with outgoing message over http.
126  std::string echo_token_;
127
128  // State of gcm and http channels. GCMNetworkChannel will only report
129  // INVALIDATIONS_ENABLED if both channels are online.
130  bool gcm_channel_online_;
131  bool http_channel_online_;
132
133  GCMNetworkChannelDiagnostic diagnostic_info_;
134
135  base::WeakPtrFactory<GCMNetworkChannel> weak_factory_;
136
137  DISALLOW_COPY_AND_ASSIGN(GCMNetworkChannel);
138};
139
140}  // namespace syncer
141
142#endif  // COMPONENTS_INVALIDATION_GCM_NETWORK_CHANNEL_H_
143