Remove uses of WaitForExitCode
[chromium-blink-merge.git] / cloud_print / service / service_state.cc
blob1164e960df9d0ba3b0c1f57dd22fec3d4dcdabbf
1 // Copyright (c) 2012 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 "cloud_print/service/service_state.h"
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "net/base/elements_upload_data_stream.h"
14 #include "net/base/escape.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/load_flags.h"
17 #include "net/base/request_priority.h"
18 #include "net/base/upload_bytes_element_reader.h"
19 #include "net/url_request/url_request.h"
20 #include "net/url_request/url_request_context.h"
21 #include "net/url_request/url_request_context_builder.h"
23 namespace {
25 const char kCloudPrintJsonName[] = "cloud_print";
26 const char kEnabledOptionName[] = "enabled";
28 const char kEmailOptionName[] = "email";
29 const char kProxyIdOptionName[] = "proxy_id";
30 const char kRobotEmailOptionName[] = "robot_email";
31 const char kRobotTokenOptionName[] = "robot_refresh_token";
32 const char kAuthTokenOptionName[] = "auth_token";
33 const char kXmppAuthTokenOptionName[] = "xmpp_auth_token";
35 const char kClientLoginUrl[] = "https://www.google.com/accounts/ClientLogin";
37 const int64 kRequestTimeoutMs = 10 * 1000;
39 class ServiceStateURLRequestDelegate : public net::URLRequest::Delegate {
40 public:
41 void OnResponseStarted(net::URLRequest* request) override {
42 if (request->GetResponseCode() == 200) {
43 Read(request);
44 if (request->status().is_io_pending())
45 return;
47 request->Cancel();
50 void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
51 Read(request);
52 if (!request->status().is_io_pending())
53 base::MessageLoop::current()->Quit();
56 const std::string& data() const {
57 return data_;
60 private:
61 void Read(net::URLRequest* request) {
62 // Read as many bytes as are available synchronously.
63 const int kBufSize = 100000;
64 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kBufSize));
65 int num_bytes = 0;
66 while (request->Read(buf.get(), kBufSize, &num_bytes)) {
67 data_.append(buf->data(), buf->data() + num_bytes);
70 std::string data_;
74 void SetNotEmptyJsonString(base::DictionaryValue* dictionary,
75 const std::string& name,
76 const std::string& value) {
77 if (!value.empty())
78 dictionary->SetString(name, value);
81 } // namespace
83 ServiceState::ServiceState() {
84 Reset();
87 ServiceState::~ServiceState() {
90 void ServiceState::Reset() {
91 email_.clear();
92 proxy_id_.clear();
93 robot_email_.clear();
94 robot_token_.clear();
95 auth_token_.clear();
96 xmpp_auth_token_.clear();
99 bool ServiceState::FromString(const std::string& json) {
100 Reset();
101 scoped_ptr<base::Value> data(base::JSONReader::Read(json));
102 if (!data.get())
103 return false;
105 const base::DictionaryValue* services = NULL;
106 if (!data->GetAsDictionary(&services))
107 return false;
109 const base::DictionaryValue* cloud_print = NULL;
110 if (!services->GetDictionary(kCloudPrintJsonName, &cloud_print))
111 return false;
113 bool valid_file = true;
114 // Don't exit on fail. Collect all data for re-use by user later.
115 if (!cloud_print->GetBoolean(kEnabledOptionName, &valid_file))
116 valid_file = false;
118 cloud_print->GetString(kEmailOptionName, &email_);
119 cloud_print->GetString(kProxyIdOptionName, &proxy_id_);
120 cloud_print->GetString(kRobotEmailOptionName, &robot_email_);
121 cloud_print->GetString(kRobotTokenOptionName, &robot_token_);
122 cloud_print->GetString(kAuthTokenOptionName, &auth_token_);
123 cloud_print->GetString(kXmppAuthTokenOptionName, &xmpp_auth_token_);
125 return valid_file && IsValid();
128 bool ServiceState::IsValid() const {
129 if (email_.empty() || proxy_id_.empty())
130 return false;
131 bool valid_robot = !robot_email_.empty() && !robot_token_.empty();
132 bool valid_auth = !auth_token_.empty() && !xmpp_auth_token_.empty();
133 return valid_robot || valid_auth;
136 std::string ServiceState::ToString() {
137 scoped_ptr<base::DictionaryValue> services(new base::DictionaryValue());
139 scoped_ptr<base::DictionaryValue> cloud_print(new base::DictionaryValue());
140 cloud_print->SetBoolean(kEnabledOptionName, true);
142 SetNotEmptyJsonString(cloud_print.get(), kEmailOptionName, email_);
143 SetNotEmptyJsonString(cloud_print.get(), kProxyIdOptionName, proxy_id_);
144 SetNotEmptyJsonString(cloud_print.get(), kRobotEmailOptionName, robot_email_);
145 SetNotEmptyJsonString(cloud_print.get(), kRobotTokenOptionName, robot_token_);
146 SetNotEmptyJsonString(cloud_print.get(), kAuthTokenOptionName, auth_token_);
147 SetNotEmptyJsonString(cloud_print.get(), kXmppAuthTokenOptionName,
148 xmpp_auth_token_);
150 services->Set(kCloudPrintJsonName, cloud_print.release());
152 std::string json;
153 base::JSONWriter::WriteWithOptions(services.get(),
154 base::JSONWriter::OPTIONS_PRETTY_PRINT,
155 &json);
156 return json;
159 std::string ServiceState::LoginToGoogle(const std::string& service,
160 const std::string& email,
161 const std::string& password) {
162 base::MessageLoopForIO loop;
164 net::URLRequestContextBuilder builder;
165 scoped_ptr<net::URLRequestContext> context(builder.Build());
167 ServiceStateURLRequestDelegate fetcher_delegate;
168 GURL url(kClientLoginUrl);
170 std::string post_body;
171 post_body += "accountType=GOOGLE";
172 post_body += "&Email=" + net::EscapeUrlEncodedData(email, true);
173 post_body += "&Passwd=" + net::EscapeUrlEncodedData(password, true);
174 post_body += "&source=" + net::EscapeUrlEncodedData("CP-Service", true);
175 post_body += "&service=" + net::EscapeUrlEncodedData(service, true);
177 scoped_ptr<net::URLRequest> request(context->CreateRequest(
178 url, net::DEFAULT_PRIORITY, &fetcher_delegate, NULL));
179 int load_flags = request->load_flags();
180 load_flags = load_flags | net::LOAD_DO_NOT_SEND_COOKIES;
181 load_flags = load_flags | net::LOAD_DO_NOT_SAVE_COOKIES;
182 request->SetLoadFlags(load_flags);
184 scoped_ptr<net::UploadElementReader> reader(
185 net::UploadOwnedBytesElementReader::CreateWithString(post_body));
186 request->set_upload(
187 net::ElementsUploadDataStream::CreateWithReader(reader.Pass(), 0));
188 request->SetExtraRequestHeaderByName(
189 "Content-Type", "application/x-www-form-urlencoded", true);
190 request->set_method("POST");
191 request->Start();
193 base::MessageLoop::current()->PostDelayedTask(
194 FROM_HERE,
195 base::MessageLoop::QuitClosure(),
196 base::TimeDelta::FromMilliseconds(kRequestTimeoutMs));
198 base::MessageLoop::current()->Run();
200 const char kAuthStart[] = "Auth=";
201 std::vector<std::string> lines;
202 Tokenize(fetcher_delegate.data(), "\r\n", &lines);
203 for (size_t i = 0; i < lines.size(); ++i) {
204 if (StartsWithASCII(lines[i], kAuthStart, false))
205 return lines[i].substr(arraysize(kAuthStart) - 1);
208 return std::string();
211 bool ServiceState::Configure(const std::string& email,
212 const std::string& password,
213 const std::string& proxy_id) {
214 robot_token_.clear();
215 robot_email_.clear();
216 email_ = email;
217 proxy_id_ = proxy_id;
218 auth_token_ = LoginToGoogle("cloudprint", email_, password);
219 xmpp_auth_token_ = LoginToGoogle("chromiumsync", email_, password);
220 return IsValid();