Avoid crashing when going back/forward to debug URLs on a sad WebUI tab.
[chromium-blink-merge.git] / chrome / service / cloud_print / cloud_print_connector.cc
blob0a7d7542e3976a8b20f23ac237adbe0366550579
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 "chrome/service/cloud_print/cloud_print_connector.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/location.h"
10 #include "base/md5.h"
11 #include "base/rand_util.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "base/values.h"
20 #include "chrome/common/cloud_print/cloud_print_constants.h"
21 #include "chrome/common/cloud_print/cloud_print_helpers.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "chrome/service/cloud_print/cloud_print_service_helpers.h"
24 #include "net/base/mime_util.h"
25 #include "ui/base/l10n/l10n_util.h"
27 namespace cloud_print {
29 CloudPrintConnector::CloudPrintConnector(Client* client,
30 const ConnectorSettings& settings)
31 : client_(client),
32 next_response_handler_(NULL),
33 stats_ptr_factory_(this) {
34 settings_.CopyFrom(settings);
37 bool CloudPrintConnector::InitPrintSystem() {
38 if (print_system_.get())
39 return true;
40 print_system_ = PrintSystem::CreateInstance(
41 settings_.print_system_settings());
42 if (!print_system_.get()) {
43 NOTREACHED();
44 return false; // No memory.
46 PrintSystem::PrintSystemResult result = print_system_->Init();
47 if (!result.succeeded()) {
48 print_system_ = NULL;
49 // We could not initialize the print system. We need to notify the server.
50 ReportUserMessage(kPrintSystemFailedMessageId, result.message());
51 return false;
53 return true;
56 void CloudPrintConnector::ScheduleStatsReport() {
57 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
58 FROM_HERE, base::Bind(&CloudPrintConnector::ReportStats,
59 stats_ptr_factory_.GetWeakPtr()),
60 base::TimeDelta::FromHours(1));
63 void CloudPrintConnector::ReportStats() {
64 PrinterJobHandler::ReportsStats();
65 ScheduleStatsReport();
68 bool CloudPrintConnector::Start() {
69 VLOG(1) << "CP_CONNECTOR: Starting connector"
70 << ", proxy id: " << settings_.proxy_id();
72 pending_tasks_.clear();
74 if (!InitPrintSystem())
75 return false;
77 ScheduleStatsReport();
79 // Start watching for updates from the print system.
80 print_server_watcher_ = print_system_->CreatePrintServerWatcher();
81 print_server_watcher_->StartWatching(this);
83 // Get list of registered printers.
84 AddPendingAvailableTask();
85 return true;
88 void CloudPrintConnector::Stop() {
89 VLOG(1) << "CP_CONNECTOR: Stopping connector"
90 << ", proxy id: " << settings_.proxy_id();
91 DCHECK(IsRunning());
92 // Do uninitialization here.
93 stats_ptr_factory_.InvalidateWeakPtrs();
94 pending_tasks_.clear();
95 print_server_watcher_ = NULL;
96 request_ = NULL;
99 bool CloudPrintConnector::IsRunning() {
100 return print_server_watcher_.get() != NULL;
103 void CloudPrintConnector::GetPrinterIds(std::list<std::string>* printer_ids) {
104 DCHECK(printer_ids);
105 printer_ids->clear();
106 for (JobHandlerMap::const_iterator iter = job_handler_map_.begin();
107 iter != job_handler_map_.end(); ++iter) {
108 printer_ids->push_back(iter->first);
112 void CloudPrintConnector::RegisterPrinters(
113 const printing::PrinterList& printers) {
114 if (!IsRunning())
115 return;
116 printing::PrinterList::const_iterator it;
117 for (it = printers.begin(); it != printers.end(); ++it) {
118 if (settings_.ShouldConnect(it->printer_name))
119 AddPendingRegisterTask(*it);
123 // Check for jobs for specific printer
124 void CloudPrintConnector::CheckForJobs(const std::string& reason,
125 const std::string& printer_id) {
126 if (!IsRunning())
127 return;
128 if (!printer_id.empty()) {
129 JobHandlerMap::iterator index = job_handler_map_.find(printer_id);
130 if (index != job_handler_map_.end()) {
131 index->second->CheckForJobs(reason);
132 } else {
133 std::string status_message = l10n_util::GetStringUTF8(
134 IDS_CLOUD_PRINT_ZOMBIE_PRINTER);
135 LOG(ERROR) << "CP_CONNECTOR: " << status_message <<
136 " Printer_id: " << printer_id;
137 ReportUserMessage(kZombiePrinterMessageId, status_message);
139 } else {
140 for (JobHandlerMap::iterator index = job_handler_map_.begin();
141 index != job_handler_map_.end(); index++) {
142 index->second->CheckForJobs(reason);
147 void CloudPrintConnector::UpdatePrinterSettings(const std::string& printer_id) {
148 // Since connector is managing many printers we need to go through all of them
149 // to select the correct settings.
150 GURL printer_list_url = GetUrlForPrinterList(
151 settings_.server_url(), settings_.proxy_id());
152 StartGetRequest(
153 printer_list_url,
154 kCloudPrintRegisterMaxRetryCount,
155 &CloudPrintConnector::HandlePrinterListResponseSettingsUpdate);
158 void CloudPrintConnector::OnPrinterAdded() {
159 AddPendingAvailableTask();
162 void CloudPrintConnector::OnPrinterDeleted(const std::string& printer_id) {
163 AddPendingDeleteTask(printer_id);
166 void CloudPrintConnector::OnAuthError() {
167 client_->OnAuthFailed();
170 // CloudPrintURLFetcher::Delegate implementation.
171 CloudPrintURLFetcher::ResponseAction CloudPrintConnector::HandleRawData(
172 const net::URLFetcher* source,
173 const GURL& url,
174 const std::string& data) {
175 // If this notification came as a result of user message call, stop it.
176 // Otherwise proceed continue processing.
177 if (user_message_request_.get() &&
178 user_message_request_->IsSameRequest(source))
179 return CloudPrintURLFetcher::STOP_PROCESSING;
180 return CloudPrintURLFetcher::CONTINUE_PROCESSING;
183 CloudPrintURLFetcher::ResponseAction CloudPrintConnector::HandleJSONData(
184 const net::URLFetcher* source,
185 const GURL& url,
186 base::DictionaryValue* json_data,
187 bool succeeded) {
188 if (!IsRunning()) // Orphant response. Connector has been stopped already.
189 return CloudPrintURLFetcher::STOP_PROCESSING;
191 DCHECK(next_response_handler_);
192 return (this->*next_response_handler_)(source, url, json_data, succeeded);
195 CloudPrintURLFetcher::ResponseAction CloudPrintConnector::OnRequestAuthError() {
196 OnAuthError();
197 return CloudPrintURLFetcher::STOP_PROCESSING;
200 std::string CloudPrintConnector::GetAuthHeader() {
201 return GetCloudPrintAuthHeaderFromStore();
204 CloudPrintConnector::~CloudPrintConnector() {}
206 CloudPrintURLFetcher::ResponseAction
207 CloudPrintConnector::HandlePrinterListResponse(
208 const net::URLFetcher* source,
209 const GURL& url,
210 base::DictionaryValue* json_data,
211 bool succeeded) {
212 DCHECK(succeeded);
213 if (!succeeded)
214 return CloudPrintURLFetcher::RETRY_REQUEST;
216 UpdateSettingsFromPrintersList(json_data);
218 // Now we need to get the list of printers from the print system
219 // and split printers into 3 categories:
220 // - existing and registered printers
221 // - new printers
222 // - deleted printers
224 // Get list of the printers from the print system.
225 printing::PrinterList local_printers;
226 PrintSystem::PrintSystemResult result =
227 print_system_->EnumeratePrinters(&local_printers);
228 bool full_list = result.succeeded();
229 if (!full_list) {
230 std::string message = result.message();
231 if (message.empty())
232 message = l10n_util::GetStringFUTF8(IDS_CLOUD_PRINT_ENUM_FAILED,
233 l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT));
234 // There was a failure enumerating printers. Send a message to the server.
235 ReportUserMessage(kEnumPrintersFailedMessageId, message);
238 // Go through the list of the cloud printers and init print job handlers.
239 base::ListValue* printer_list = NULL;
240 // There may be no "printers" value in the JSON
241 if (json_data->GetList(kPrinterListValue, &printer_list) && printer_list) {
242 for (size_t index = 0; index < printer_list->GetSize(); index++) {
243 base::DictionaryValue* printer_data = NULL;
244 if (printer_list->GetDictionary(index, &printer_data)) {
245 std::string printer_name;
246 printer_data->GetString(kNameValue, &printer_name);
247 std::string printer_id;
248 printer_data->GetString(kIdValue, &printer_id);
250 if (!settings_.ShouldConnect(printer_name)) {
251 VLOG(1) << "CP_CONNECTOR: Deleting " << printer_name <<
252 " id: " << printer_id << " as blacklisted";
253 AddPendingDeleteTask(printer_id);
254 } else if (RemovePrinterFromList(printer_name, &local_printers)) {
255 InitJobHandlerForPrinter(printer_data);
256 } else {
257 // Cloud printer is not found on the local system.
258 if (full_list || settings_.delete_on_enum_fail()) {
259 // Delete if we get the full list of printers or
260 // |delete_on_enum_fail_| is set.
261 VLOG(1) << "CP_CONNECTOR: Deleting " << printer_name <<
262 " id: " << printer_id <<
263 " full_list: " << full_list <<
264 " delete_on_enum_fail: " << settings_.delete_on_enum_fail();
265 AddPendingDeleteTask(printer_id);
266 } else {
267 LOG(ERROR) << "CP_CONNECTOR: Printer: " << printer_name <<
268 " id: " << printer_id <<
269 " not found in print system and full printer list was" <<
270 " not received. Printer will not be able to process" <<
271 " jobs.";
274 } else {
275 NOTREACHED();
280 request_ = NULL;
282 RegisterPrinters(local_printers);
283 ContinuePendingTaskProcessing(); // Continue processing background tasks.
284 return CloudPrintURLFetcher::STOP_PROCESSING;
287 CloudPrintURLFetcher::ResponseAction
288 CloudPrintConnector::HandlePrinterListResponseSettingsUpdate(
289 const net::URLFetcher* source,
290 const GURL& url,
291 base::DictionaryValue* json_data,
292 bool succeeded) {
293 DCHECK(succeeded);
294 if (!succeeded)
295 return CloudPrintURLFetcher::RETRY_REQUEST;
297 UpdateSettingsFromPrintersList(json_data);
298 return CloudPrintURLFetcher::STOP_PROCESSING;
301 CloudPrintURLFetcher::ResponseAction
302 CloudPrintConnector::HandlePrinterDeleteResponse(
303 const net::URLFetcher* source,
304 const GURL& url,
305 base::DictionaryValue* json_data,
306 bool succeeded) {
307 VLOG(1) << "CP_CONNECTOR: Handler printer delete response"
308 << ", succeeded: " << succeeded
309 << ", url: " << url;
310 ContinuePendingTaskProcessing(); // Continue processing background tasks.
311 return CloudPrintURLFetcher::STOP_PROCESSING;
314 CloudPrintURLFetcher::ResponseAction
315 CloudPrintConnector::HandleRegisterPrinterResponse(
316 const net::URLFetcher* source,
317 const GURL& url,
318 base::DictionaryValue* json_data,
319 bool succeeded) {
320 VLOG(1) << "CP_CONNECTOR: Handler printer register response"
321 << ", succeeded: " << succeeded
322 << ", url: " << url;
323 if (succeeded) {
324 base::ListValue* printer_list = NULL;
325 // There should be a "printers" value in the JSON
326 if (json_data->GetList(kPrinterListValue, &printer_list)) {
327 base::DictionaryValue* printer_data = NULL;
328 if (printer_list->GetDictionary(0, &printer_data))
329 InitJobHandlerForPrinter(printer_data);
332 ContinuePendingTaskProcessing(); // Continue processing background tasks.
333 return CloudPrintURLFetcher::STOP_PROCESSING;
337 void CloudPrintConnector::StartGetRequest(const GURL& url,
338 int max_retries,
339 ResponseHandler handler) {
340 next_response_handler_ = handler;
341 request_ = CloudPrintURLFetcher::Create();
342 request_->StartGetRequest(CloudPrintURLFetcher::REQUEST_UPDATE_JOB,
343 url, this, max_retries, std::string());
346 void CloudPrintConnector::StartPostRequest(
347 CloudPrintURLFetcher::RequestType type,
348 const GURL& url,
349 int max_retries,
350 const std::string& mime_type,
351 const std::string& post_data,
352 ResponseHandler handler) {
353 next_response_handler_ = handler;
354 request_ = CloudPrintURLFetcher::Create();
355 request_->StartPostRequest(
356 type, url, this, max_retries, mime_type, post_data, std::string());
359 void CloudPrintConnector::ReportUserMessage(const std::string& message_id,
360 const std::string& failure_msg) {
361 // This is a fire and forget type of function.
362 // Result of this request will be ignored.
363 std::string mime_boundary;
364 CreateMimeBoundaryForUpload(&mime_boundary);
365 GURL url = GetUrlForUserMessage(settings_.server_url(), message_id);
366 std::string post_data;
367 net::AddMultipartValueForUpload(kMessageTextValue, failure_msg, mime_boundary,
368 std::string(), &post_data);
369 net::AddMultipartFinalDelimiterForUpload(mime_boundary, &post_data);
370 std::string mime_type("multipart/form-data; boundary=");
371 mime_type += mime_boundary;
372 user_message_request_ = CloudPrintURLFetcher::Create();
373 user_message_request_->StartPostRequest(
374 CloudPrintURLFetcher::REQUEST_USER_MESSAGE, url, this, 1, mime_type,
375 post_data, std::string());
378 bool CloudPrintConnector::RemovePrinterFromList(
379 const std::string& printer_name,
380 printing::PrinterList* printer_list) {
381 for (printing::PrinterList::iterator index = printer_list->begin();
382 index != printer_list->end(); index++) {
383 if (IsSamePrinter(index->printer_name, printer_name)) {
384 index = printer_list->erase(index);
385 return true;
388 return false;
391 void CloudPrintConnector::InitJobHandlerForPrinter(
392 base::DictionaryValue* printer_data) {
393 DCHECK(printer_data);
394 PrinterJobHandler::PrinterInfoFromCloud printer_info_cloud;
395 printer_data->GetString(kIdValue, &printer_info_cloud.printer_id);
396 DCHECK(!printer_info_cloud.printer_id.empty());
397 VLOG(1) << "CP_CONNECTOR: Init job handler"
398 << ", printer id: " << printer_info_cloud.printer_id;
399 JobHandlerMap::iterator index = job_handler_map_.find(
400 printer_info_cloud.printer_id);
401 if (index != job_handler_map_.end())
402 return; // Nothing to do if we already have a job handler for this printer.
404 printing::PrinterBasicInfo printer_info;
405 printer_data->GetString(kNameValue, &printer_info.printer_name);
406 DCHECK(!printer_info.printer_name.empty());
407 printer_data->GetString(kPrinterDescValue,
408 &printer_info.printer_description);
409 // Printer status is a string value which actually contains an integer.
410 std::string printer_status;
411 if (printer_data->GetString(kPrinterStatusValue, &printer_status)) {
412 base::StringToInt(printer_status, &printer_info.printer_status);
414 printer_data->GetString(kPrinterCapsHashValue,
415 &printer_info_cloud.caps_hash);
416 base::ListValue* tags_list = NULL;
417 if (printer_data->GetList(kTagsValue, &tags_list) && tags_list) {
418 for (size_t index = 0; index < tags_list->GetSize(); index++) {
419 std::string tag;
420 if (tags_list->GetString(index, &tag) &&
421 base::StartsWith(tag, kCloudPrintServiceTagsHashTagName,
422 base::CompareCase::INSENSITIVE_ASCII)) {
423 std::vector<std::string> tag_parts = base::SplitString(
424 tag, "=", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
425 DCHECK_EQ(tag_parts.size(), 2U);
426 if (tag_parts.size() == 2)
427 printer_info_cloud.tags_hash = tag_parts[1];
432 int xmpp_timeout = 0;
433 printer_data->GetInteger(kLocalSettingsPendingXmppValue, &xmpp_timeout);
434 printer_info_cloud.current_xmpp_timeout = settings_.xmpp_ping_timeout_sec();
435 printer_info_cloud.pending_xmpp_timeout = xmpp_timeout;
437 scoped_refptr<PrinterJobHandler> job_handler;
438 job_handler = new PrinterJobHandler(printer_info,
439 printer_info_cloud,
440 settings_.server_url(),
441 print_system_.get(),
442 this);
443 job_handler_map_[printer_info_cloud.printer_id] = job_handler;
444 job_handler->Initialize();
447 void CloudPrintConnector::UpdateSettingsFromPrintersList(
448 base::DictionaryValue* json_data) {
449 base::ListValue* printer_list = NULL;
450 int min_xmpp_timeout = std::numeric_limits<int>::max();
451 // There may be no "printers" value in the JSON
452 if (json_data->GetList(kPrinterListValue, &printer_list) && printer_list) {
453 for (size_t index = 0; index < printer_list->GetSize(); index++) {
454 base::DictionaryValue* printer_data = NULL;
455 if (printer_list->GetDictionary(index, &printer_data)) {
456 int xmpp_timeout = 0;
457 if (printer_data->GetInteger(kLocalSettingsPendingXmppValue,
458 &xmpp_timeout)) {
459 min_xmpp_timeout = std::min(xmpp_timeout, min_xmpp_timeout);
465 if (min_xmpp_timeout != std::numeric_limits<int>::max()) {
466 DCHECK(min_xmpp_timeout >= kMinXmppPingTimeoutSecs);
467 settings_.SetXmppPingTimeoutSec(min_xmpp_timeout);
468 client_->OnXmppPingUpdated(min_xmpp_timeout);
473 void CloudPrintConnector::AddPendingAvailableTask() {
474 PendingTask task;
475 task.type = PENDING_PRINTERS_AVAILABLE;
476 AddPendingTask(task);
479 void CloudPrintConnector::AddPendingDeleteTask(const std::string& id) {
480 PendingTask task;
481 task.type = PENDING_PRINTER_DELETE;
482 task.printer_id = id;
483 AddPendingTask(task);
486 void CloudPrintConnector::AddPendingRegisterTask(
487 const printing::PrinterBasicInfo& info) {
488 PendingTask task;
489 task.type = PENDING_PRINTER_REGISTER;
490 task.printer_info = info;
491 AddPendingTask(task);
494 void CloudPrintConnector::AddPendingTask(const PendingTask& task) {
495 pending_tasks_.push_back(task);
496 // If this is the only pending task, we need to start the process.
497 if (pending_tasks_.size() == 1) {
498 base::ThreadTaskRunnerHandle::Get()->PostTask(
499 FROM_HERE, base::Bind(&CloudPrintConnector::ProcessPendingTask, this));
503 void CloudPrintConnector::ProcessPendingTask() {
504 if (!IsRunning())
505 return; // Orphant call.
506 if (pending_tasks_.size() == 0)
507 return; // No peding tasks.
509 PendingTask task = pending_tasks_.front();
511 switch (task.type) {
512 case PENDING_PRINTERS_AVAILABLE :
513 OnPrintersAvailable();
514 break;
515 case PENDING_PRINTER_REGISTER :
516 OnPrinterRegister(task.printer_info);
517 break;
518 case PENDING_PRINTER_DELETE :
519 OnPrinterDelete(task.printer_id);
520 break;
521 default:
522 NOTREACHED();
526 void CloudPrintConnector::ContinuePendingTaskProcessing() {
527 if (pending_tasks_.size() == 0)
528 return; // No pending tasks.
530 // Delete current task and repost if we have more task available.
531 pending_tasks_.pop_front();
532 if (pending_tasks_.size() != 0) {
533 base::ThreadTaskRunnerHandle::Get()->PostTask(
534 FROM_HERE, base::Bind(&CloudPrintConnector::ProcessPendingTask, this));
538 void CloudPrintConnector::OnPrintersAvailable() {
539 GURL printer_list_url = GetUrlForPrinterList(
540 settings_.server_url(), settings_.proxy_id());
541 StartGetRequest(printer_list_url,
542 kCloudPrintRegisterMaxRetryCount,
543 &CloudPrintConnector::HandlePrinterListResponse);
546 void CloudPrintConnector::OnPrinterRegister(
547 const printing::PrinterBasicInfo& info) {
548 for (JobHandlerMap::iterator it = job_handler_map_.begin();
549 it != job_handler_map_.end(); ++it) {
550 if (IsSamePrinter(it->second->GetPrinterName(), info.printer_name)) {
551 // Printer already registered, continue to the next task.
552 ContinuePendingTaskProcessing();
553 return;
557 // Asynchronously fetch the printer caps and defaults. The story will
558 // continue in OnReceivePrinterCaps.
559 print_system_->GetPrinterCapsAndDefaults(
560 info.printer_name.c_str(),
561 base::Bind(&CloudPrintConnector::OnReceivePrinterCaps,
562 base::Unretained(this)));
565 void CloudPrintConnector::OnPrinterDelete(const std::string& printer_id) {
566 // Remove corresponding printer job handler.
567 JobHandlerMap::iterator it = job_handler_map_.find(printer_id);
568 if (it != job_handler_map_.end()) {
569 it->second->Shutdown();
570 job_handler_map_.erase(it);
573 // TODO(gene): We probably should not try indefinitely here. Just once or
574 // twice should be enough.
575 // Bug: http://code.google.com/p/chromium/issues/detail?id=101850
576 GURL url = GetUrlForPrinterDelete(
577 settings_.server_url(), printer_id, "printer_deleted");
578 StartGetRequest(url,
579 kCloudPrintAPIMaxRetryCount,
580 &CloudPrintConnector::HandlePrinterDeleteResponse);
583 void CloudPrintConnector::OnReceivePrinterCaps(
584 bool succeeded,
585 const std::string& printer_name,
586 const printing::PrinterCapsAndDefaults& caps_and_defaults) {
587 if (!IsRunning())
588 return; // Orphant call.
589 DCHECK(pending_tasks_.size() > 0 &&
590 pending_tasks_.front().type == PENDING_PRINTER_REGISTER);
592 if (!succeeded) {
593 LOG(ERROR) << "CP_CONNECTOR: Failed to get printer info"
594 << ", printer name: " << printer_name;
595 // This printer failed to register, notify the server of this failure.
596 base::string16 printer_name_utf16 = base::UTF8ToUTF16(printer_name);
597 std::string status_message = l10n_util::GetStringFUTF8(
598 IDS_CLOUD_PRINT_REGISTER_PRINTER_FAILED,
599 printer_name_utf16,
600 l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT));
601 ReportUserMessage(kGetPrinterCapsFailedMessageId, status_message);
603 ContinuePendingTaskProcessing(); // Skip this printer registration.
604 return;
607 const printing::PrinterBasicInfo& info = pending_tasks_.front().printer_info;
608 DCHECK(IsSamePrinter(info.printer_name, printer_name));
610 std::string mime_boundary;
611 CreateMimeBoundaryForUpload(&mime_boundary);
612 std::string post_data;
614 net::AddMultipartValueForUpload(kProxyIdValue,
615 settings_.proxy_id(), mime_boundary, std::string(), &post_data);
616 net::AddMultipartValueForUpload(kPrinterNameValue,
617 info.printer_name, mime_boundary, std::string(), &post_data);
618 net::AddMultipartValueForUpload(kPrinterDescValue,
619 info.printer_description, mime_boundary, std::string(), &post_data);
620 net::AddMultipartValueForUpload(kPrinterStatusValue,
621 base::IntToString(info.printer_status),
622 mime_boundary, std::string(), &post_data);
623 // Add local_settings with a current XMPP ping interval.
624 net::AddMultipartValueForUpload(kPrinterLocalSettingsValue,
625 base::StringPrintf(kCreateLocalSettingsXmppPingFormat,
626 settings_.xmpp_ping_timeout_sec()),
627 mime_boundary, std::string(), &post_data);
628 post_data += GetPostDataForPrinterInfo(info, mime_boundary);
629 if (caps_and_defaults.caps_mime_type == kContentTypeJSON) {
630 net::AddMultipartValueForUpload(kUseCDD, "true", mime_boundary,
631 std::string(), &post_data);
633 net::AddMultipartValueForUpload(kPrinterCapsValue,
634 caps_and_defaults.printer_capabilities, mime_boundary,
635 caps_and_defaults.caps_mime_type, &post_data);
636 net::AddMultipartValueForUpload(kPrinterDefaultsValue,
637 caps_and_defaults.printer_defaults, mime_boundary,
638 caps_and_defaults.defaults_mime_type, &post_data);
639 // Send a hash of the printer capabilities to the server. We will use this
640 // later to check if the capabilities have changed
641 net::AddMultipartValueForUpload(kPrinterCapsHashValue,
642 base::MD5String(caps_and_defaults.printer_capabilities),
643 mime_boundary, std::string(), &post_data);
644 net::AddMultipartFinalDelimiterForUpload(mime_boundary, &post_data);
645 std::string mime_type("multipart/form-data; boundary=");
646 mime_type += mime_boundary;
648 GURL post_url = GetUrlForPrinterRegistration(settings_.server_url());
649 StartPostRequest(CloudPrintURLFetcher::REQUEST_REGISTER, post_url,
650 kCloudPrintAPIMaxRetryCount, mime_type, post_data,
651 &CloudPrintConnector::HandleRegisterPrinterResponse);
654 bool CloudPrintConnector::IsSamePrinter(const std::string& name1,
655 const std::string& name2) const {
656 return base::EqualsCaseInsensitiveASCII(name1, name2);
659 } // namespace cloud_print