Commit dd50bca3 authored by Piotr Pawliczek's avatar Piotr Pawliczek Committed by Commit Bot

External Print Servers: Query a print server from cups_printers_handler

This patch add methods to CupsPrinterHandler that allow to query a list
of printers from a print server with given URL. Returned list of printers
is compared with the cuurent list of saved printers. This patch adds also
enum PrintServerQueryResult with error codes for ServerPrintersFetcher.

BUG=chromium:1014760
TEST=on my workstation

Change-Id: I14f5d2a68c5ec0621b3e1190622a2bca291d4603
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1912918
Commit-Queue: Piotr Pawliczek <pawliczek@chromium.org>
Auto-Submit: Piotr Pawliczek <pawliczek@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Reviewed-by: default avatarLuum Habtemariam <luum@chromium.org>
Cr-Commit-Position: refs/heads/master@{#715587}
parent faa17358
......@@ -79,10 +79,17 @@ class ServerPrintersFetcher::PrivateImplementation
void OnComplete(bool success) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!success) {
const int net_error = simple_url_loader_->NetError();
PRINTER_LOG(ERROR) << "Error when querying the print server "
<< server_name_
<< ": NetError=" << simple_url_loader_->NetError();
// Some error occurred. Call the callback with an empty vector.
<< server_name_ << ": NetError=" << net_error;
// Set last_error_, call the callback with an empty vector and exit.
if (net_error >= -399 && net_error <= -303) {
last_error_ = PrintServerQueryResult::kHttpError;
} else if (net_error >= -302 && net_error <= -300) {
last_error_ = PrintServerQueryResult::kIncorrectUrl;
} else {
last_error_ = PrintServerQueryResult::kConnectionError;
}
PostResponse({});
return;
}
......@@ -101,7 +108,8 @@ class ServerPrintersFetcher::PrivateImplementation
LOG(WARNING) << message;
PRINTER_LOG(ERROR) << "Error when querying the print server "
<< server_name_ << ": unparsable IPP response.";
// Call the callback with an empty vector and exit.
// Set last_error_, call the callback with an empty vector and exit.
last_error_ = PrintServerQueryResult::kCannotParseIppResponse;
PostResponse({});
return;
}
......@@ -127,6 +135,8 @@ class ServerPrintersFetcher::PrivateImplementation
std::move(start_retry).Run();
}
PrintServerQueryResult last_error() const { return last_error_; }
private:
// The main task. It is scheduled in the constructor.
void SendQuery() {
......@@ -205,6 +215,8 @@ class ServerPrintersFetcher::PrivateImplementation
// Raw payload of the HTTP response.
std::string response_;
PrintServerQueryResult last_error_ = PrintServerQueryResult::kNoErrors;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
std::unique_ptr<network::SimpleURLLoader> simple_url_loader_;
......@@ -228,4 +240,8 @@ void ServerPrintersFetcher::PimDeleter::operator()(
ServerPrintersFetcher::~ServerPrintersFetcher() = default;
PrintServerQueryResult ServerPrintersFetcher::GetLastError() const {
return pim_->last_error();
}
} // namespace chromeos
......@@ -16,6 +16,14 @@ class GURL;
namespace chromeos {
enum PrintServerQueryResult {
kNoErrors = 0,
kIncorrectUrl,
kConnectionError,
kHttpError,
kCannotParseIppResponse
};
// Instances of this class are used to query list of available printers from
// given print server. The constructor posts to an internal task runner
// a procedure responsible for building and sending the query request. When the
......@@ -37,6 +45,8 @@ class ServerPrintersFetcher {
OnPrintersFetchedCallback cb);
virtual ~ServerPrintersFetcher();
PrintServerQueryResult GetLastError() const;
private:
// Forward declaration of a type of an internal object.
class PrivateImplementation;
......
......@@ -4,6 +4,7 @@
#include "chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h"
#include <set>
#include <utility>
#include "base/bind.h"
......@@ -29,6 +30,7 @@
#include "chrome/browser/chromeos/printing/printer_event_tracker.h"
#include "chrome/browser/chromeos/printing/printer_event_tracker_factory.h"
#include "chrome/browser/chromeos/printing/printer_info.h"
#include "chrome/browser/chromeos/printing/server_printers_fetcher.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/local_discovery/endpoint_resolver.h"
#include "chrome/browser/profiles/profile.h"
......@@ -55,6 +57,7 @@
#include "net/base/ip_endpoint.h"
#include "net/url_request/url_request_context_getter.h"
#include "printing/backend/print_backend.h"
#include "url/gurl.h"
namespace chromeos {
namespace settings {
......@@ -257,6 +260,42 @@ Printer::PpdReference GetPpdReference(const base::Value* info) {
return Printer::PpdReference{"", "", true};
}
bool ConvertToGURL(const std::string& url, GURL* gurl) {
*gurl = GURL(url);
if (!gurl->is_valid()) {
// URL is not valid.
return false;
}
if (!gurl->SchemeIsHTTPOrHTTPS() && !gurl->SchemeIs("ipp") &&
!gurl->SchemeIs("ipps")) {
// URL has unsupported scheme; we support only: http, https, ipp, ipps.
return false;
}
// Replaces ipp/ipps by http/https. IPP standard describes protocol built
// on top of HTTP, so both types of addresses have the same meaning in the
// context of IPP interface. Moreover, the URL must have http/https scheme
// to pass IsStandard() test from GURL library (see "Validation of the URL
// address" below).
bool set_ipp_port = false;
if (gurl->SchemeIs("ipp")) {
set_ipp_port = (gurl->IntPort() == url::PORT_UNSPECIFIED);
*gurl = GURL("http" + url.substr(url.find_first_of(':')));
} else if (gurl->SchemeIs("ipps")) {
*gurl = GURL("https" + url.substr(url.find_first_of(':')));
}
// The default port for ipp is 631. If the schema ipp is replaced by http
// and the port is not explicitly defined in the url, we have to overwrite
// the default http port with the default ipp port. For ipps we do nothing
// because implementers use the same port for ipps and https.
if (set_ipp_port) {
GURL::Replacements replacement;
replacement.SetPortStr("631");
*gurl = gurl->ReplaceComponents(replacement);
}
// Validation of the URL address.
return gurl->IsStandard();
}
} // namespace
CupsPrintersHandler::CupsPrintersHandler(
......@@ -1194,5 +1233,69 @@ void CupsPrintersHandler::OnIpResolved(const std::string& callback_id,
*GetCupsPrinterInfo(printer));
}
void CupsPrintersHandler::HandleQueryPrintServer(const base::ListValue* args) {
std::string callback_id;
std::string server_url;
CHECK_EQ(2U, args->GetSize());
CHECK(args->GetString(0, &callback_id));
CHECK(args->GetString(1, &server_url));
GURL server_gurl;
if (!ConvertToGURL(server_url, &server_gurl)) {
RejectJavascriptCallback(
base::Value(callback_id),
base::Value(PrintServerQueryResult::kIncorrectUrl));
return;
}
server_printers_fetcher_ = std::make_unique<ServerPrintersFetcher>(
server_gurl, "(from user)",
base::BindRepeating(&CupsPrintersHandler::OnQueryPrintServerCompleted,
weak_factory_.GetWeakPtr(), callback_id));
}
void CupsPrintersHandler::OnQueryPrintServerCompleted(
const std::string& callback_id,
const ServerPrintersFetcher* sender,
const GURL& server_url,
std::vector<PrinterDetector::DetectedPrinter>&& returned_printers) {
const PrintServerQueryResult result = sender->GetLastError();
if (result != PrintServerQueryResult::kNoErrors) {
RejectJavascriptCallback(base::Value(callback_id), base::Value(result));
return;
}
// Get all "saved" printers and organize them according to their URL.
const std::vector<Printer> saved_printers =
printers_manager_->GetPrinters(PrinterClass::kSaved);
std::set<GURL> known_printers;
for (const Printer& printer : saved_printers) {
GURL gurl;
if (ConvertToGURL(printer.uri(), &gurl))
known_printers.insert(gurl);
}
// Built final list of printers and a list of current names. If "current name"
// is a null value, then a corresponding printer is not saved in the profile
// (it can be added).
std::vector<Printer> printers;
printers.reserve(returned_printers.size());
for (PrinterDetector::DetectedPrinter& printer : returned_printers) {
printers.push_back(std::move(printer.printer));
GURL printer_gurl;
if (ConvertToGURL(printers.back().uri(), &printer_gurl)) {
if (known_printers.count(printer_gurl))
printers.pop_back();
}
}
// Delete fetcher object.
server_printers_fetcher_.reset();
// Create result value and finish the callback.
base::Value result_dict = BuildCupsPrintersList(printers);
ResolveJavascriptCallback(base::Value(callback_id), result_dict);
}
} // namespace settings
} // namespace chromeos
......@@ -29,11 +29,13 @@ namespace local_discovery {
class EndpointResolver;
} // namespace local_discovery
class GURL;
class Profile;
namespace chromeos {
class PpdProvider;
class ServerPrintersFetcher;
namespace settings {
......@@ -206,6 +208,13 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler,
const Printer& printer,
const net::IPEndPoint& endpoint);
void HandleQueryPrintServer(const base::ListValue* args);
void OnQueryPrintServerCompleted(
const std::string& callback_id,
const ServerPrintersFetcher* sender,
const GURL& server_url,
std::vector<PrinterDetector::DetectedPrinter>&& returned_printers);
Profile* profile_;
// Discovery support. discovery_active_ tracks whether or not the UI
......@@ -231,6 +240,8 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler,
CupsPrintersManager* printers_manager_;
std::unique_ptr<local_discovery::EndpointResolver> endpoint_resolver_;
std::unique_ptr<ServerPrintersFetcher> server_printers_fetcher_;
ScopedObserver<CupsPrintersManager, CupsPrintersManager::Observer>
printers_manager_observer_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment