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.
5 #include "google_apis/gcm/engine/registration_request.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/values.h"
11 #include "net/base/escape.h"
12 #include "net/http/http_request_headers.h"
13 #include "net/http/http_status_code.h"
14 #include "net/url_request/url_fetcher.h"
15 #include "net/url_request/url_request_context_getter.h"
16 #include "net/url_request/url_request_status.h"
23 const char kRegistrationURL
[] =
24 "https://android.clients.google.com/c2dm/register3";
25 const char kRegistrationRequestContentType
[] =
26 "application/x-www-form-urlencoded";
29 const char kAppIdKey
[] = "app";
30 const char kCertKey
[] = "cert";
31 const char kDeviceIdKey
[] = "device";
32 const char kLoginHeader
[] = "AidLogin";
33 const char kSenderKey
[] = "sender";
34 const char kUserAndroidIdKey
[] = "X-GOOG.USER_AID";
35 const char kUserSerialNumberKey
[] = "device_user_id";
37 // Request validation constants.
38 const size_t kMaxSenders
= 100;
40 // Response constants.
41 const char kTokenPrefix
[] = "token=";
43 void BuildFormEncoding(const std::string
& key
,
44 const std::string
& value
,
48 out
->append(key
+ "=" + net::EscapeUrlEncodedData(value
, true));
53 RegistrationRequest::RequestInfo::RequestInfo(
55 uint64 security_token
,
56 uint64 user_android_id
,
57 int64 user_serial_number
,
58 const std::string
& app_id
,
59 const std::string
& cert
,
60 const std::vector
<std::string
>& sender_ids
)
61 : android_id(android_id
),
62 security_token(security_token
),
63 user_android_id(user_android_id
),
64 user_serial_number(user_serial_number
),
67 sender_ids(sender_ids
) {}
69 RegistrationRequest::RequestInfo::~RequestInfo() {}
71 RegistrationRequest::RegistrationRequest(
72 const RequestInfo
& request_info
,
73 const RegistrationCallback
& callback
,
74 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter
)
75 : callback_(callback
),
76 request_info_(request_info
),
77 request_context_getter_(request_context_getter
) {}
79 RegistrationRequest::~RegistrationRequest() {}
81 void RegistrationRequest::Start() {
82 DCHECK(!callback_
.is_null());
83 DCHECK(request_info_
.android_id
!= 0UL);
84 DCHECK(request_info_
.security_token
!= 0UL);
85 DCHECK(!request_info_
.cert
.empty());
86 DCHECK(0 < request_info_
.sender_ids
.size() &&
87 request_info_
.sender_ids
.size() <= kMaxSenders
);
89 DCHECK(!url_fetcher_
.get());
90 url_fetcher_
.reset(net::URLFetcher::Create(
91 GURL(kRegistrationURL
), net::URLFetcher::POST
, this));
92 url_fetcher_
->SetRequestContext(request_context_getter_
);
94 std::string android_id
= base::Uint64ToString(request_info_
.android_id
);
95 std::string auth_header
=
96 std::string(net::HttpRequestHeaders::kAuthorization
) + ": " +
97 kLoginHeader
+ " " + android_id
+ ":" +
98 base::Uint64ToString(request_info_
.security_token
);
99 url_fetcher_
->SetExtraRequestHeaders(auth_header
);
102 BuildFormEncoding(kAppIdKey
, request_info_
.app_id
, &body
);
103 BuildFormEncoding(kCertKey
, request_info_
.cert
, &body
);
104 BuildFormEncoding(kDeviceIdKey
, android_id
, &body
);
107 for (std::vector
<std::string
>::const_iterator iter
=
108 request_info_
.sender_ids
.begin();
109 iter
!= request_info_
.sender_ids
.end();
111 DCHECK(!iter
->empty());
112 if (!senders
.empty())
114 senders
.append(*iter
);
116 BuildFormEncoding(kSenderKey
, senders
, &body
);
118 if (request_info_
.user_serial_number
!= 0) {
119 DCHECK(request_info_
.user_android_id
!= 0);
120 BuildFormEncoding(kUserSerialNumberKey
,
121 base::Int64ToString(request_info_
.user_serial_number
),
123 BuildFormEncoding(kUserAndroidIdKey
,
124 base::Uint64ToString(request_info_
.user_android_id
),
128 DVLOG(1) << "Registration request: " << body
;
129 url_fetcher_
->SetUploadData(kRegistrationRequestContentType
, body
);
131 DVLOG(1) << "Performing registration for: " << request_info_
.app_id
;
132 url_fetcher_
->Start();
135 void RegistrationRequest::OnURLFetchComplete(const net::URLFetcher
* source
) {
136 std::string response
;
137 if (!source
->GetStatus().is_success() ||
138 source
->GetResponseCode() != net::HTTP_OK
||
139 !source
->GetResponseAsString(&response
)) {
140 // TODO(fgoski): Introduce retry logic.
141 // TODO(jianli): Handle "Error=INVALID_SENDER".
142 LOG(ERROR
) << "Failed to get registration response: "
143 << source
->GetStatus().is_success() << " "
144 << source
->GetResponseCode();
149 DVLOG(1) << "Parsing registration response: " << response
;
150 size_t token_pos
= response
.find(kTokenPrefix
);
152 if (token_pos
!= std::string::npos
)
153 token
= response
.substr(token_pos
+ strlen(kTokenPrefix
));
155 LOG(ERROR
) << "Failed to extract token.";
156 callback_
.Run(token
);