summaryrefslogtreecommitdiffstats
path: root/cloud_print
diff options
context:
space:
mode:
authormaksymb@chromium.org <maksymb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-19 06:16:41 +0000
committermaksymb@chromium.org <maksymb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-19 06:16:41 +0000
commit0c74882a5d139b47c89dc352079bb316ef6781ff (patch)
tree37bf3657419c0a5ceda081e652964d27098ead04 /cloud_print
parent457ced519a84e749d372c4e4fe91f9cf47d4fa1c (diff)
downloadchromium_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.cc12
-rw-r--r--cloud_print/gcp20/prototype/cloud_print_response_parser.h3
-rw-r--r--cloud_print/gcp20/prototype/gcp20_device.gyp3
-rw-r--r--cloud_print/gcp20/prototype/local_print_job.cc12
-rw-r--r--cloud_print/gcp20/prototype/local_print_job.h40
-rw-r--r--cloud_print/gcp20/prototype/print_job_handler.cc86
-rw-r--r--cloud_print/gcp20/prototype/print_job_handler.h24
-rw-r--r--cloud_print/gcp20/prototype/printer.cc108
-rw-r--r--cloud_print/gcp20/prototype/printer.h16
-rw-r--r--cloud_print/gcp20/prototype/printer_unittest.cc24
-rw-r--r--cloud_print/gcp20/prototype/privet_http_server.cc111
-rw-r--r--cloud_print/gcp20/prototype/privet_http_server.h44
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,