libweave: http::Transport access moved into HttpTransportClient HttpTransportClient is implementation of HttpClient interface. HttpTransportClient will be moved out of libweave into buffet. BUG=brillo:1250 TEST=`FEATURES=test emerge-gizmo libweave buffet` Change-Id: I9c3db5309318212020bb0348cc9fee4c8856011d
diff --git a/libweave/include/weave/http_client.h b/libweave/include/weave/http_client.h new file mode 100644 index 0000000..8263d21 --- /dev/null +++ b/libweave/include/weave/http_client.h
@@ -0,0 +1,56 @@ +// Copyright 2015 The Chromium OS 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 LIBWEAVE_INCLUDE_WEAVE_HTTP_CLIENT_H_ +#define LIBWEAVE_INCLUDE_WEAVE_HTTP_CLIENT_H_ + +#include <string> +#include <utility> +#include <vector> + +#include <base/callback.h> +#include <chromeos/errors/error.h> + +namespace weave { + +class HttpClient { + public: + class Response { + public: + virtual int GetStatusCode() const = 0; + virtual std::string GetContentType() const = 0; + virtual const std::string& GetData() const = 0; + + // TODO(vitalybuka): Hide when SendRequestAndBlock is removed. + virtual ~Response() = default; + }; + + using Headers = std::vector<std::pair<std::string, std::string>>; + using SuccessCallback = base::Callback<void(int, const Response&)>; + using ErrorCallback = base::Callback<void(int, const chromeos::Error*)>; + + // TODO(vitalybuka): Remove blocking version. + virtual std::unique_ptr<Response> SendRequestAndBlock( + const std::string& method, + const std::string& url, + const std::string& data, + const std::string& mime_type, + const Headers& headers, + chromeos::ErrorPtr* error) = 0; + + virtual int SendRequest(const std::string& method, + const std::string& url, + const std::string& data, + const std::string& mime_type, + const Headers& headers, + const SuccessCallback& success_callback, + const ErrorCallback& error_callback) = 0; + + protected: + virtual ~HttpClient() = default; +}; + +} // namespace weave + +#endif // LIBWEAVE_INCLUDE_WEAVE_HTTP_CLIENT_H_
diff --git a/libweave/libweave.gyp b/libweave/libweave.gyp index cdc7077..9a1f2b6 100644 --- a/libweave/libweave.gyp +++ b/libweave/libweave.gyp
@@ -34,6 +34,7 @@ 'src/commands/user_role.cc', 'src/device_manager.cc', 'src/device_registration_info.cc', + 'src/http_transport_client.cc', 'src/notification/notification_parser.cc', 'src/notification/pull_channel.cc', 'src/notification/xml_node.cc',
diff --git a/libweave/src/device_registration_info.cc b/libweave/src/device_registration_info.cc index 9c06383..948b485 100644 --- a/libweave/src/device_registration_info.cc +++ b/libweave/src/device_registration_info.cc
@@ -11,23 +11,25 @@ #include <vector> #include <base/bind.h> +#include <base/json/json_reader.h> #include <base/json/json_writer.h> #include <base/strings/string_number_conversions.h> #include <base/values.h> #include <chromeos/bind_lambda.h> #include <chromeos/data_encoding.h> #include <chromeos/errors/error_codes.h> -#include <chromeos/http/http_utils.h> #include <chromeos/key_value_store.h> #include <chromeos/mime_utils.h> #include <chromeos/strings/string_utils.h> #include <chromeos/url_utils.h> +#include <weave/http_client.h> #include <weave/network.h> #include "libweave/src/commands/cloud_command_proxy.h" #include "libweave/src/commands/command_definition.h" #include "libweave/src/commands/command_manager.h" #include "libweave/src/commands/schema_constants.h" +#include "libweave/src/http_transport_client.h" #include "libweave/src/notification/xmpp_channel.h" #include "libweave/src/states/state_manager.h" #include "libweave/src/utils.h" @@ -40,12 +42,23 @@ namespace { +const int kHttpStatusContinue = 100; +const int kHttpStatusBadRequest = 400; +const int kHttpStatusDenied = 401; +const int kHttpStatusForbidden = 403; +const int kHttpStatusInternalServerError = 500; + +const char kGet[] = "GET"; +const char kPatch[] = "PATCH"; +const char kPost[] = "POST"; +const char kPut[] = "PUT"; + std::pair<std::string, std::string> BuildAuthHeader( const std::string& access_token_type, const std::string& access_token) { std::string authorization = chromeos::string_utils::Join(" ", access_token_type, access_token); - return {chromeos::http::request_header::kAuthorization, authorization}; + return {"Authorization", authorization}; } inline void SetUnexpectedError(chromeos::ErrorPtr* error) { @@ -105,6 +118,105 @@ cb.Run(); } +class RequestSender final { + public: + RequestSender(const std::string& method, + const std::string& url, + HttpClient* transport) + : method_{method}, url_{url}, transport_{transport} {} + + std::unique_ptr<HttpClient::Response> SendAndBlock( + chromeos::ErrorPtr* error) { + return transport_->SendRequestAndBlock(method_, url_, data_, mime_type_, + headers_, error); + } + + int Send(const HttpClient::SuccessCallback& success_callback, + const HttpClient::ErrorCallback& error_callback) { + return transport_->SendRequest(method_, url_, data_, mime_type_, headers_, + success_callback, error_callback); + } + + void AddAuthHeader(const std::string& access_token) { + headers_.emplace_back(BuildAuthHeader("Bearer", access_token)); + } + + void SetData(const std::string& data, const std::string& mime_type) { + data_ = data; + mime_type_ = mime_type; + } + + void SetFormData( + const std::vector<std::pair<std::string, std::string>>& data) { + data_ = chromeos::data_encoding::WebParamsEncode(data); + mime_type_ = chromeos::mime::application::kWwwFormUrlEncoded; + } + + void SetJsonData(const base::Value& json) { + std::string data; + CHECK(base::JSONWriter::Write(json, &data_)); + mime_type_ = chromeos::mime::AppendParameter( + chromeos::mime::application::kJson, + chromeos::mime::parameters::kCharset, "utf-8"); + } + + private: + std::string method_; + std::string url_; + std::string data_; + std::string mime_type_; + std::vector<std::pair<std::string, std::string>> headers_; + HttpClient* transport_{nullptr}; + + DISALLOW_COPY_AND_ASSIGN(RequestSender); +}; + +std::unique_ptr<base::DictionaryValue> ParseJsonResponse( + const HttpClient::Response& response, + chromeos::ErrorPtr* error) { + // Make sure we have a correct content type. Do not try to parse + // binary files, or HTML output. Limit to application/json and text/plain. + auto content_type = + chromeos::mime::RemoveParameters(response.GetContentType()); + if (content_type != chromeos::mime::application::kJson && + content_type != chromeos::mime::text::kPlain) { + chromeos::Error::AddTo(error, FROM_HERE, chromeos::errors::json::kDomain, + "non_json_content_type", + "Unexpected response content type: " + content_type); + return std::unique_ptr<base::DictionaryValue>(); + } + + const std::string& json = response.GetData(); + std::string error_message; + auto value = base::JSONReader::ReadAndReturnError(json, base::JSON_PARSE_RFC, + nullptr, &error_message); + if (!value) { + chromeos::Error::AddToPrintf(error, FROM_HERE, + chromeos::errors::json::kDomain, + chromeos::errors::json::kParseError, + "Error '%s' occurred parsing JSON string '%s'", + error_message.c_str(), json.c_str()); + return std::unique_ptr<base::DictionaryValue>(); + } + base::DictionaryValue* dict_value = nullptr; + if (!value->GetAsDictionary(&dict_value)) { + chromeos::Error::AddToPrintf( + error, FROM_HERE, chromeos::errors::json::kDomain, + chromeos::errors::json::kObjectExpected, + "Response is not a valid JSON object: '%s'", json.c_str()); + return std::unique_ptr<base::DictionaryValue>(); + } else { + // |value| is now owned by |dict_value|, so release the scoped_ptr now. + base::IgnoreResult(value.release()); + } + return std::unique_ptr<base::DictionaryValue>(dict_value); +} + +bool IsSuccessful(const HttpClient::Response& response) { + int code = response.GetStatusCode(); + return code >= kHttpStatusContinue && code < kHttpStatusBadRequest; +} + } // anonymous namespace DeviceRegistrationInfo::DeviceRegistrationInfo( @@ -114,8 +226,9 @@ const std::shared_ptr<chromeos::http::Transport>& transport, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, bool notifications_enabled, - weave::Network* network) - : transport_{transport}, + Network* network) + : http_client_owner_{new buffet::HttpTransportClient{transport}}, + http_client_{http_client_owner_.get()}, task_runner_{task_runner}, command_manager_{command_manager}, state_manager_{state_manager}, @@ -144,11 +257,6 @@ DeviceRegistrationInfo::~DeviceRegistrationInfo() = default; -std::pair<std::string, std::string> -DeviceRegistrationInfo::GetAuthorizationHeader() const { - return BuildAuthHeader("Bearer", access_token_); -} - std::string DeviceRegistrationInfo::GetServiceURL( const std::string& subpath, const chromeos::data_encoding::WebParamList& params) const { @@ -212,11 +320,11 @@ } std::unique_ptr<base::DictionaryValue> -DeviceRegistrationInfo::ParseOAuthResponse(chromeos::http::Response* response, +DeviceRegistrationInfo::ParseOAuthResponse(const HttpClient::Response& response, chromeos::ErrorPtr* error) { - int code = 0; - auto resp = chromeos::http::ParseJsonResponse(response, &code, error); - if (resp && code >= chromeos::http::status_code::BadRequest) { + int code = response.GetStatusCode(); + auto resp = ParseJsonResponse(response, error); + if (resp && code >= kHttpStatusBadRequest) { std::string error_code, error_message; if (!resp->GetString("error", &error_code)) { error_code = "unexpected_response"; @@ -267,15 +375,14 @@ auto shared_error_callback = std::make_shared<CloudRequestErrorCallback>(error_callback); - chromeos::http::FormFieldList form_data{ + RequestSender sender{kPost, GetOAuthURL("token"), http_client_}; + sender.SetFormData({ {"refresh_token", config_->refresh_token()}, {"client_id", config_->client_id()}, {"client_secret", config_->client_secret()}, {"grant_type", "refresh_token"}, - }; - - chromeos::http::RequestID request_id = chromeos::http::PostFormData( - GetOAuthURL("token"), form_data, {}, transport_, + }); + int request_id = sender.Send( base::Bind(&DeviceRegistrationInfo::OnRefreshAccessTokenSuccess, weak_factory_.GetWeakPtr(), shared_success_callback, shared_error_callback), @@ -289,12 +396,12 @@ void DeviceRegistrationInfo::OnRefreshAccessTokenSuccess( const std::shared_ptr<base::Closure>& success_callback, const std::shared_ptr<CloudRequestErrorCallback>& error_callback, - chromeos::http::RequestID id, - std::unique_ptr<chromeos::http::Response> response) { + int id, + const HttpClient::Response& response) { VLOG(1) << "Refresh access token request with ID " << id << " completed"; oauth2_backoff_entry_->InformOfRequest(true); chromeos::ErrorPtr error; - auto json = ParseOAuthResponse(response.get(), &error); + auto json = ParseOAuthResponse(response, &error); if (!json) { error_callback->Run(error.get()); return; @@ -328,7 +435,7 @@ void DeviceRegistrationInfo::OnRefreshAccessTokenError( const std::shared_ptr<base::Closure>& success_callback, const std::shared_ptr<CloudRequestErrorCallback>& error_callback, - chromeos::http::RequestID id, + int id, const chromeos::Error* error) { VLOG(1) << "Refresh access token request with ID " << id << " failed"; oauth2_backoff_entry_->InformOfRequest(false); @@ -430,8 +537,8 @@ void DeviceRegistrationInfo::GetDeviceInfo( const CloudRequestCallback& success_callback, const CloudRequestErrorCallback& error_callback) { - DoCloudRequest(chromeos::http::request_type::kGet, GetDeviceURL(), nullptr, - success_callback, error_callback); + DoCloudRequest(weave::kGet, GetDeviceURL(), nullptr, success_callback, + error_callback); } std::string DeviceRegistrationInfo::RegisterDevice(const std::string& ticket_id, @@ -448,27 +555,30 @@ auto url = GetServiceURL("registrationTickets/" + ticket_id, {{"key", config_->api_key()}}); - std::unique_ptr<chromeos::http::Response> response = - chromeos::http::PatchJsonAndBlock(url, &req_json, {}, transport_, error); - auto json_resp = - chromeos::http::ParseJsonResponse(response.get(), nullptr, error); + + RequestSender sender{kPatch, url, http_client_}; + sender.SetJsonData(req_json); + auto response = sender.SendAndBlock(error); + + if (!response) + return std::string(); + auto json_resp = ParseJsonResponse(*response, error); if (!json_resp) return std::string(); - if (!response->IsSuccessful()) { + if (!IsSuccessful(*response)) { ParseGCDError(json_resp.get(), error); return std::string(); } url = GetServiceURL("registrationTickets/" + ticket_id + "/finalize", {{"key", config_->api_key()}}); - response = chromeos::http::SendRequestWithNoDataAndBlock( - chromeos::http::request_type::kPost, url, {}, transport_, error); + response = RequestSender{kPost, url, http_client_}.SendAndBlock(error); if (!response) return std::string(); - json_resp = chromeos::http::ParseJsonResponse(response.get(), nullptr, error); + json_resp = ParseJsonResponse(*response, error); if (!json_resp) return std::string(); - if (!response->IsSuccessful()) { + if (!IsSuccessful(*response)) { ParseGCDError(json_resp.get(), error); return std::string(); } @@ -490,19 +600,20 @@ UpdateDeviceInfoTimestamp(*device_draft_response); // Now get access_token and refresh_token - response = chromeos::http::PostFormDataAndBlock( - GetOAuthURL("token"), + RequestSender sender2{kPost, GetOAuthURL("token"), http_client_}; + sender2.SetFormData( {{"code", auth_code}, {"client_id", config_->client_id()}, {"client_secret", config_->client_secret()}, {"redirect_uri", "oob"}, {"scope", "https://www.googleapis.com/auth/clouddevices"}, - {"grant_type", "authorization_code"}}, - {}, transport_, error); + {"grant_type", "authorization_code"}}); + response = sender2.SendAndBlock(error); + if (!response) return std::string(); - json_resp = ParseOAuthResponse(response.get(), error); + json_resp = ParseOAuthResponse(*response, error); int expires_in = 0; std::string refresh_token; if (!json_resp || !json_resp->GetString("access_token", &access_token_) || @@ -582,24 +693,25 @@ const std::string mime_type = chromeos::mime::AppendParameter(kJson, kCharset, "utf-8"); - chromeos::http::RequestID request_id = chromeos::http::SendRequest( - data->method, data->url, data->body.c_str(), data->body.size(), mime_type, - {GetAuthorizationHeader()}, transport_, - base::Bind(&DeviceRegistrationInfo::OnCloudRequestSuccess, AsWeakPtr(), - data), - base::Bind(&DeviceRegistrationInfo::OnCloudRequestError, AsWeakPtr(), - data)); + RequestSender sender{data->method, data->url, http_client_}; + sender.SetData(data->body, mime_type); + sender.AddAuthHeader(access_token_); + int request_id = + sender.Send(base::Bind(&DeviceRegistrationInfo::OnCloudRequestSuccess, + AsWeakPtr(), data), + base::Bind(&DeviceRegistrationInfo::OnCloudRequestError, + AsWeakPtr(), data)); VLOG(1) << "Cloud request with ID " << request_id << " successfully sent"; } void DeviceRegistrationInfo::OnCloudRequestSuccess( const std::shared_ptr<const CloudRequestData>& data, - chromeos::http::RequestID request_id, - std::unique_ptr<chromeos::http::Response> response) { - int status_code = response->GetStatusCode(); + int request_id, + const HttpClient::Response& response) { + int status_code = response.GetStatusCode(); VLOG(1) << "Response for cloud request with ID " << request_id << " received with status code " << status_code; - if (status_code == chromeos::http::status_code::Denied) { + if (status_code == kHttpStatusDenied) { cloud_backoff_entry_->InformOfRequest(true); RefreshAccessToken( base::Bind(&DeviceRegistrationInfo::OnAccessTokenRefreshed, AsWeakPtr(), @@ -609,7 +721,7 @@ return; } - if (status_code >= chromeos::http::status_code::InternalServerError) { + if (status_code >= kHttpStatusInternalServerError) { // Request was valid, but server failed, retry. // TODO(antonm): Reconsider status codes, maybe only some require // retry. @@ -619,17 +731,16 @@ } chromeos::ErrorPtr error; - auto json_resp = - chromeos::http::ParseJsonResponse(response.get(), nullptr, &error); + auto json_resp = ParseJsonResponse(response, &error); if (!json_resp) { data->error_callback.Run(error.get()); cloud_backoff_entry_->InformOfRequest(true); return; } - if (!response->IsSuccessful()) { + if (!IsSuccessful(response)) { ParseGCDError(json_resp.get(), &error); - if (status_code == chromeos::http::status_code::Forbidden && + if (status_code == kHttpStatusForbidden && error->HasError(kErrorDomainGCDServer, "rateLimitExceeded")) { // If we exceeded server quota, retry the request later. RetryCloudRequest(data); @@ -647,7 +758,7 @@ void DeviceRegistrationInfo::OnCloudRequestError( const std::shared_ptr<const CloudRequestData>& data, - chromeos::http::RequestID request_id, + int request_id, const chromeos::Error* error) { VLOG(1) << "Cloud request with ID " << request_id << " failed"; RetryCloudRequest(data); @@ -776,8 +887,8 @@ const base::DictionaryValue& command_patch, const base::Closure& on_success, const base::Closure& on_error) { - DoCloudRequest(chromeos::http::request_type::kPatch, - GetServiceURL("commands/" + command_id), &command_patch, + DoCloudRequest(weave::kPatch, GetServiceURL("commands/" + command_id), + &command_patch, base::Bind(&IgnoreCloudResultWithCallback, on_success), base::Bind(&IgnoreCloudErrorWithCallback, on_error)); } @@ -853,7 +964,7 @@ {}, {{"lastUpdateTimeMs", last_device_resource_updated_timestamp_}}); DoCloudRequest( - chromeos::http::request_type::kPut, url, device_resource.get(), + weave::kPut, url, device_resource.get(), base::Bind(&DeviceRegistrationInfo::OnUpdateDeviceResourceSuccess, AsWeakPtr()), base::Bind(&DeviceRegistrationInfo::OnUpdateDeviceResourceError, @@ -934,7 +1045,7 @@ const base::Callback<void(const base::ListValue&)>& on_success, const CloudRequestErrorCallback& on_failure) { DoCloudRequest( - chromeos::http::request_type::kGet, + weave::kGet, GetServiceURL("commands/queue", {{"deviceId", config_->device_id()}}), nullptr, base::Bind(&HandleFetchCommandsResult, on_success), on_failure); } @@ -970,9 +1081,8 @@ std::unique_ptr<base::DictionaryValue> cmd_copy{command_dict->DeepCopy()}; cmd_copy->SetString("state", "aborted"); // TODO(wiley) We could consider handling this error case more gracefully. - DoCloudRequest(chromeos::http::request_type::kPut, - GetServiceURL("commands/" + command_id), cmd_copy.get(), - base::Bind(&IgnoreCloudResult), + DoCloudRequest(weave::kPut, GetServiceURL("commands/" + command_id), + cmd_copy.get(), base::Bind(&IgnoreCloudResult), base::Bind(&IgnoreCloudError)); } else { // Normal command, publish it to local clients. @@ -1015,8 +1125,8 @@ std::unique_ptr<CloudCommandProxy> cloud_proxy{new CloudCommandProxy{ command_instance.get(), this, state_manager_->GetStateChangeQueue(), std::move(backoff_entry), task_runner_}}; - // CloudCommandProxy::CloudCommandProxy() subscribe itself to weave::Command - // notifications. When weave::Command is being destroyed it sends + // CloudCommandProxy::CloudCommandProxy() subscribe itself to Command + // notifications. When Command is being destroyed it sends // ::OnCommandDestroyed() and CloudCommandProxy deletes itself. cloud_proxy.release(); command_manager_->AddCommand(std::move(command_instance)); @@ -1063,7 +1173,7 @@ device_state_update_pending_ = true; DoCloudRequest( - chromeos::http::request_type::kPost, GetDeviceURL("patchState"), &body, + weave::kPost, GetDeviceURL("patchState"), &body, base::Bind(&DeviceRegistrationInfo::OnPublishStateSuccess, AsWeakPtr(), update_id), base::Bind(&DeviceRegistrationInfo::OnPublishStateError, AsWeakPtr()));
diff --git a/libweave/src/device_registration_info.h b/libweave/src/device_registration_info.h index 2cf3e91..dccb6dd 100644 --- a/libweave/src/device_registration_info.h +++ b/libweave/src/device_registration_info.h
@@ -24,6 +24,7 @@ #include <chromeos/http/http_transport.h> #include <weave/cloud.h> #include <weave/config.h> +#include <weave/http_client.h> #include "libweave/src/buffet_config.h" #include "libweave/src/commands/cloud_command_update_interface.h" @@ -42,10 +43,14 @@ class KeyValueStore; } // namespace chromeos +namespace buffet { +class HttpTransportClient; +} // namespace buffet + namespace weave { -class StateManager; class Network; +class StateManager; extern const char kErrorDomainOAuth2[]; extern const char kErrorDomainGCD[]; @@ -98,11 +103,6 @@ // Add callback to listen for changes in config. void AddOnConfigChangedCallback(const Config::OnChangedCallback& callback); - // Returns the authorization HTTP header that can be used to talk - // to GCD server for authenticated device communication. - // Make sure ValidateAndRefreshAccessToken() is called before this call. - std::pair<std::string, std::string> GetAuthorizationHeader() const; - // Returns the GCD service request URL. If |subpath| is specified, it is // appended to the base URL which is normally // https://www.googleapis.com/clouddevices/v1/". @@ -175,18 +175,18 @@ void OnRefreshAccessTokenSuccess( const std::shared_ptr<base::Closure>& success_callback, const std::shared_ptr<CloudRequestErrorCallback>& error_callback, - chromeos::http::RequestID id, - std::unique_ptr<chromeos::http::Response> response); + int id, + const HttpClient::Response& response); void OnRefreshAccessTokenError( const std::shared_ptr<base::Closure>& success_callback, const std::shared_ptr<CloudRequestErrorCallback>& error_callback, - chromeos::http::RequestID id, + int id, const chromeos::Error* error); // Parse the OAuth response, and sets registration status to // kInvalidCredentials if our registration is no longer valid. std::unique_ptr<base::DictionaryValue> ParseOAuthResponse( - chromeos::http::Response* response, + const HttpClient::Response& response, chromeos::ErrorPtr* error); // This attempts to open a notification channel. The channel needs to be @@ -215,10 +215,10 @@ void SendCloudRequest(const std::shared_ptr<const CloudRequestData>& data); void OnCloudRequestSuccess( const std::shared_ptr<const CloudRequestData>& data, - chromeos::http::RequestID request_id, - std::unique_ptr<chromeos::http::Response> response); + int request_id, + const HttpClient::Response& response); void OnCloudRequestError(const std::shared_ptr<const CloudRequestData>& data, - chromeos::http::RequestID request_id, + int request_id, const chromeos::Error* error); void RetryCloudRequest(const std::shared_ptr<const CloudRequestData>& data); void OnAccessTokenRefreshed( @@ -305,7 +305,10 @@ bool connected_to_cloud_{false}; // HTTP transport used for communications. - std::shared_ptr<chromeos::http::Transport> transport_; + // TODO(vitalybuka): Move to buffet. + std::unique_ptr<buffet::HttpTransportClient> http_client_owner_; + HttpClient* http_client_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; // Global command manager. std::shared_ptr<CommandManager> command_manager_;
diff --git a/libweave/src/http_transport_client.cc b/libweave/src/http_transport_client.cc new file mode 100644 index 0000000..dbe0ffc --- /dev/null +++ b/libweave/src/http_transport_client.cc
@@ -0,0 +1,85 @@ +// Copyright 2015 The Chromium OS 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 "libweave/src/http_transport_client.h" + +#include <base/bind.h> +#include <chromeos/errors/error.h> +#include <chromeos/http/http_request.h> +#include <chromeos/http/http_utils.h> + +namespace buffet { + +namespace { + +class ResponseImpl : public weave::HttpClient::Response { + public: + ~ResponseImpl() override = default; + explicit ResponseImpl(std::unique_ptr<chromeos::http::Response> response) + : response_{std::move(response)}, + data_{response_->ExtractDataAsString()} {} + + // weave::HttpClient::Response implementation + int GetStatusCode() const override { return response_->GetStatusCode(); } + + std::string GetContentType() const override { + return response_->GetContentType(); + } + + const std::string& GetData() const override { return data_; } + + private: + std::unique_ptr<chromeos::http::Response> response_; + std::string data_; + DISALLOW_COPY_AND_ASSIGN(ResponseImpl); +}; + +void OnSuccessCallback( + const weave::HttpClient::SuccessCallback& success_callback, + int id, + std::unique_ptr<chromeos::http::Response> response) { + success_callback.Run(id, ResponseImpl{std::move(response)}); +} + +void OnErrorCallback(const weave::HttpClient::ErrorCallback& error_callback, + int id, + const chromeos::Error* error) { + error_callback.Run(id, error); +} + +} // anonymous namespace + +HttpTransportClient::HttpTransportClient( + const std::shared_ptr<chromeos::http::Transport>& transport) + : transport_{transport} {} + +HttpTransportClient::~HttpTransportClient() {} + +std::unique_ptr<weave::HttpClient::Response> +HttpTransportClient::SendRequestAndBlock(const std::string& method, + const std::string& url, + const std::string& data, + const std::string& mime_type, + const Headers& headers, + chromeos::ErrorPtr* error) { + return std::unique_ptr<weave::HttpClient::Response>{ + new ResponseImpl{chromeos::http::SendRequestAndBlock( + method, url, data.data(), data.size(), mime_type, headers, transport_, + error)}}; +} + +int HttpTransportClient::SendRequest(const std::string& method, + const std::string& url, + const std::string& data, + const std::string& mime_type, + const Headers& headers, + const SuccessCallback& success_callback, + const ErrorCallback& error_callback) { + return chromeos::http::SendRequest( + method, url, data.data(), data.size(), mime_type, headers, transport_, + base::Bind(&OnSuccessCallback, success_callback), + base::Bind(&OnErrorCallback, error_callback)); +} + +} // namespace buffet
diff --git a/libweave/src/http_transport_client.h b/libweave/src/http_transport_client.h new file mode 100644 index 0000000..0eb5579 --- /dev/null +++ b/libweave/src/http_transport_client.h
@@ -0,0 +1,52 @@ +// Copyright 2015 The Chromium OS 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 LIBWEAVE_SRC_HTTP_TRANSPORT_CLIENT_H_ +#define LIBWEAVE_SRC_HTTP_TRANSPORT_CLIENT_H_ + +#include <memory> +#include <string> + +#include <weave/http_client.h> + +namespace chromeos { +namespace http { +class Transport; +} +} + +namespace buffet { + +class HttpTransportClient : public weave::HttpClient { + public: + explicit HttpTransportClient( + const std::shared_ptr<chromeos::http::Transport>& transport); + + ~HttpTransportClient() override; + + // weave::HttpClient implementation. + std::unique_ptr<Response> SendRequestAndBlock( + const std::string& method, + const std::string& url, + const std::string& data, + const std::string& mime_type, + const Headers& headers, + chromeos::ErrorPtr* error) override; + + int SendRequest(const std::string& method, + const std::string& url, + const std::string& data, + const std::string& mime_type, + const Headers& headers, + const SuccessCallback& success_callback, + const ErrorCallback& error_callback) override; + + private: + std::shared_ptr<chromeos::http::Transport> transport_; + DISALLOW_COPY_AND_ASSIGN(HttpTransportClient); +}; + +} // namespace buffet + +#endif // LIBWEAVE_SRC_HTTP_TRANSPORT_CLIENT_H_