buffet: Introduce a helper method to do cloud API request. For now this helper is somewhat naive and it requires a lot of love to reach production quality. Eventually it will go away from device_registration_info. BUG=chromium:420580 TEST=cros_workon_make buffet --test && manual testing. Change-Id: Iada36af6ea6b0be4c5af6c318818e3ad0682625e Reviewed-on: https://chromium-review.googlesource.com/221075 Reviewed-by: Christopher Wiley <wiley@chromium.org> Tested-by: Anton Muhin <antonm@chromium.org> Commit-Queue: Anton Muhin <antonm@chromium.org>
diff --git a/buffet/device_registration_info.cc b/buffet/device_registration_info.cc index 1e4d511..2c04dcf 100644 --- a/buffet/device_registration_info.cc +++ b/buffet/device_registration_info.cc
@@ -9,7 +9,9 @@ #include <vector> #include <base/json/json_writer.h> +#include <base/message_loop/message_loop.h> #include <base/values.h> +#include <chromeos/bind_lambda.h> #include <chromeos/data_encoding.h> #include <chromeos/http/http_utils.h> #include <chromeos/mime_utils.h> @@ -338,6 +340,7 @@ if (!CheckRegistration(error)) return std::unique_ptr<base::Value>(); + // TODO(antonm): Switch to DoCloudRequest later. auto response = chromeos::http::Get( GetDeviceURL(), {GetAuthorizationHeader()}, transport_, error); int status_code = 0; @@ -483,6 +486,72 @@ return true; } +void DeviceRegistrationInfo::DoCloudRequest( + const char* method, + const std::string& url, + const base::DictionaryValue* body, + CloudRequestCallback callback, + CloudRequestErroback errorback) { + // TODO(antonm): Add retries for 5xx. + // TODO(antonm): Add reauthorisation on access token expiration (do not + // forget about 5xx when fetching new access token). + // TODO(antonm): Add support for device removal. + + chromeos::ErrorPtr error; + + auto report_error = [errorback, &error] () { + auto cb = [errorback] (chromeos::Error* error_ptr) { + errorback.Run(*error_ptr); + }; + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(cb, base::Owned(error.release()))); + }; + + std::string data; + if (body) + base::JSONWriter::Write(body, &data); + + const std::string mime_type{chromeos::mime::AppendParameter( + chromeos::mime::application::kJson, + chromeos::mime::parameters::kCharset, + "utf-8")}; + + const std::unique_ptr<const chromeos::http::Response> response{ + chromeos::http::SendRequest( + method, + url, + data.c_str(), data.size(), + mime_type.c_str(), + {GetAuthorizationHeader()}, + transport_, + &error)}; + if (!response) { + report_error(); + return; + } + + int status_code{0}; + std::unique_ptr<base::DictionaryValue> json_resp{ + chromeos::http::ParseJsonResponse(response.get(), &status_code, &error)}; + if (!json_resp) { + report_error(); + return; + } + + if (status_code >= chromeos::http::status_code::BadRequest) { + LOG(WARNING) << "Cloud request failed. Response code = " << status_code; + ParseGCDError(json_resp.get(), &error); + report_error(); + return; + } + + auto cb = [callback] (base::DictionaryValue* result) { + callback.Run(*result); + }; + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(cb, base::Owned(json_resp.release()))); +} + void DeviceRegistrationInfo::StartDevice(chromeos::ErrorPtr* error) { if (!CheckRegistration(error)) return; @@ -492,18 +561,13 @@ if (!device_resource) return; - // TODO(antonm): Use PUT, not PATCH for updates. - std::unique_ptr<chromeos::http::Response> response = - chromeos::http::PatchJson(GetDeviceURL(), device_resource.release(), - {GetAuthorizationHeader()}, transport_, error); - if (!response) - return; + DoCloudRequest( + chromeos::http::request_type::kPut, + GetDeviceURL(), + device_resource.release(), + base::Bind([](const base::DictionaryValue& data) {}), + base::Bind([](const chromeos::Error& error) {})); - int status_code = 0; - std::unique_ptr<base::DictionaryValue> json = - chromeos::http::ParseJsonResponse(response.get(), &status_code, error); - if (!json || status_code >= chromeos::http::status_code::BadRequest) - return; // TODO(antonm): Implement the rest of startup sequence: // * Abort commands cloud thinks are running
diff --git a/buffet/device_registration_info.h b/buffet/device_registration_info.h index 6a82ffa..8292ea6 100644 --- a/buffet/device_registration_info.h +++ b/buffet/device_registration_info.h
@@ -10,6 +10,7 @@ #include <string> #include <utility> +#include <base/callback.h> #include <base/macros.h> #include <base/time/time.h> #include <chromeos/data_encoding.h> @@ -120,6 +121,23 @@ // Makes sure the access token is available and up-to-date. bool ValidateAndRefreshAccessToken(chromeos::ErrorPtr* error); + using CloudRequestCallback = + base::Callback<void(const base::DictionaryValue&)>; + using CloudRequestErroback = + base::Callback<void(const chromeos::Error& error)>; + + // Do a HTTPS request to cloud services. + // Handles many cases like reauthorization, 5xx HTTP response codes + // and device removal. It is a recommended way to do cloud API + // requests. + // TODO(antonm): Consider moving into some other class. + void DoCloudRequest( + const char* method, + const std::string& url, + const base::DictionaryValue* body, + CloudRequestCallback callback, + CloudRequestErroback errorback); + // Builds Cloud API devices collection REST resouce which matches // current state of the device including command definitions // for all supported commands and current device state.