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.