| // Copyright 2018 The Fuchsia 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 "topaz/auth_providers/oauth/oauth_request_builder.h" |
| |
| #include <iomanip> |
| #include <iostream> |
| |
| #include "lib/fsl/socket/strings.h" |
| #include "lib/fsl/vmo/strings.h" |
| #include "lib/fxl/logging.h" |
| #include "lib/fxl/macros.h" |
| #include "lib/fxl/strings/join_strings.h" |
| #include "lib/fxl/strings/string_number_conversions.h" |
| |
| namespace auth_providers { |
| namespace oauth { |
| |
| namespace http = ::fuchsia::net::oldhttp; |
| |
| namespace { |
| |
| std::string UrlEncode(const std::string& value) { |
| std::ostringstream escaped; |
| escaped.fill('0'); |
| escaped << std::hex; |
| |
| for (char c : value) { |
| // Keep alphanumeric and other accepted characters intact |
| if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '=' || |
| c == '&' || c == '+') { |
| escaped << c; |
| continue; |
| } |
| |
| // Any other characters are percent-encoded |
| escaped << std::uppercase; |
| escaped << '%' << std::setw(2) << int(static_cast<unsigned char>(c)); |
| escaped << std::nouppercase; |
| } |
| |
| return escaped.str(); |
| } |
| |
| } // namespace |
| |
| OAuthRequestBuilder::OAuthRequestBuilder(const std::string& url, |
| const std::string& method) |
| : url_(url), method_(method) { |
| FXL_CHECK(!url_.empty()); |
| FXL_CHECK(!method_.empty()); |
| } |
| |
| OAuthRequestBuilder::~OAuthRequestBuilder() {} |
| |
| OAuthRequestBuilder& OAuthRequestBuilder::SetAuthorizationHeader( |
| const std::string& token) { |
| FXL_DCHECK(!token.empty()); |
| http_headers_["Authorization"] = "Bearer " + token; |
| return *this; |
| } |
| |
| OAuthRequestBuilder& OAuthRequestBuilder::SetUrlEncodedBody( |
| const std::string& body) { |
| http_headers_["content-type"] = "application/x-www-form-urlencoded"; |
| |
| if (body.empty()) { |
| return *this; |
| } |
| return SetRequestBody(UrlEncode(body)); |
| } |
| |
| OAuthRequestBuilder& OAuthRequestBuilder::SetJsonBody(const std::string& body) { |
| http_headers_["accept"] = "application/json"; |
| http_headers_["content-type"] = "application/json"; |
| return SetRequestBody(body); |
| } |
| |
| OAuthRequestBuilder& OAuthRequestBuilder::SetQueryParams( |
| std::map<std::string, std::string> query_params) { |
| for (auto it = query_params.begin(); it != query_params.end(); ++it) { |
| query_string_ += (it == query_params.begin() ? "?" : "&"); |
| query_string_ += UrlEncode(it->first) + "=" + UrlEncode(it->second); |
| } |
| return *this; |
| } |
| |
| http::URLRequest OAuthRequestBuilder::Build() const { |
| fsl::SizedVmo data; |
| auto result = fsl::VmoFromString(request_body_, &data); |
| FXL_CHECK(result); |
| |
| http::URLRequest request; |
| request.url = url_ + query_string_; |
| request.method = method_; |
| request.auto_follow_redirects = true; |
| request.body = http::URLBody::New(); |
| request.body->set_buffer(std::move(data).ToTransport()); |
| for (const auto& http_header : http_headers_) { |
| http::HttpHeader hdr; |
| hdr.name = http_header.first; |
| hdr.value = http_header.second; |
| request.headers.push_back(std::move(hdr)); |
| } |
| |
| return request; |
| } |
| |
| OAuthRequestBuilder& OAuthRequestBuilder::SetRequestBody( |
| const std::string& body) { |
| request_body_ = body; |
| |
| uint64_t data_size = request_body_.length(); |
| if (data_size > 0) |
| http_headers_["content-length"] = fxl::NumberToString(data_size).data(); |
| |
| return *this; |
| } |
| |
| } // namespace oauth |
| } // namespace auth_providers |