diff options
author | maksymb@chromium.org <maksymb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-19 06:16:41 +0000 |
---|---|---|
committer | maksymb@chromium.org <maksymb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-19 06:16:41 +0000 |
commit | 0c74882a5d139b47c89dc352079bb316ef6781ff (patch) | |
tree | 37bf3657419c0a5ceda081e652964d27098ead04 /cloud_print | |
parent | 457ced519a84e749d372c4e4fe91f9cf47d4fa1c (diff) | |
download | chromium_src-0c74882a5d139b47c89dc352079bb316ef6781ff.zip chromium_src-0c74882a5d139b47c89dc352079bb316ef6781ff.tar.gz chromium_src-0c74882a5d139b47c89dc352079bb316ef6781ff.tar.bz2 |
GCP2.0 Device: Simple printing with new caps.
BUG=
Review URL: https://chromiumcodereview.appspot.com/22985007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@218229 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cloud_print')
-rw-r--r-- | cloud_print/gcp20/prototype/cloud_print_response_parser.cc | 12 | ||||
-rw-r--r-- | cloud_print/gcp20/prototype/cloud_print_response_parser.h | 3 | ||||
-rw-r--r-- | cloud_print/gcp20/prototype/gcp20_device.gyp | 3 | ||||
-rw-r--r-- | cloud_print/gcp20/prototype/local_print_job.cc | 12 | ||||
-rw-r--r-- | cloud_print/gcp20/prototype/local_print_job.h | 40 | ||||
-rw-r--r-- | cloud_print/gcp20/prototype/print_job_handler.cc | 86 | ||||
-rw-r--r-- | cloud_print/gcp20/prototype/print_job_handler.h | 24 | ||||
-rw-r--r-- | cloud_print/gcp20/prototype/printer.cc | 108 | ||||
-rw-r--r-- | cloud_print/gcp20/prototype/printer.h | 16 | ||||
-rw-r--r-- | cloud_print/gcp20/prototype/printer_unittest.cc | 24 | ||||
-rw-r--r-- | cloud_print/gcp20/prototype/privet_http_server.cc | 111 | ||||
-rw-r--r-- | cloud_print/gcp20/prototype/privet_http_server.h | 44 |
12 files changed, 418 insertions, 65 deletions
diff --git a/cloud_print/gcp20/prototype/cloud_print_response_parser.cc b/cloud_print/gcp20/prototype/cloud_print_response_parser.cc index 66bcd85..c43ed39 100644 --- a/cloud_print/gcp20/prototype/cloud_print_response_parser.cc +++ b/cloud_print/gcp20/prototype/cloud_print_response_parser.cc @@ -7,6 +7,7 @@ #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/logging.h" +#include "base/strings/string_number_conversions.h" #include "base/values.h" namespace cloud_print_response_parser { @@ -183,17 +184,26 @@ bool ParseFetchResponse(const std::string& response, } std::vector<Job> job_list(jobs->GetSize()); + std::string create_time_str; for (size_t idx = 0; idx < job_list.size(); ++idx) { base::DictionaryValue* job = NULL; jobs->GetDictionary(idx, &job); if (!job->GetString("id", &job_list[idx].job_id) || - !job->GetString("createTime", &job_list[idx].create_time) || + !job->GetString("createTime", &create_time_str) || !job->GetString("fileUrl", &job_list[idx].file_url) || !job->GetString("ticketUrl", &job_list[idx].ticket_url) || !job->GetString("title", &job_list[idx].title)) { *error_description = "Cannot parse job info."; return false; } + int64 create_time_ms = 0; + if (!base::StringToInt64(create_time_str, &create_time_ms)) { + *error_description = "Cannot convert time."; + return false; + } + job_list[idx].create_time = + base::Time::UnixEpoch() + + base::TimeDelta::FromMilliseconds(create_time_ms); } *list = job_list; diff --git a/cloud_print/gcp20/prototype/cloud_print_response_parser.h b/cloud_print/gcp20/prototype/cloud_print_response_parser.h index c32d932..ff8daec 100644 --- a/cloud_print/gcp20/prototype/cloud_print_response_parser.h +++ b/cloud_print/gcp20/prototype/cloud_print_response_parser.h @@ -9,6 +9,7 @@ #include <vector> #include "base/callback.h" +#include "base/time/time.h" #include "cloud_print/gcp20/prototype/local_settings.h" namespace base { @@ -24,7 +25,7 @@ struct Job { ~Job(); std::string job_id; - std::string create_time; + base::Time create_time; std::string file_url; std::string ticket_url; std::string title; diff --git a/cloud_print/gcp20/prototype/gcp20_device.gyp b/cloud_print/gcp20/prototype/gcp20_device.gyp index 13688a9..0952344 100644 --- a/cloud_print/gcp20/prototype/gcp20_device.gyp +++ b/cloud_print/gcp20/prototype/gcp20_device.gyp @@ -49,6 +49,8 @@ 'dns_sd_server.cc', 'dns_sd_server.h', 'local_settings.h', + 'local_print_job.cc', + 'local_print_job.h', 'print_job_handler.cc', 'print_job_handler.h', 'printer_state.cc', @@ -89,6 +91,7 @@ 'target_name': 'gcp20_device_unittests', 'type': 'executable', 'sources': [ + 'printer_unittest.cc', 'x_privet_token_unittest.cc', ], 'dependencies': [ diff --git a/cloud_print/gcp20/prototype/local_print_job.cc b/cloud_print/gcp20/prototype/local_print_job.cc new file mode 100644 index 0000000..b795c30 --- /dev/null +++ b/cloud_print/gcp20/prototype/local_print_job.cc @@ -0,0 +1,12 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cloud_print/gcp20/prototype/local_print_job.h" + +LocalPrintJob::LocalPrintJob() : offline(false) { +} + +LocalPrintJob::~LocalPrintJob() { +} + diff --git a/cloud_print/gcp20/prototype/local_print_job.h b/cloud_print/gcp20/prototype/local_print_job.h new file mode 100644 index 0000000..b28e024 --- /dev/null +++ b/cloud_print/gcp20/prototype/local_print_job.h @@ -0,0 +1,40 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CLOUD_PRINT_GCP20_PROTOTYPE_LOCAL_PRINT_JOB_H_ +#define CLOUD_PRINT_GCP20_PROTOTYPE_LOCAL_PRINT_JOB_H_ + +#include <string> + +struct LocalPrintJob { + enum CreateResult { + CREATE_SUCCESS, + CREATE_INVALID_TICKET, + CREATE_PRINTER_BUSY, + CREATE_PRINTER_ERROR, + }; + + enum SaveResult { + SAVE_SUCCESS, + SAVE_INVALID_PRINT_JOB, + SAVE_INVALID_DOCUMENT_TYPE, + SAVE_INVALID_DOCUMENT, + SAVE_DOCUMENT_TOO_LARGE, + SAVE_PRINTER_BUSY, + SAVE_PRINTER_ERROR, + }; + + LocalPrintJob(); + ~LocalPrintJob(); + + std::string user_name; + std::string client_name; + std::string job_name; + std::string content; + std::string content_type; + bool offline; +}; + +#endif // CLOUD_PRINT_GCP20_PROTOTYPE_LOCAL_PRINT_JOB_H_ + diff --git a/cloud_print/gcp20/prototype/print_job_handler.cc b/cloud_print/gcp20/prototype/print_job_handler.cc index c7549e4..7c28560 100644 --- a/cloud_print/gcp20/prototype/print_job_handler.cc +++ b/cloud_print/gcp20/prototype/print_job_handler.cc @@ -5,38 +5,100 @@ #include "cloud_print/gcp20/prototype/print_job_handler.h" #include "base/file_util.h" +#include "base/format_macros.h" +#include "base/guid.h" #include "base/logging.h" +#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/time/time.h" namespace { +const int kLocalPrintJobInitExpiration = 5*60; // in seconds + const base::FilePath::CharType kJobsPath[] = FILE_PATH_LITERAL("printjobs"); } // namespace +using base::StringPrintf; + PrintJobHandler::PrintJobHandler() { } PrintJobHandler::~PrintJobHandler() { } -bool PrintJobHandler::SavePrintJob(const std::string& data, +LocalPrintJob::SaveResult PrintJobHandler::SaveLocalPrintJob( + const LocalPrintJob& job, + std::string* job_id, + std::string* error_description, + int* timeout) { + std::string suffix = StringPrintf("%s:%s", + job.user_name.c_str(), + job.client_name.c_str()); + std::string file_extension; + // TODO(maksymb): Gather together this type checking with Printer + // supported types in kCdd. + if (job.content_type == "application/pdf") { + file_extension = "pdf"; + } else if (job.content_type == "image/pwg-raster") { + file_extension = "pwg"; + } else if (job.content_type == "image/jpeg") { + file_extension = "jpg"; + } else { + error_description->clear(); + return LocalPrintJob::SAVE_INVALID_DOCUMENT_TYPE; + } + + std::string id = StringToLowerASCII(base::GenerateGUID()); + if (!SavePrintJob(job.content, std::string(), + base::Time::Now(), + StringPrintf("%s", id.c_str()), + suffix, job.job_name, file_extension)) { + *error_description = "IO error"; + return LocalPrintJob::SAVE_PRINTER_ERROR; + } + + *job_id = id; + return LocalPrintJob::SAVE_SUCCESS; +} + +bool PrintJobHandler::SavePrintJob(const std::string& content, const std::string& ticket, - const std::string& job_name, - const std::string& title) { + const base::Time& create_time, + const std::string& id, + const std::string& job_name_suffix, + // suffix is not extension + // it may be used to mark local printer jobs + const std::string& title, + const std::string& file_extension) { VLOG(1) << "Printing printjob: \"" + title + "\""; base::FilePath directory(kJobsPath); - using file_util::CreateDirectory; - - if (!base::DirectoryExists(directory) && !CreateDirectory(directory)) { + if (!base::DirectoryExists(directory) && + !file_util::CreateDirectory(directory)) { LOG(WARNING) << "Cannot create directory: " << directory.value(); return false; } + base::Time::Exploded create_time_exploded; + create_time.UTCExplode(&create_time_exploded); + std::string job_name = + StringPrintf("%.4d%.2d%.2d-%.2d:%.2d:%.2d-%.3dms.%s", + create_time_exploded.year, + create_time_exploded.month, + create_time_exploded.day_of_month, + create_time_exploded.hour, + create_time_exploded.minute, + create_time_exploded.second, + create_time_exploded.millisecond, + id.c_str()); + if (!job_name_suffix.empty()) + job_name += "." + job_name_suffix; directory = directory.AppendASCII(job_name); - if (!base::DirectoryExists(directory) && !CreateDirectory(directory)) { + if (!base::DirectoryExists(directory) && + !file_util::CreateDirectory(directory)) { LOG(WARNING) << "Cannot create directory: " << directory.value(); return false; } @@ -49,15 +111,15 @@ bool PrintJobHandler::SavePrintJob(const std::string& data, return false; } - written = file_util::WriteFile(directory.AppendASCII("data.pdf"), - data.data(), - static_cast<int>(data.size())); - if (static_cast<size_t>(written) != data.size()) { + written = file_util::WriteFile( + directory.AppendASCII("data." + file_extension), + content.data(), static_cast<int>(content.size())); + if (static_cast<size_t>(written) != content.size()) { LOG(WARNING) << "Cannot save data."; return false; } - LOG(INFO) << "Saved printjob: " << job_name; + LOG(INFO) << "Saved printjob: " << job_name << ": " << title; return true; } diff --git a/cloud_print/gcp20/prototype/print_job_handler.h b/cloud_print/gcp20/prototype/print_job_handler.h index 594e5a2..fc48a1e 100644 --- a/cloud_print/gcp20/prototype/print_job_handler.h +++ b/cloud_print/gcp20/prototype/print_job_handler.h @@ -8,16 +8,34 @@ #include <string> #include "base/basictypes.h" +#include "cloud_print/gcp20/prototype/local_print_job.h" + +namespace base { + +class DictionaryValue; +class Time; + +} // namespace base class PrintJobHandler { public: PrintJobHandler(); ~PrintJobHandler(); - bool SavePrintJob(const std::string& data, + LocalPrintJob::CreateResult CreatePrintJob(std::string* job_id, + int* expires_in); + LocalPrintJob::SaveResult SaveLocalPrintJob(const LocalPrintJob& job, + std::string* job_id, + std::string* error_description, + int* timeout); + + bool SavePrintJob(const std::string& content, const std::string& ticket, - const std::string& job_name, - const std::string& title); + const base::Time& create_time, + const std::string& id, + const std::string& job_name_suffix, + const std::string& title, + const std::string& file_extension); private: DISALLOW_COPY_AND_ASSIGN(PrintJobHandler); diff --git a/cloud_print/gcp20/prototype/printer.cc b/cloud_print/gcp20/prototype/printer.cc index f0583cf..197f70d 100644 --- a/cloud_print/gcp20/prototype/printer.cc +++ b/cloud_print/gcp20/prototype/printer.cc @@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/file_util.h" +#include "base/format_macros.h" #include "base/guid.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" @@ -47,30 +48,57 @@ const double kTimeToNextAccessTokenUpdate = 0.8; // relatively to living time. const char kCdd[] = "{\n" -" 'version': '1.0',\n" -" 'printer': {\n" -" 'vendor_capability': [\n" +" \"version\": \"1.0\",\n" +" \"printer\": {\n" +" \"supported_content_type\": [\n" " {\n" -" 'id': 'psk:MediaType',\n" -" 'display_name': 'Media Type',\n" -" 'type': 'SELECT',\n" -" 'select_cap': {\n" -" 'option': [\n" +" \"content_type\": \"application/pdf\"\n" +" },\n" +" {\n" +" \"content_type\": \"image/pwg-raster\"\n" +" },\n" +" {\n" +" \"content_type\": \"image/jpeg\"\n" +" }\n" +" ],\n" +" \"color\": {\n" +" \"option\": [\n" +" {\n" +" \"is_default\": true,\n" +" \"type\": \"STANDARD_COLOR\",\n" +" \"vendor_id\": \"CMYK\"\n" +" },\n" +" {\n" +" \"is_default\": false,\n" +" \"type\": \"STANDARD_MONOCHROME\",\n" +" \"vendor_id\": \"Gray\"\n" +" }\n" +" ]\n" +" },\n" +" \"vendor_capability\": [\n" +" {\n" +" \"id\": \"psk:MediaType\",\n" +" \"display_name\": \"Media Type\",\n" +" \"type\": \"SELECT\",\n" +" \"select_cap\": {\n" +" \"option\": [\n" " {\n" -" 'value': 'psk:Plain',\n" -" 'display_name': 'Plain Paper',\n" -" 'is_default': true\n" +" \"value\": \"psk:Plain\",\n" +" \"display_name\": \"Plain Paper\",\n" +" \"is_default\": true\n" " },\n" " {\n" -" 'value': 'ns0000:Glossy',\n" -" 'display_name': 'Glossy Photo',\n" -" 'is_default': false\n" +" \"value\": \"ns0000:Glossy\",\n" +" \"display_name\": \"Glossy Photo\",\n" +" \"is_default\": false\n" " }\n" " ]\n" " }\n" " }\n" " ],\n" -" 'reverse_order': { 'default': false }\n" +" \"reverse_order\": {\n" +" \"default\": false\n" +" }\n" " }\n" "}\n"; @@ -150,6 +178,10 @@ void Printer::Stop() { xmpp_listener_.reset(); } +std::string Printer::GetRawCdd() { + return kCdd; +} + void Printer::OnAuthError() { LOG(ERROR) << "Auth error occurred"; state_.access_token_update = base::Time(); @@ -307,8 +339,16 @@ void Printer::CreateInfo(PrivetHttpServer::DeviceInfo* info) { info->x_privet_token = xtoken_.GenerateXToken(); - if (state_.registration_state == PrinterState::UNREGISTERED) + // TODO(maksymb): Create enum for available APIs and replace + // this API text names with constants from enum. API text names should be only + // known in PrivetHttpServer. + if (state_.registration_state == PrinterState::UNREGISTERED) { info->api.push_back("/privet/register"); + } else { + if (IsLocalPrintingAllowed()) + info->api.push_back("/privet/printer/submitdoc"); + info->api.push_back("/privet/capabilities"); + } info->type.push_back("printer"); } @@ -317,10 +357,39 @@ bool Printer::IsRegistered() const { return state_.registration_state == PrinterState::REGISTERED; } +bool Printer::IsLocalPrintingAllowed() const { + return state_.local_settings.local_printing_enabled; +} + bool Printer::CheckXPrivetTokenHeader(const std::string& token) const { return xtoken_.CheckValidXToken(token); } +scoped_ptr<base::DictionaryValue> Printer::GetCapabilities() { + scoped_ptr<base::Value> value(base::JSONReader::Read(kCdd)); + base::DictionaryValue* dictionary_value = NULL; + value->GetAsDictionary(&dictionary_value); + return scoped_ptr<base::DictionaryValue>(dictionary_value->DeepCopy()); +} + +void Printer::CreateJob(const std::string& ticket) { + // TODO(maksymb): Implement advanced printing + NOTIMPLEMENTED(); +} + +LocalPrintJob::SaveResult Printer::SubmitDoc(const LocalPrintJob& job, + std::string* job_id, + std::string* error_description, + int* timeout) { + return print_job_handler_->SaveLocalPrintJob(job, job_id, error_description, + timeout); +} + +void Printer::GetJobStatus(int job_id) { + // TODO(maksymb): Implement advanced printing + NOTIMPLEMENTED(); +} + void Printer::OnRegistrationStartResponseParsed( const std::string& registration_token, const std::string& complete_invite_url, @@ -398,11 +467,8 @@ void Printer::OnPrintJobsAvailable(const std::vector<Job>& jobs) { void Printer::OnPrintJobDownloaded(const Job& job) { VLOG(3) << "Function: " << __FUNCTION__; - print_job_handler_->SavePrintJob( - job.file, - job.ticket, - base::StringPrintf("%s.%s", job.create_time.c_str(), job.job_id.c_str()), - job.title); + print_job_handler_->SavePrintJob(job.file, job.ticket, job.create_time, + job.job_id, "remote", job.title, "pdf"); requester_->SendPrintJobDone(job.job_id); } diff --git a/cloud_print/gcp20/prototype/printer.h b/cloud_print/gcp20/prototype/printer.h index f4bbb07..ccc97b3 100644 --- a/cloud_print/gcp20/prototype/printer.h +++ b/cloud_print/gcp20/prototype/printer.h @@ -20,6 +20,8 @@ extern const base::FilePath::CharType kPrinterStatePath[]; +struct LocalPrintJob; + // This class maintains work of DNS-SD server, HTTP server and others. class Printer : public base::SupportsWeakPtr<Printer>, public PrivetHttpServer::Delegate, @@ -42,6 +44,8 @@ class Printer : public base::SupportsWeakPtr<Printer>, void Stop(); private: + FRIEND_TEST_ALL_PREFIXES(Printer, ValidateCapabilities); + enum ConnectionState { NOT_CONFIGURED, OFFLINE, @@ -49,6 +53,9 @@ class Printer : public base::SupportsWeakPtr<Printer>, CONNECTING }; + // For testing purposes. + static std::string GetRawCdd(); + // PrivetHttpServer::Delegate methods: virtual PrivetHttpServer::RegistrationErrorStatus RegistrationStart( const std::string& user) OVERRIDE; @@ -64,7 +71,16 @@ class Printer : public base::SupportsWeakPtr<Printer>, virtual void GetRegistrationServerError(std::string* description) OVERRIDE; virtual void CreateInfo(PrivetHttpServer::DeviceInfo* info) OVERRIDE; virtual bool IsRegistered() const OVERRIDE; + virtual bool IsLocalPrintingAllowed() const OVERRIDE; virtual bool CheckXPrivetTokenHeader(const std::string& token) const OVERRIDE; + virtual scoped_ptr<base::DictionaryValue> GetCapabilities() OVERRIDE; + virtual void CreateJob(const std::string& ticket) OVERRIDE; + virtual LocalPrintJob::SaveResult SubmitDoc( + const LocalPrintJob& job, + std::string* job_id, + std::string* error_description, + int* timeout) OVERRIDE; + virtual void GetJobStatus(int job_id) OVERRIDE; // CloudRequester::Delegate methods: virtual void OnRegistrationStartResponseParsed( diff --git a/cloud_print/gcp20/prototype/printer_unittest.cc b/cloud_print/gcp20/prototype/printer_unittest.cc new file mode 100644 index 0000000..afce69b --- /dev/null +++ b/cloud_print/gcp20/prototype/printer_unittest.cc @@ -0,0 +1,24 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cloud_print/gcp20/prototype/printer.h" + +#include "base/basictypes.h" +#include "base/json/json_reader.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(Printer, ValidateCapabilities) { + int error_code; + std::string error_msg; + scoped_ptr<base::Value> value( + base::JSONReader::ReadAndReturnError(Printer::GetRawCdd(), 0, + &error_code, &error_msg)); + ASSERT_TRUE(!!value) << error_msg; + + base::DictionaryValue* dictionary_value = NULL; + EXPECT_TRUE(value->GetAsDictionary(&dictionary_value)) << "Not a dictionary"; +} + diff --git a/cloud_print/gcp20/prototype/privet_http_server.cc b/cloud_print/gcp20/prototype/privet_http_server.cc index 45e633d..cb34b9a 100644 --- a/cloud_print/gcp20/prototype/privet_http_server.cc +++ b/cloud_print/gcp20/prototype/privet_http_server.cc @@ -6,6 +6,7 @@ #include "base/command_line.h" #include "base/json/json_writer.h" +#include "base/strings/stringprintf.h" #include "net/base/ip_endpoint.h" #include "net/base/net_errors.h" #include "net/base/url_util.h" @@ -17,6 +18,14 @@ namespace { const int kDeviceBusyTimeout = 30; // in seconds const int kPendingUserActionTimeout = 5; // in seconds +const char kPrivetInfo[] = "/privet/info"; +const char kPrivetRegister[] = "/privet/register"; +const char kPrivetAccessToken[] = "/privet/accesstoken"; +const char kPrivetCapabilities[] = "/privet/capabilities"; +const char kPrivetPrinterCreateJob[] = "/privet/printer/createjob"; +const char kPrivetPrinterSubmitDoc[] = "/privet/printer/submitdoc"; +const char kPrivetPrinterJobState[] = "/privet/printer/jobstate"; + // {"error":|error_type|} scoped_ptr<base::DictionaryValue> CreateError(const std::string& error_type) { scoped_ptr<base::DictionaryValue> error(new base::DictionaryValue); @@ -34,7 +43,7 @@ scoped_ptr<base::DictionaryValue> CreateErrorWithDescription( return error.Pass(); } -// {"error":|error_type|, "timeout":|timout|} +// {"error":|error_type|, "timeout":|timeout|} scoped_ptr<base::DictionaryValue> CreateErrorWithTimeout( const std::string& error_type, int timeout) { @@ -45,17 +54,14 @@ scoped_ptr<base::DictionaryValue> CreateErrorWithTimeout( // Returns |true| if |request| should be GET method. bool IsGetMethod(const std::string& request) { - return request == "/privet/info"/* || - request == "/privet/accesstoken" || - request == "/privet/capabilities" || - request == "/privet/printer/jobstate"*/; + return request == kPrivetInfo || + request == kPrivetCapabilities; } // Returns |true| if |request| should be POST method. bool IsPostMethod(const std::string& request) { - return request == "/privet/register"/* || - request == "/privet/printer/createjob" || - request == "/privet/printer/submitdoc"*/; + return request == kPrivetRegister || + request == kPrivetPrinterSubmitDoc; } } // namespace @@ -118,7 +124,7 @@ void PrivetHttpServer::OnHttpRequest(int connection_id, return; } - if (url.path() != "/privet/info" && + if (url.path() != kPrivetInfo && !delegate_->CheckXPrivetTokenHeader(iter->second)) { server_->Send(connection_id, net::HTTP_OK, "{\"error\":\"invalid_x_privet_token\"}", @@ -128,8 +134,7 @@ void PrivetHttpServer::OnHttpRequest(int connection_id, } std::string response; - net::HttpStatusCode status_code = - ProcessHttpRequest(url, info.data, &response); + net::HttpStatusCode status_code = ProcessHttpRequest(url, info, &response); server_->Send(connection_id, status_code, response, "application/json"); } @@ -175,15 +180,19 @@ bool PrivetHttpServer::ValidateRequestMethod(int connection_id, net::HttpStatusCode PrivetHttpServer::ProcessHttpRequest( const GURL& url, - const std::string& data, + const net::HttpServerRequestInfo& info, std::string* response) { net::HttpStatusCode status_code = net::HTTP_OK; scoped_ptr<base::DictionaryValue> json_response; - if (url.path() == "/privet/info") { + if (url.path() == kPrivetInfo) { json_response = ProcessInfo(&status_code); - } else if (url.path() == "/privet/register") { + } else if (url.path() == kPrivetRegister) { json_response = ProcessRegister(url, &status_code); + } else if (url.path() == kPrivetCapabilities) { + json_response = ProcessCapabilities(&status_code); + } else if (url.path() == kPrivetPrinterSubmitDoc) { + json_response = ProcessSubmitDoc(url, info, &status_code); } else { NOTREACHED(); } @@ -236,9 +245,80 @@ scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessInfo( return response.Pass(); } +scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessCapabilities( + net::HttpStatusCode* status_code) const { + if (!delegate_->IsRegistered()) { + *status_code = net::HTTP_NOT_FOUND; + return scoped_ptr<base::DictionaryValue>(); + } + + return delegate_->GetCapabilities(); +} + +scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessSubmitDoc( + const GURL& url, + const net::HttpServerRequestInfo& info, + net::HttpStatusCode* status_code) const { + if (!delegate_->IsRegistered() || !delegate_->IsLocalPrintingAllowed()) { + *status_code = net::HTTP_NOT_FOUND; + return scoped_ptr<base::DictionaryValue>(); + } + + // Parse query + LocalPrintJob job; + std::string offline; + net::GetValueForKeyInQuery(url, "client_name", &job.client_name); + bool job_name_present = + net::GetValueForKeyInQuery(url, "job_name", &job.job_name); + net::GetValueForKeyInQuery(url, "user_name", &job.user_name); + net::GetValueForKeyInQuery(url, "offline", &offline); + job.offline = (offline == "1"); + job.content_type = info.GetHeaderValue("content-type"); + job.content = info.data; + + // Call delegate + std::string job_id; + std::string error_description; + int timeout; + LocalPrintJob::SaveResult status = + delegate_->SubmitDoc(job, &job_id, &error_description, &timeout); + + // Create response + *status_code = net::HTTP_OK; + scoped_ptr<base::DictionaryValue> response(new DictionaryValue); + switch (status) { + case LocalPrintJob::SAVE_SUCCESS: + response->SetString("job_id", job_id); + response->SetInteger("expires_in", -1); + response->SetString("job_type", job.content_type); + response->SetString( + "job_size", + base::StringPrintf("%u", static_cast<uint32>(job.content.size()))); + if (job_name_present) + response->SetString("job_name", job.job_name); + return response.Pass(); + + case LocalPrintJob::SAVE_INVALID_PRINT_JOB: + return CreateError("invalid_print_job"); + case LocalPrintJob::SAVE_INVALID_DOCUMENT_TYPE: + return CreateError("invalid_document_type"); + case LocalPrintJob::SAVE_INVALID_DOCUMENT: + return CreateError("invalid_document"); + case LocalPrintJob::SAVE_DOCUMENT_TOO_LARGE: + return CreateError("document_too_large"); + case LocalPrintJob::SAVE_PRINTER_BUSY: + return CreateErrorWithTimeout("printer_busy", -2); + case LocalPrintJob::SAVE_PRINTER_ERROR: + return CreateErrorWithDescription("printer_error", error_description); + default: + NOTREACHED(); + return scoped_ptr<base::DictionaryValue>(); + } +} + scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessRegister( const GURL& url, - net::HttpStatusCode* status_code) { + net::HttpStatusCode* status_code) const { if (delegate_->IsRegistered()) { *status_code = net::HTTP_NOT_FOUND; return scoped_ptr<base::DictionaryValue>(); @@ -332,4 +412,3 @@ void PrivetHttpServer::ProcessRegistrationStatus( }; } - diff --git a/cloud_print/gcp20/prototype/privet_http_server.h b/cloud_print/gcp20/prototype/privet_http_server.h index b551976..db113de 100644 --- a/cloud_print/gcp20/prototype/privet_http_server.h +++ b/cloud_print/gcp20/prototype/privet_http_server.h @@ -10,7 +10,7 @@ #include "base/basictypes.h" #include "base/values.h" -#include "net/http/http_status_code.h" +#include "cloud_print/gcp20/prototype/local_print_job.h" #include "net/server/http_server.h" #include "net/server/http_server_request_info.h" @@ -58,8 +58,6 @@ class PrivetHttpServer: public net::HttpServer::Delegate { class Delegate { public: - Delegate() {} - virtual ~Delegate() {} // Invoked when registration is starting. @@ -87,11 +85,30 @@ class PrivetHttpServer: public net::HttpServer::Delegate { // Invoked when /privet/info is called. virtual void CreateInfo(DeviceInfo* info) = 0; - // Invoked for checking should /privet/register be exposed. + // Invoked for checking wether /privet/register should be exposed. virtual bool IsRegistered() const = 0; + // Invoked for checking wether /privet/printer/* should be exposed. + virtual bool IsLocalPrintingAllowed() const = 0; + // Invoked when XPrivetToken has to be checked. virtual bool CheckXPrivetTokenHeader(const std::string& token) const = 0; + + // Invoked for getting capabilities. + virtual scoped_ptr<base::DictionaryValue> GetCapabilities() = 0; + + // Invoked for creating a job. + virtual void CreateJob(const std::string& ticket) = 0; + + // Invoked for simple local printing. + virtual LocalPrintJob::SaveResult SubmitDoc( + const LocalPrintJob& job, + std::string* job_id, + std::string* error_description, + int* timeout) = 0; + + // Invoked for getting job status. + virtual void GetJobStatus(int job_id) = 0; }; // Constructor doesn't start server. @@ -130,20 +147,25 @@ class PrivetHttpServer: public net::HttpServer::Delegate { // Processes http request after all preparations (XPrivetHeader check, // data handling etc.) - net::HttpStatusCode ProcessHttpRequest(const GURL& url, - const std::string& data, - std::string* response); + net::HttpStatusCode ProcessHttpRequest( + const GURL& url, + const net::HttpServerRequestInfo& info, + std::string* response); // Pivet API methods. Return reference to NULL if output should be empty. scoped_ptr<base::DictionaryValue> ProcessInfo( net::HttpStatusCode* status_code) const; - scoped_ptr<base::DictionaryValue> ProcessReset( - net::HttpStatusCode* status_code); + scoped_ptr<base::DictionaryValue> ProcessCapabilities( + net::HttpStatusCode* status_code) const; + scoped_ptr<base::DictionaryValue> ProcessSubmitDoc( + const GURL& url, + const net::HttpServerRequestInfo& info, + net::HttpStatusCode* status_code) const; scoped_ptr<base::DictionaryValue> ProcessRegister( const GURL& url, - net::HttpStatusCode* status_code); + net::HttpStatusCode* status_code) const; - // Proccesses current status and depending on it replaces (or not) + // Processes current status and depending on it replaces (or not) // |current_response| with error or empty response. void ProcessRegistrationStatus( RegistrationErrorStatus status, |