1 // Copyright 2013 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. 4 5 #include "cloud_print/gcp20/prototype/cloud_print_response_parser.h" 6 7 #include "base/json/json_reader.h" 8 #include "base/json/json_writer.h" 9 #include "base/logging.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/values.h" 12 13 namespace cloud_print_response_parser { 14 15 Job::Job() { 16 } 17 18 Job::~Job() { 19 } 20 21 // Parses json base::Value to base::DictionaryValue. 22 // If |success| value in JSON dictionary is |false| then |message| will 23 // contain |message| from the JSON dictionary. 24 // Returns |true| if no parsing error occurred. 25 bool GetJsonDictinaryAndCheckSuccess(base::Value* json, 26 std::string* error_description, 27 bool* json_success, 28 std::string* message, 29 base::DictionaryValue** dictionary) { 30 base::DictionaryValue* response_dictionary = NULL; 31 if (!json || !json->GetAsDictionary(&response_dictionary)) { 32 *error_description = "No JSON dictionary response received."; 33 return false; 34 } 35 36 bool response_json_success = false; 37 if (!response_dictionary->GetBoolean("success", &response_json_success)) { 38 *error_description = "Cannot parse success state."; 39 return false; 40 } 41 42 if (!response_json_success) { 43 std::string response_message; 44 if (!response_dictionary->GetString("message", &response_message)) { 45 *error_description = "Cannot parse message from response."; 46 return false; 47 } 48 *message = response_message; 49 } 50 51 *json_success = response_json_success; 52 *dictionary = response_dictionary; 53 return true; 54 } 55 56 bool ParseRegisterStartResponse(const std::string& response, 57 std::string* error_description, 58 std::string* polling_url, 59 std::string* registration_token, 60 std::string* complete_invite_url, 61 std::string* device_id) { 62 scoped_ptr<base::Value> json(base::JSONReader::Read(response)); 63 base::DictionaryValue* response_dictionary = NULL; 64 bool json_success; 65 std::string message; 66 if (!GetJsonDictinaryAndCheckSuccess(json.get(), error_description, 67 &json_success, &message, 68 &response_dictionary)) { 69 return false; 70 } 71 if (!json_success) { 72 *error_description = message; 73 return false; 74 } 75 76 std::string response_registration_token; 77 if (!response_dictionary->GetString("registration_token", 78 &response_registration_token)) { 79 *error_description = "No registration_token specified."; 80 return false; 81 } 82 83 std::string response_complete_invite_url; 84 if (!response_dictionary->GetString("complete_invite_url", 85 &response_complete_invite_url)) { 86 *error_description = "No complete_invite_url specified."; 87 return false; 88 } 89 90 std::string response_polling_url; 91 if (!response_dictionary->GetString("polling_url", &response_polling_url)) { 92 *error_description = "No polling_url specified."; 93 return false; 94 } 95 96 base::ListValue* list = NULL; 97 if (!response_dictionary->GetList("printers", &list)) { 98 *error_description = "No printers list specified."; 99 return false; 100 } 101 102 base::DictionaryValue* printer = NULL; 103 if (!list->GetDictionary(0, &printer)) { 104 *error_description = "Printers list is empty or printer is not dictionary."; 105 return false; 106 } 107 108 std::string id; 109 if (!printer->GetString("id", &id)) { 110 *error_description = "No id specified."; 111 return false; 112 } 113 114 if (id.empty()) { 115 *error_description = "id is empty."; 116 return false; 117 } 118 119 *polling_url = response_polling_url; 120 *registration_token = response_registration_token; 121 *complete_invite_url = response_complete_invite_url; 122 *device_id = id; 123 return true; 124 } 125 126 bool ParseRegisterCompleteResponse(const std::string& response, 127 std::string* error_description, 128 std::string* authorization_code, 129 std::string* xmpp_jid) { 130 scoped_ptr<base::Value> json(base::JSONReader::Read(response)); 131 base::DictionaryValue* response_dictionary = NULL; 132 bool json_success; 133 std::string message; 134 if (!GetJsonDictinaryAndCheckSuccess(json.get(), error_description, 135 &json_success, &message, 136 &response_dictionary)) { 137 return false; 138 } 139 if (!json_success) { 140 *error_description = message; 141 return false; 142 } 143 144 std::string response_authorization_code; 145 if (!response_dictionary->GetString("authorization_code", 146 &response_authorization_code)) { 147 *error_description = "Cannot parse authorization_code."; 148 return false; 149 } 150 151 std::string response_xmpp_jid; 152 if (!response_dictionary->GetString("xmpp_jid", &response_xmpp_jid)) { 153 *error_description = "Cannot parse xmpp jid."; 154 return false; 155 } 156 157 *authorization_code = response_authorization_code; 158 *xmpp_jid = response_xmpp_jid; 159 return true; 160 } 161 162 bool ParseFetchResponse(const std::string& response, 163 std::string* error_description, 164 std::vector<Job>* list) { 165 scoped_ptr<base::Value> json(base::JSONReader::Read(response)); 166 base::DictionaryValue* response_dictionary = NULL; 167 bool json_success; 168 std::string message; 169 if (!GetJsonDictinaryAndCheckSuccess(json.get(), error_description, 170 &json_success, &message, 171 &response_dictionary)) { 172 return false; 173 } 174 175 if (!json_success) { // Let's suppose we have no jobs to proceed. 176 list->clear(); 177 return true; 178 } 179 180 base::ListValue* jobs = NULL; 181 if (!response_dictionary->GetList("jobs", &jobs)) { 182 *error_description = "Cannot parse jobs list."; 183 return false; 184 } 185 186 std::vector<Job> job_list(jobs->GetSize()); 187 std::string create_time_str; 188 for (size_t idx = 0; idx < job_list.size(); ++idx) { 189 base::DictionaryValue* job = NULL; 190 jobs->GetDictionary(idx, &job); 191 if (!job->GetString("id", &job_list[idx].job_id) || 192 !job->GetString("createTime", &create_time_str) || 193 !job->GetString("fileUrl", &job_list[idx].file_url) || 194 !job->GetString("ticketUrl", &job_list[idx].ticket_url) || 195 !job->GetString("title", &job_list[idx].title)) { 196 *error_description = "Cannot parse job info."; 197 return false; 198 } 199 int64 create_time_ms = 0; 200 if (!base::StringToInt64(create_time_str, &create_time_ms)) { 201 *error_description = "Cannot convert time."; 202 return false; 203 } 204 job_list[idx].create_time = 205 base::Time::UnixEpoch() + 206 base::TimeDelta::FromMilliseconds(create_time_ms); 207 } 208 209 *list = job_list; 210 return true; 211 } 212 213 bool ParseLocalSettingsResponse(const std::string& response, 214 std::string* error_description, 215 LocalSettings::State* state, 216 LocalSettings* settings) { 217 scoped_ptr<base::Value> json(base::JSONReader::Read(response)); 218 base::DictionaryValue* response_dictionary = NULL; 219 bool json_success; 220 std::string message; 221 if (!GetJsonDictinaryAndCheckSuccess(json.get(), error_description, 222 &json_success, &message, 223 &response_dictionary)) { 224 return false; 225 } 226 227 if (!json_success) { // Let's suppose our printer was deleted. 228 *state = LocalSettings::PRINTER_DELETED; 229 return true; 230 } 231 232 base::ListValue* list = NULL; 233 if (!response_dictionary->GetList("printers", &list)) { 234 *error_description = "No printers list specified."; 235 return false; 236 } 237 238 base::DictionaryValue* printer = NULL; 239 if (!list->GetDictionary(0, &printer)) { 240 *error_description = "Printers list is empty or printer is not dictionary."; 241 return false; 242 } 243 244 base::DictionaryValue* local_settings_dict = NULL; 245 if (!printer->GetDictionary("local_settings", &local_settings_dict)) { 246 *error_description = "No local_settings found."; 247 return false; 248 } 249 250 base::DictionaryValue* current = NULL; 251 if (!local_settings_dict->GetDictionary("current", ¤t)) { 252 *error_description = "No *current* local settings found."; 253 return false; 254 } 255 256 LocalSettings::State settings_state; 257 base::DictionaryValue* pending = NULL; 258 base::DictionaryValue* settings_to_parse = NULL; 259 if (local_settings_dict->GetDictionary("pending", &pending)) { 260 settings_to_parse = pending; 261 settings_state = LocalSettings::PENDING; 262 } else { 263 settings_to_parse = current; 264 settings_state = LocalSettings::CURRENT; 265 } 266 267 LocalSettings local_settings; 268 if (!settings_to_parse->GetBoolean("local_discovery", 269 &local_settings.local_discovery) || 270 !settings_to_parse->GetBoolean("access_token_enabled", 271 &local_settings.access_token_enabled) || 272 !settings_to_parse->GetBoolean("printer/local_printing_enabled", 273 &local_settings.local_printing_enabled) || 274 !settings_to_parse->GetInteger("xmpp_timeout_value", 275 &local_settings.xmpp_timeout_value)) { 276 *error_description = "Cannot parse local_settings info."; 277 return false; 278 } 279 280 *state = settings_state; 281 *settings = local_settings; 282 return true; 283 } 284 285 } // namespace cloud_print_response_parser 286 287