Integrate network related part which both nearby sharing and fastpair are adopted.

Details can be seen in the `Integrate reusable internal components into third_party` part of `server access design doc` (go/fast_pair_server_data_access)

PiperOrigin-RevId: 498208011
This commit is contained in:
hai007
2022-12-28 10:28:32 -08:00
committed by Copybara-Service
parent 6ef8a4c00a
commit 88e350e5d2
38 changed files with 2926 additions and 2 deletions
+8
View File
@@ -416,6 +416,7 @@ let package = Package(
"internal/platform/implementation/BUILD",
"internal/platform/BUILD",
"internal/analytics/BUILD",
"internal/network/BUILD",
// tests
"connections/listeners_test.cc",
"connections/strategy_test.cc",
@@ -520,6 +521,13 @@ let package = Package(
"internal/platform/byte_utils_test.cc",
"internal/platform/direct_executor_test.cc",
"internal/platform/borrowable_test.cc",
"internal/platform/implementation/windows/http_loader_test.cc",
"internal/network/utils_test.cc",
"internal/network/url_test.cc",
"internal/network/http_response_test.cc",
"internal/network/http_request_test.cc",
"internal/network/http_client_impl_test.cc",
"internal/network/http_status_code_test.cc",
// simulation
"connections/implementation/offline_simulation_user.cc",
"connections/implementation/simulation_user.cc",
+96
View File
@@ -0,0 +1,96 @@
licenses(["notice"])
cc_library(
name = "types",
srcs = [
"http_request.cc",
"http_response.cc",
"http_status_code.cc",
"url.cc",
"utils.cc",
],
hdrs = [
"http_body.h",
"http_client.h",
"http_client_factory.h",
"http_request.h",
"http_response.h",
"http_status_code.h",
"url.h",
"utils.h",
],
visibility = [
"//connections:__subpackages__",
"//fastpair:__subpackages__",
"//internal:__pkg__",
"//internal/platform:__subpackages__",
"//internal/platform/implementation:__subpackages__",
"//location/nearby/cpp/fastpair:__subpackages__",
"//presence:__subpackages__",
],
deps = [
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
],
)
cc_library(
name = "nearby_http_client",
srcs = [
"http_client_impl.cc",
],
hdrs = [
"debug.h",
"http_client_factory_impl.h",
"http_client_impl.h",
],
defines = ["_SILENCE_CLANG_COROUTINE_MESSAGE"],
visibility = [
"//connections:__subpackages__",
"//fastpair:__subpackages__",
"//internal:__pkg__",
"//internal/platform:__subpackages__",
"//internal/platform/implementation:__subpackages__",
"//location/nearby/cpp/fastpair:__subpackages__",
"//presence:__subpackages__",
],
deps = [
":types",
"//internal/platform:logging",
"//internal/platform/implementation:platform",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/synchronization",
],
)
cc_test(
name = "nearby_http_client_test",
size = "small",
timeout = "short",
srcs = [
"http_client_impl_test.cc",
"http_request_test.cc",
"http_response_test.cc",
"http_status_code_test.cc",
"url_test.cc",
"utils_test.cc",
],
shard_count = 8,
deps = [
":nearby_http_client",
":types",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation/g3",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
+34
View File
@@ -0,0 +1,34 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_NETWORK_DEBUG_H_
#define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_DEBUG_H_
namespace location {
namespace nearby {
namespace network {
namespace debug {
// Indicates to whether output HTTP request.
constexpr bool kRequestEnabled = false;
// Indicates to whether output HTTP response.
constexpr bool kResponseEnabled = false;
} // namespace debug
} // namespace network
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_NETWORK_DEBUG_H_
+67
View File
@@ -0,0 +1,67 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_BODY_H_
#define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_BODY_H_
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
namespace network {
class HttpBody {
public:
HttpBody() = default;
~HttpBody() = default;
HttpBody(const HttpBody&) = default;
HttpBody& operator=(const HttpBody&) = default;
HttpBody(HttpBody&&) = default;
HttpBody& operator=(HttpBody&&) = default;
void SetData(const char* data, size_t size) {
if (data == nullptr) {
size = 0;
}
data_.assign(data, size);
}
void SetData(absl::string_view data) {
data_.assign(data.data(), data.size());
}
bool empty() { return data_.empty(); }
const char* data() const { return &data_[0]; }
size_t size() const { return data_.size(); }
absl::string_view GetRawData() const { return data_; }
private:
std::string data_;
};
using HttpRequestBody = HttpBody;
using HttpResponseBody = HttpBody;
} // namespace network
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_BODY_H_
+41
View File
@@ -0,0 +1,41 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_H_
#define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_H_
#include <functional>
#include "absl/status/statusor.h"
#include "internal/network/http_request.h"
#include "internal/network/http_response.h"
namespace location {
namespace nearby {
namespace network {
class HttpClient {
public:
virtual ~HttpClient() = default;
virtual void StartRequest(
const HttpRequest& request,
std::function<void(const absl::StatusOr<HttpResponse>&)> callback) = 0;
};
} // namespace network
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_H_
+38
View File
@@ -0,0 +1,38 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_FACTORY_H_
#define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_FACTORY_H_
#include <memory>
#include <utility>
#include "internal/network/http_client.h"
namespace location {
namespace nearby {
namespace network {
class HttpClientFactory {
public:
virtual ~HttpClientFactory() = default;
virtual std::unique_ptr<HttpClient> CreateInstance() = 0;
};
} // namespace network
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_FACTORY_H_
@@ -0,0 +1,38 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_FACTORY_IMPL_H_
#define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_FACTORY_IMPL_H_
#include <memory>
#include "internal/network/http_client_factory.h"
#include "internal/network/http_client_impl.h"
namespace location {
namespace nearby {
namespace network {
class HttpClientFactoryImpl : public HttpClientFactory {
public:
std::unique_ptr<HttpClient> CreateInstance() override {
return std::make_unique<NearbyHttpClient>();
}
};
} // namespace network
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_FACTORY_IMPL_H_
+123
View File
@@ -0,0 +1,123 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/network/http_client_impl.h"
#include <chrono> // NOLINT
#include <functional>
#include <future> // NOLINT
#include <ostream>
#include <sstream>
#include <utility>
#include "internal/network/debug.h"
#include "internal/platform/implementation/platform.h"
#include "internal/platform/logging.h"
namespace location {
namespace nearby {
namespace network {
void NearbyHttpClient::StartRequest(
const HttpRequest& request,
std::function<void(const absl::StatusOr<HttpResponse>&)> callback) {
absl::MutexLock lock(&mutex_);
CleanThreads();
std::future<void> http_thread = std::async(std::launch::async, [&, request,
callback]() {
api::WebRequest web_request;
web_request.url = request.GetUrl().GetUrlPath();
web_request.method = absl::StrCat(request.GetMethodString());
for (const auto& header : request.GetAllHeaders()) {
for (const auto& value : header.second) {
web_request.headers.emplace(header.first, value);
}
}
web_request.body = absl::StrCat(request.GetBody().GetRawData());
if (debug::kRequestEnabled) {
std::stringstream request_stream;
request_stream << "HTTP REQUEST====>" << std::endl;
request_stream << web_request.method << " " << web_request.url
<< std::endl;
for (const auto& header : web_request.headers) {
request_stream << header.first << ": " << header.second << std::endl;
}
request_stream << std::endl;
request_stream << "body size: " << request.GetBody().GetRawData().size()
<< std::endl;
NEARBY_LOGS(VERBOSE) << request_stream.str();
}
absl::StatusOr<api::WebResponse> web_response =
api::ImplementationPlatform::SendRequest(web_request);
if (!web_response.ok()) {
if (callback != nullptr) {
callback(web_response.status());
}
return;
}
if (debug::kResponseEnabled) {
std::stringstream response_stream;
response_stream << "HTTP RESPONSE====>" << std::endl;
response_stream << "url: " << web_request.url << std::endl;
response_stream << web_response->status_code << " "
<< web_response->status_text << std::endl;
for (const auto& header : web_response->headers) {
response_stream << header.first << ": " << header.second << std::endl;
}
response_stream << std::endl;
response_stream << "body size: " << web_response->body.size()
<< std::endl;
NEARBY_LOGS(VERBOSE) << response_stream.str();
}
HttpResponse response;
response.SetStatusCode(
static_cast<HttpStatusCode>(web_response->status_code));
response.SetReasonPhrase(web_response->status_text);
for (const auto& header : web_response->headers) {
response.AddHeader(header.first, header.second);
}
response.SetBody(web_response->body);
if (callback != nullptr) {
callback(response);
}
});
http_threads_.push_back(std::move(http_thread));
}
void NearbyHttpClient::CleanThreads() {
auto it = http_threads_.begin();
while (it != http_threads_.end()) {
// Delete the thread if it is ready
auto status = it->wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
it = http_threads_.erase(it);
} else {
++it;
}
}
}
} // namespace network
} // namespace nearby
} // namespace location
+57
View File
@@ -0,0 +1,57 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_IMPL_H_
#define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_IMPL_H_
#include <functional>
#include <future> // NOLINT
#include <thread> // NOLINT
#include <utility>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "internal/network/http_client.h"
namespace location {
namespace nearby {
namespace network {
class NearbyHttpClient : public HttpClient {
public:
NearbyHttpClient() = default;
~NearbyHttpClient() override = default;
NearbyHttpClient(const NearbyHttpClient&) = default;
NearbyHttpClient& operator=(const NearbyHttpClient&) = default;
NearbyHttpClient(NearbyHttpClient&&) = default;
NearbyHttpClient& operator=(NearbyHttpClient&&) = default;
void StartRequest(const HttpRequest& request,
std::function<void(const absl::StatusOr<HttpResponse>&)>
callback) override ABSL_LOCKS_EXCLUDED(mutex_);
private:
void CleanThreads() ABSL_SHARED_LOCKS_REQUIRED(mutex_);
absl::Mutex mutex_;
std::vector<std::future<void>> http_threads_ ABSL_GUARDED_BY(mutex_);
};
} // namespace network
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_IMPL_H_
+275
View File
@@ -0,0 +1,275 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/network/http_client_impl.h"
#include <cstddef>
#include <map>
#include <string>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "internal/network/http_status_code.h"
#include "internal/platform/implementation/http_loader.h"
#include "internal/platform/implementation/platform.h"
namespace location {
namespace nearby {
namespace api {
namespace {
struct HttpTestContext {
WebRequest web_request;
WebResponse web_response;
absl::Status status;
};
HttpTestContext* GetContext() {
static HttpTestContext* context = new HttpTestContext();
return context;
}
} // namespace
// Mock web implementation of the platform
absl::StatusOr<WebResponse> ImplementationPlatform::SendRequest(
const WebRequest& request) {
GetContext()->web_request = request;
if (GetContext()->status.ok()) {
return GetContext()->web_response;
}
return GetContext()->status;
}
} // namespace api
namespace network {
using ::testing::SizeIs;
class NearbyHttpClientTest : public ::testing::Test {
public:
void SetUp() override {
api::GetContext()->web_request = api::WebRequest();
api::GetContext()->web_response = api::WebResponse();
api::GetContext()->status = absl::Status();
}
void MockFailedResponse(absl::Status status) {
api::GetContext()->status = status;
}
void MockResponse(network::HttpStatusCode status,
absl::string_view status_message,
const std::multimap<std::string, std::string>& headers,
absl::string_view body) {
api::WebResponse web_response;
web_response.status_code = static_cast<int>(status);
web_response.status_text = absl::StrCat(status_message);
web_response.headers = headers;
web_response.body = absl::StrCat(body);
api::GetContext()->web_response = web_response;
}
api::WebRequest GetWebRequest() { return api::GetContext()->web_request; }
absl::StatusOr<HttpResponse> GetResponse(
absl::string_view url, HttpRequestMethod method,
const std::multimap<std::string, std::string>& headers,
absl::string_view body) {
absl::StatusOr<HttpResponse> result;
absl::StatusOr<Url> request_url = Url::Create(url);
if (!request_url.ok()) {
return request_url.status();
}
HttpRequest request{request_url.value()};
auto it = headers.begin();
while (it != headers.end()) {
request.AddHeader(it->first, it->second);
++it;
}
request.SetMethod(method);
request.SetBody(body);
absl::Notification notification;
client_.StartRequest(
request, [&result, &notification](
const absl::StatusOr<HttpResponse>& http_response) {
result = http_response;
notification.Notify();
});
// No timeout to emulate original behavior
notification.WaitForNotification();
return result;
}
void CheckHeader(const std::multimap<std::string, std::string>& headers,
absl::string_view key, absl::string_view expected_value) {
auto it = headers.find(std::string(key));
ASSERT_TRUE(it != headers.end());
bool found = false;
while (it != headers.end()) {
if (it->second == absl::StrCat(expected_value)) {
found = true;
break;
}
++it;
}
EXPECT_TRUE(found);
}
private:
NearbyHttpClient client_;
};
namespace {
TEST_F(NearbyHttpClientTest, TestGet) {
MockResponse(HttpStatusCode::kHttpOk, "OK", {{"Content_Type", "text/html"}},
"web content");
auto result =
GetResponse("http://www.google.com", HttpRequestMethod::kGet, {}, "");
// Checks request.
api::WebRequest web_request = GetWebRequest();
EXPECT_EQ(web_request.url, "http://www.google.com");
EXPECT_EQ(web_request.method, "GET");
// Checks response.
ASSERT_TRUE(result.ok());
EXPECT_EQ(result->GetStatusCode(), HttpStatusCode::kHttpOk);
EXPECT_EQ(result->GetBody().GetRawData(), "web content");
ASSERT_THAT(result->GetAllHeaders(), SizeIs(1));
EXPECT_EQ(result->GetAllHeaders().at("Content_Type")[0], "text/html");
}
TEST_F(NearbyHttpClientTest, TestGetWithQuery) {
MockResponse(HttpStatusCode::kHttpOk, "OK", {{"Content_Type", "text/html"}},
"web content");
auto result = GetResponse("http://www.google.com?name=name1&age=36",
HttpRequestMethod::kGet, {}, "");
// Checks request.
api::WebRequest web_request = GetWebRequest();
EXPECT_EQ(web_request.url, "http://www.google.com?name=name1&age=36");
EXPECT_EQ(web_request.method, "GET");
// Checks response.
ASSERT_TRUE(result.ok());
EXPECT_EQ(result->GetStatusCode(), HttpStatusCode::kHttpOk);
}
TEST_F(NearbyHttpClientTest, TestGetWithErrorResult) {
MockFailedResponse(absl::InternalError("no connection."));
auto result = GetResponse("http://www.google.com?name=name1&age=36",
HttpRequestMethod::kGet, {}, "");
// Checks request.
api::WebRequest web_request = GetWebRequest();
EXPECT_EQ(web_request.url, "http://www.google.com?name=name1&age=36");
EXPECT_EQ(web_request.method, "GET");
// Checks response.
EXPECT_FALSE(result.ok());
}
TEST_F(NearbyHttpClientTest, TestPost) {
MockResponse(HttpStatusCode::kHttpNoContent, "OK",
{{"Content_Type", "text/html"}}, "");
auto result =
GetResponse("http://www.google.com", HttpRequestMethod::kPost, {}, "");
// Checks request.
api::WebRequest web_request = GetWebRequest();
EXPECT_EQ(web_request.url, "http://www.google.com");
EXPECT_EQ(web_request.method, "POST");
// Checks response.
ASSERT_TRUE(result.ok());
EXPECT_EQ(result->GetStatusCode(), HttpStatusCode::kHttpNoContent);
HttpResponseBody body = result->GetBody();
EXPECT_TRUE(body.empty());
}
TEST_F(NearbyHttpClientTest, TestPostWithHeader) {
MockResponse(HttpStatusCode::kHttpNoContent, "OK",
{{"Content_Type", "text/html"}}, "");
auto result =
GetResponse("http://www.google.com", HttpRequestMethod::kPost,
{{"Content_Type", "text/json"}, {"size", "596"}}, "");
// Checks request.
api::WebRequest web_request = GetWebRequest();
EXPECT_EQ(web_request.url, "http://www.google.com");
EXPECT_EQ(web_request.method, "POST");
ASSERT_NO_FATAL_FAILURE(
CheckHeader(web_request.headers, "Content_Type", "text/json"));
ASSERT_NO_FATAL_FAILURE(CheckHeader(web_request.headers, "size", "596"));
// Checks response.
ASSERT_TRUE(result.ok());
EXPECT_EQ(result->GetStatusCode(), HttpStatusCode::kHttpNoContent);
EXPECT_EQ(result->GetBody().GetRawData(), "");
}
TEST_F(NearbyHttpClientTest, TestPostWithErrorResult) {
MockFailedResponse(absl::UnauthenticatedError("no user."));
auto result =
GetResponse("http://www.google.com", HttpRequestMethod::kPost,
{{"Content_Type", "text/json"}, {"size", "596"}}, "");
// Checks request.
api::WebRequest web_request = GetWebRequest();
EXPECT_EQ(web_request.url, "http://www.google.com");
EXPECT_EQ(web_request.method, "POST");
ASSERT_NO_FATAL_FAILURE(
CheckHeader(web_request.headers, "Content_Type", "text/json"));
ASSERT_NO_FATAL_FAILURE(CheckHeader(web_request.headers, "size", "596"));
// Checks response.
ASSERT_FALSE(result.ok());
}
TEST_F(NearbyHttpClientTest, TestRequestWithCleanThreads) {
MockResponse(HttpStatusCode::kHttpOk, "OK", {{"Content_Type", "text/html"}},
"web content");
auto result =
GetResponse("http://www.google.com", HttpRequestMethod::kGet, {}, "");
// Checks request.
api::WebRequest web_request = GetWebRequest();
EXPECT_EQ(web_request.url, "http://www.google.com");
EXPECT_EQ(web_request.method, "GET");
// Checks response.
ASSERT_TRUE(result.ok());
result =
GetResponse("http://www.youtube.com", HttpRequestMethod::kGet, {}, "");
ASSERT_TRUE(result.ok());
}
} // namespace
} // namespace network
} // namespace nearby
} // namespace location
+104
View File
@@ -0,0 +1,104 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/network/http_request.h"
#include <string>
#include <vector>
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
namespace network {
HttpRequest::HttpRequest(const Url& url) : url_(url) {
method_ = HttpRequestMethod::kGet;
}
void HttpRequest::SetUrl(const Url& url) { url_ = url; }
const Url& HttpRequest::GetUrl() const { return url_; }
void HttpRequest::SetMethod(const HttpRequestMethod& method) {
method_ = method;
}
const HttpRequestMethod& HttpRequest::GetMethod() const { return method_; }
absl::string_view HttpRequest::GetMethodString() const {
switch (method_) {
case HttpRequestMethod::kConnect:
return "CONNECT";
case HttpRequestMethod::kDelete:
return "DELETE";
case HttpRequestMethod::kGet:
return "GET";
case HttpRequestMethod::kHead:
return "HEAD";
case HttpRequestMethod::kOptions:
return "OPTIONS";
case HttpRequestMethod::kPatch:
return "PATCH";
case HttpRequestMethod::kPost:
return "POST";
case HttpRequestMethod::kPut:
return "PUT";
case HttpRequestMethod::kTrace:
return "TRACE";
}
}
void HttpRequest::AddHeader(absl::string_view header, absl::string_view value) {
auto it = headers_.find(header);
if (it == headers_.end()) {
headers_.emplace(header, std::vector<std::string>({std::string(value)}));
} else {
it->second.push_back(std::string(value));
}
}
void HttpRequest::RemoveHeader(absl::string_view header) {
headers_.erase(header);
}
const absl::flat_hash_map<std::string, std::vector<std::string>>&
HttpRequest::GetAllHeaders() const {
return headers_;
}
void HttpRequest::AddQueryParameter(absl::string_view query,
absl::string_view value) {
url_.AddQueryParameter(query, value);
}
void HttpRequest::RemoveQueryParameter(absl::string_view query) {
url_.RemoveQueryParameter(query);
}
const Url::QueryParameters& HttpRequest::GetAllQueryParameters() const {
return url_.GetAllQueryStrings();
}
void HttpRequest::SetBody(const HttpRequestBody& body) { body_ = body; }
void HttpRequest::SetBody(absl::string_view body) {
body_.SetData(body.data(), body.size());
}
const HttpRequestBody& HttpRequest::GetBody() const { return body_; }
} // namespace network
} // namespace nearby
} // namespace location
+92
View File
@@ -0,0 +1,92 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_REQUEST_H_
#define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_REQUEST_H_
#include <memory>
#include <string>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "internal/network/http_body.h"
#include "internal/network/url.h"
namespace location {
namespace nearby {
namespace network {
enum class HttpRequestMethod {
kOptions,
kGet,
kHead,
kPost,
kPut,
kDelete,
kTrace,
kConnect,
kPatch
};
class HttpRequest {
public:
HttpRequest() = default;
explicit HttpRequest(const Url& url);
~HttpRequest() = default;
HttpRequest(const HttpRequest&) = default;
HttpRequest& operator=(const HttpRequest&) = default;
HttpRequest(HttpRequest&&) = default;
HttpRequest& operator=(HttpRequest&&) = default;
void SetUrl(const Url& url);
const Url& GetUrl() const;
void SetMethod(const HttpRequestMethod& method);
const HttpRequestMethod& GetMethod() const;
absl::string_view GetMethodString() const;
void AddHeader(absl::string_view header, absl::string_view value);
void RemoveHeader(absl::string_view header);
const absl::flat_hash_map<std::string, std::vector<std::string>>&
GetAllHeaders() const;
void AddQueryParameter(absl::string_view query, absl::string_view value);
void RemoveQueryParameter(absl::string_view query);
const Url::QueryParameters& GetAllQueryParameters() const;
void SetBody(const HttpRequestBody& body);
void SetBody(absl::string_view body);
const HttpRequestBody& GetBody() const;
private:
// The url of the request
Url url_;
// The request method: GET, POST, etc.
HttpRequestMethod method_ = HttpRequestMethod::kGet;
// The request headers, may include repeat keys
absl::flat_hash_map<std::string, std::vector<std::string>> headers_;
// The request body, it may be empty.
HttpRequestBody body_;
};
} // namespace network
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_REQUEST_H_
+88
View File
@@ -0,0 +1,88 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/network/http_request.h"
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "internal/network/http_body.h"
namespace location {
namespace nearby {
namespace network {
namespace {
using ::testing::SizeIs;
TEST(HttpRequest, TestBuildRequest) {
auto url = Url::Create("http://www.google.com");
ASSERT_TRUE(url.ok());
HttpRequest request_explicit(*url);
EXPECT_EQ(request_explicit.GetMethodString(), "GET");
EXPECT_EQ(request_explicit.GetUrl(), *url);
HttpRequest request;
EXPECT_EQ(request.GetMethodString(), "GET");
request.SetUrl(*url);
EXPECT_EQ(request.GetUrl(), *url);
request.AddQueryParameter("name", "google");
EXPECT_THAT(request.GetAllQueryParameters(), SizeIs(1));
request.AddQueryParameter("name", "android");
EXPECT_THAT(request.GetAllQueryParameters(), SizeIs(2));
request.AddHeader("content-type", "text/html");
EXPECT_THAT(request.GetAllHeaders(), SizeIs(1));
request.SetMethod(HttpRequestMethod::kPost);
EXPECT_EQ(request.GetMethodString(), "POST");
EXPECT_EQ(request.GetMethod(), HttpRequestMethod::kPost);
request.RemoveQueryParameter("name");
EXPECT_THAT(request.GetAllQueryParameters(), SizeIs(0));
request.RemoveHeader("content-type");
EXPECT_THAT(request.GetAllHeaders(), SizeIs(0));
request.SetBody("test body");
EXPECT_EQ(request.GetBody().GetRawData(), "test body");
HttpRequestBody body;
body.SetData("new body");
request.SetBody(body);
EXPECT_EQ(request.GetBody().GetRawData(), "new body");
body.SetData(nullptr, 100);
request.SetBody(body);
EXPECT_TRUE(request.GetBody().GetRawData().empty());
}
TEST(HttpRequest, TestGetMethodString) {
HttpRequest request;
request.SetMethod(HttpRequestMethod::kPost);
EXPECT_EQ(request.GetMethodString(), "POST");
request.SetMethod(HttpRequestMethod::kPut);
EXPECT_EQ(request.GetMethodString(), "PUT");
request.SetMethod(HttpRequestMethod::kDelete);
EXPECT_EQ(request.GetMethodString(), "DELETE");
request.SetMethod(HttpRequestMethod::kConnect);
EXPECT_EQ(request.GetMethodString(), "CONNECT");
request.SetMethod(HttpRequestMethod::kHead);
EXPECT_EQ(request.GetMethodString(), "HEAD");
request.SetMethod(HttpRequestMethod::kOptions);
EXPECT_EQ(request.GetMethodString(), "OPTIONS");
request.SetMethod(HttpRequestMethod::kPatch);
EXPECT_EQ(request.GetMethodString(), "PATCH");
request.SetMethod(HttpRequestMethod::kTrace);
EXPECT_EQ(request.GetMethodString(), "TRACE");
}
} // namespace
} // namespace network
} // namespace nearby
} // namespace location
+74
View File
@@ -0,0 +1,74 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/network/http_response.h"
#include <string>
#include <vector>
#include "absl/strings/str_cat.h"
namespace location {
namespace nearby {
namespace network {
void HttpResponse::SetStatusCode(const HttpStatusCode& status_code) {
status_code_ = status_code;
}
HttpStatusCode HttpResponse::GetStatusCode() const { return status_code_; }
void HttpResponse::SetReasonPhrase(absl::string_view reason_phrase) {
reason_phrase_ = std::string(reason_phrase);
}
absl::string_view HttpResponse::GetReasonPhrase() const {
return reason_phrase_;
}
void HttpResponse::AddHeader(absl::string_view header,
absl::string_view value) {
auto it = headers_.find(header);
if (it == headers_.end()) {
headers_.emplace(header, std::vector<std::string>({std::string(value)}));
} else {
it->second.push_back(std::string(value));
}
}
void HttpResponse::SetHeaders(
const absl::flat_hash_map<std::string, std::vector<std::string>>& headers) {
headers_ = headers;
}
const absl::flat_hash_map<std::string, std::vector<std::string>>&
HttpResponse::GetAllHeaders() const {
return headers_;
}
void HttpResponse::RemoveHeader(absl::string_view header) {
headers_.erase(header);
}
void HttpResponse::SetBody(const HttpResponseBody& body) { body_ = body; }
void HttpResponse::SetBody(absl::string_view body) {
body_.SetData(body.data(), body.size());
}
const HttpResponseBody& HttpResponse::GetBody() const { return body_; }
} // namespace network
} // namespace nearby
} // namespace location
+77
View File
@@ -0,0 +1,77 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_RESPONSE_H_
#define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_RESPONSE_H_
#include <memory>
#include <string>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "internal/network/http_body.h"
#include "internal/network/http_request.h"
#include "internal/network/http_status_code.h"
namespace location {
namespace nearby {
namespace network {
class HttpResponse {
public:
HttpResponse() = default;
~HttpResponse() = default;
HttpResponse(const HttpResponse&) = default;
HttpResponse& operator=(const HttpResponse&) = default;
HttpResponse(HttpResponse&&) = default;
HttpResponse& operator=(HttpResponse&&) = default;
void SetStatusCode(const HttpStatusCode& status_code);
HttpStatusCode GetStatusCode() const;
void SetReasonPhrase(absl::string_view reason_phrase);
absl::string_view GetReasonPhrase() const;
void AddHeader(absl::string_view header, absl::string_view value);
void RemoveHeader(absl::string_view header);
void SetHeaders(const absl::flat_hash_map<std::string,
std::vector<std::string>>& headers);
const absl::flat_hash_map<std::string, std::vector<std::string>>&
GetAllHeaders() const;
void SetBody(const HttpResponseBody& body);
void SetBody(absl::string_view body);
const HttpResponseBody& GetBody() const;
private:
// The status code returned from remote server
HttpStatusCode status_code_ = HttpStatusCode::kHttpOk;
// Provides a short textual description of the Status Code.
std::string reason_phrase_;
// The response headers returned from remove server
absl::flat_hash_map<std::string, std::vector<std::string>> headers_;
// The response content from remote server, it may be empty
HttpResponseBody body_;
};
} // namespace network
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_RESPONSE_H_
+47
View File
@@ -0,0 +1,47 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/network/http_response.h"
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
namespace location {
namespace nearby {
namespace network {
namespace {
using ::testing::SizeIs;
TEST(HttpResponse, TestBuildResponse) {
HttpResponse response;
response.SetStatusCode(HttpStatusCode::kHttpNotFound);
EXPECT_EQ(response.GetStatusCode(), HttpStatusCode::kHttpNotFound);
response.SetReasonPhrase("OK");
EXPECT_EQ(response.GetReasonPhrase(), "OK");
response.AddHeader("Content-Type", "text/html");
EXPECT_THAT(response.GetAllHeaders(), SizeIs(1));
response.RemoveHeader("Content-Type");
EXPECT_THAT(response.GetAllHeaders(), SizeIs(0));
HttpResponseBody body;
body.SetData("test body");
response.SetBody(body);
EXPECT_EQ(response.GetBody().GetRawData(), "test body");
}
} // namespace
} // namespace network
} // namespace nearby
} // namespace location
+118
View File
@@ -0,0 +1,118 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/network/http_status_code.h"
namespace location {
namespace nearby {
namespace network {
absl::string_view GetHttpReasonPhrase(HttpStatusCode code) {
switch (code) {
case HttpStatusCode::kHttpContinue:
return "Continue";
case HttpStatusCode::kHttpSwitchingProtocols:
return "Switching Protocols";
case HttpStatusCode::kEarlyHints:
return "Early Hints";
case HttpStatusCode::kHttpOk:
return "OK";
case HttpStatusCode::kHttpCreated:
return "Created";
case HttpStatusCode::kHttpAccepted:
return "Accepted";
case HttpStatusCode::kHttpNonAuthoritativeInformation:
return "Non-Authoritative Information";
case HttpStatusCode::kHttpNoContent:
return "No Content";
case HttpStatusCode::kHttpResetContent:
return "Reset Content";
case HttpStatusCode::kHttpPartialContent:
return "Partial Content";
case HttpStatusCode::kHttpMultipleChocies:
return "Multiple Choices";
case HttpStatusCode::kHttpMovedPermancently:
return "Moved Permanently";
case HttpStatusCode::kHttpFound:
return "Found";
case HttpStatusCode::kHttpSeeOther:
return "See Other";
case HttpStatusCode::kHttpNotModified:
return "Not Modified";
case HttpStatusCode::kHttpUseProxy:
return "Use Proxy";
case HttpStatusCode::kHttpTemporaryRedirect:
return "Temporary Redirect";
case HttpStatusCode::kHttpPermanentRedirect:
return "Permanent Redirect";
case HttpStatusCode::kHttpBadRequest:
return "Bad Request";
case HttpStatusCode::kHttpUnauthorized:
return "Unauthorized";
case HttpStatusCode::kHttpPaymentRequest:
return "Payment Required";
case HttpStatusCode::kHttpForbidden:
return "Forbidden";
case HttpStatusCode::kHttpNotFound:
return "Not Found";
case HttpStatusCode::kHttpMethodNotAllowed:
return "Method Not Allowed";
case HttpStatusCode::kHttpNotAcceptable:
return "Not Acceptable";
case HttpStatusCode::kHttpProxyAuthenticationRequired:
return "Proxy Authentication Required";
case HttpStatusCode::kHttpRequestTimeout:
return "Request Timeout";
case HttpStatusCode::kHttpConflict:
return "Conflict";
case HttpStatusCode::kHttpGone:
return "Gone";
case HttpStatusCode::kHttpLengthRequired:
return "Length Required";
case HttpStatusCode::kHttpPreconditionFailed:
return "Precondition Failed";
case HttpStatusCode::kHttpRequestEntityTooLarge:
return "Request Entity Too Large";
case HttpStatusCode::kHttpRequestUriTooLong:
return "Request-URI Too Long";
case HttpStatusCode::kHttpUnsupportedMediaType:
return "Unsupported Media Type";
case HttpStatusCode::kHttpRequestedRangeNotSatisfiable:
return "Requested Range Not Satisfiable";
case HttpStatusCode::kHttpExpectationFailed:
return "Expectation Failed";
case HttpStatusCode::kHttpInvalidXprivetToken:
return "Invalid XPrivet Token";
case HttpStatusCode::kHttpTooEarly:
return "Too Early";
case HttpStatusCode::kHttpTooManyRequests:
return "Too Many Requests";
case HttpStatusCode::kHttpInternalServerError:
return "Internal Server Error";
case HttpStatusCode::kHttpNotImplemented:
return "Not Implemented";
case HttpStatusCode::kHttpBadGateway:
return "Bad Gateway";
case HttpStatusCode::kHttpServiceUnavailable:
return "Service Unavailable";
case HttpStatusCode::kHttpGatewayTimeout:
return "Gateway Timeout";
case HttpStatusCode::kHttpVersionNotSupported:
return "HTTP Version Not Supported";
}
}
} // namespace network
} // namespace nearby
} // namespace location
+93
View File
@@ -0,0 +1,93 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_STATUS_CODE_H_
#define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_STATUS_CODE_H_
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
namespace network {
// HTTP response status codes are separated into five categories. Details can be
// found in https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
enum class HttpStatusCode {
// Informational 1xx: The request has been accepted and needs to be processed
// further.
kHttpContinue = 100,
kHttpSwitchingProtocols = 101,
kEarlyHints = 103,
// Information 2xx: The request has been accepted and approved by the server.
kHttpOk = 200,
kHttpCreated = 201,
kHttpAccepted = 202,
kHttpNonAuthoritativeInformation = 203,
kHttpNoContent = 204,
kHttpResetContent = 205,
kHttpPartialContent = 206,
// Redirection 3xx: The request needs client's further action to be completed.
kHttpMultipleChocies = 300,
kHttpMovedPermancently = 301,
kHttpFound = 302,
kHttpSeeOther = 303,
kHttpNotModified = 304,
kHttpUseProxy = 305,
// 306 is no longer used.
kHttpTemporaryRedirect = 307,
kHttpPermanentRedirect = 308,
// Client error 4xx: There may be errors in the client that prevent the server
// from processing the request.
kHttpBadRequest = 400,
kHttpUnauthorized = 401,
kHttpPaymentRequest = 402,
kHttpForbidden = 403,
kHttpNotFound = 404,
kHttpMethodNotAllowed = 405,
kHttpNotAcceptable = 406,
kHttpProxyAuthenticationRequired = 407,
kHttpRequestTimeout = 408,
kHttpConflict = 409,
kHttpGone = 410,
kHttpLengthRequired = 411,
kHttpPreconditionFailed = 412,
kHttpRequestEntityTooLarge = 413,
kHttpRequestUriTooLong = 414,
kHttpUnsupportedMediaType = 415,
kHttpRequestedRangeNotSatisfiable = 416,
kHttpExpectationFailed = 417,
// 418 returned by Cloud Print.
kHttpInvalidXprivetToken = 418,
kHttpTooEarly = 425,
kHttpTooManyRequests = 429,
// Server error 5xx
kHttpInternalServerError = 500,
kHttpNotImplemented = 501,
kHttpBadGateway = 502,
kHttpServiceUnavailable = 503,
kHttpGatewayTimeout = 504,
kHttpVersionNotSupported = 505
};
absl::string_view GetHttpReasonPhrase(HttpStatusCode code);
} // namespace network
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_STATUS_CODE_H_
+109
View File
@@ -0,0 +1,109 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/network/http_status_code.h"
#include "gtest/gtest.h"
namespace location {
namespace nearby {
namespace network {
namespace {
TEST(HttpStatusCode, TestReturnCorrectReasonPhrase) {
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpContinue), "Continue");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpSwitchingProtocols),
"Switching Protocols");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kEarlyHints), "Early Hints");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpOk), "OK");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpCreated), "Created");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpAccepted), "Accepted");
EXPECT_EQ(
GetHttpReasonPhrase(HttpStatusCode::kHttpNonAuthoritativeInformation),
"Non-Authoritative Information");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpNoContent), "No Content");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpResetContent),
"Reset Content");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpPartialContent),
"Partial Content");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpMultipleChocies),
"Multiple Choices");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpMovedPermancently),
"Moved Permanently");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpFound), "Found");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpSeeOther), "See Other");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpNotModified),
"Not Modified");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpUseProxy), "Use Proxy");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpTemporaryRedirect),
"Temporary Redirect");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpPermanentRedirect),
"Permanent Redirect");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpBadRequest),
"Bad Request");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpUnauthorized),
"Unauthorized");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpPaymentRequest),
"Payment Required");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpForbidden), "Forbidden");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpNotFound), "Not Found");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpMethodNotAllowed),
"Method Not Allowed");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpNotAcceptable),
"Not Acceptable");
EXPECT_EQ(
GetHttpReasonPhrase(HttpStatusCode::kHttpProxyAuthenticationRequired),
"Proxy Authentication Required");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpRequestTimeout),
"Request Timeout");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpConflict), "Conflict");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpGone), "Gone");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpLengthRequired),
"Length Required");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpPreconditionFailed),
"Precondition Failed");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpRequestEntityTooLarge),
"Request Entity Too Large");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpUnsupportedMediaType),
"Unsupported Media Type");
EXPECT_EQ(
GetHttpReasonPhrase(HttpStatusCode::kHttpRequestedRangeNotSatisfiable),
"Requested Range Not Satisfiable");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpExpectationFailed),
"Expectation Failed");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpInvalidXprivetToken),
"Invalid XPrivet Token");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpTooEarly), "Too Early");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpTooManyRequests),
"Too Many Requests");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpInternalServerError),
"Internal Server Error");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpNotImplemented),
"Not Implemented");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpBadGateway),
"Bad Gateway");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpServiceUnavailable),
"Service Unavailable");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpGatewayTimeout),
"Gateway Timeout");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpVersionNotSupported),
"HTTP Version Not Supported");
EXPECT_EQ(GetHttpReasonPhrase(HttpStatusCode::kHttpRequestUriTooLong),
"Request-URI Too Long");
}
} // namespace
} // namespace network
} // namespace nearby
} // namespace location
+259
View File
@@ -0,0 +1,259 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/network/url.h"
#include <ostream>
#include <regex> //NOLINT
#include <string>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "internal/network/utils.h"
namespace location {
namespace nearby {
namespace network {
absl::StatusOr<Url> Url::Create(absl::string_view url_string) {
Url url;
if (!url.SetUrlPath(url_string)) {
return absl::InvalidArgumentError("bad url.");
}
return url;
}
bool Url::SetUrlPath(absl::string_view url_path) {
return ApplyUrlString(url_path);
}
std::string Url::GetUrlPath() const {
return scheme_ + "://" + host_ + GetPortString() + path_ + GetQueryString() +
GetFragmentString();
}
absl::string_view Url::GetScheme() const { return scheme_; }
absl::string_view Url::GetHostName() const { return host_; }
absl::string_view Url::GetPath() const { return path_; }
uint16_t Url::GetPort() const { return port_; }
absl::string_view Url::GetFragment() const { return fragment_; }
bool Url::ApplyUrlString(absl::string_view url_string) {
// Refer to: https://www.rfc-editor.org/rfc/rfc3986#page-50
std::regex url_reg(
R"(^(([^:\/?#]+):)?(//([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)",
std::regex::extended);
std::smatch matches;
std::string url{url_string};
std::regex_search(url, matches, url_reg);
scheme_ = matches[2];
if (!(scheme_ == "http" || scheme_ == "https")) {
return false;
}
std::string authority = matches[4];
if (authority.empty()) {
return false;
}
size_t pos = authority.find(':');
if (pos != std::string::npos) {
host_ = authority.substr(0, pos);
port_ = std::stoi(authority.substr(pos + 1));
} else {
host_ = authority;
port_ = scheme_ == "http" ? 80 : 443;
}
path_ = matches[5];
if (path_ == "/") {
path_ = "";
}
query_parameters_.clear();
std::string query = matches[7];
if (!query.empty()) {
// split by &
size_t start = 0;
size_t end = 0;
while ((end = query.find('&', start)) != std::string::npos) {
std::string kv = query.substr(start, end - start);
start = end + 1;
size_t eq_pos = kv.find('=');
if (eq_pos <= 0 || eq_pos == std::string::npos) {
continue;
}
query_parameters_.push_back(
{UrlDecode(kv.substr(0, eq_pos)), UrlDecode(kv.substr(eq_pos + 1))});
}
if (start < query.size()) {
size_t eq_pos = query.find('=', start);
if (eq_pos > start && eq_pos < query.size() - 1) {
query_parameters_.push_back(
{UrlDecode(query.substr(start, eq_pos - start)),
UrlDecode(query.substr(eq_pos + 1))});
}
}
}
fragment_ = matches[9];
return true;
}
void Url::AddQueryParameter(absl::string_view query, absl::string_view value) {
query_parameters_.push_back({absl::StrCat(query), absl::StrCat(value)});
}
void Url::RemoveQueryParameter(absl::string_view query) {
auto it = query_parameters_.begin();
while (it != query_parameters_.end()) {
if (it->first == query) {
it = query_parameters_.erase(it);
} else {
++it;
}
}
}
std::vector<std::string> Url::GetQueryValues(absl::string_view query) const {
std::vector<std::string> values;
auto it = query_parameters_.begin();
while (it != query_parameters_.end()) {
if (it->first == query) {
values.push_back(it->second);
}
++it;
}
return values;
}
const Url::QueryParameters& Url::GetAllQueryStrings() const {
return query_parameters_;
}
std::string Url::GetQueryString() const {
if (query_parameters_.empty()) {
return "";
}
std::string query = "";
auto it = query_parameters_.begin();
bool first = true;
while (it != query_parameters_.end()) {
if (first) {
query += "?";
first = false;
} else {
query += "&";
}
query += UrlEncode(it->first) + "=" + UrlEncode(it->second);
it++;
}
return query;
}
std::string Url::GetPortString() const {
if ((scheme_ == "http" && port_ == 80) ||
(scheme_ == "https" && port_ == 443)) {
return "";
}
return absl::StrCat(":", port_);
}
std::string Url::GetFragmentString() const {
if (fragment_.empty()) {
return "";
}
return "#" + fragment_;
}
std::ostream& operator<<(std::ostream& os, const Url& url) {
os << url.GetUrlPath();
return os;
}
bool operator==(const Url& url1, const Url& url2) {
if (url1.GetScheme() != url2.GetScheme()) {
return false;
}
if (url1.GetHostName() != url2.GetHostName()) {
return false;
}
if (url1.GetPort() != url2.GetPort()) {
return false;
}
if (url1.GetPath() != url2.GetPath()) {
return false;
}
auto queries1 = url1.GetAllQueryStrings();
auto queries2 = url2.GetAllQueryStrings();
if (queries1.size() != queries2.size()) {
return false;
}
std::vector<bool> state;
state.reserve(queries1.size());
for (int i = 0; i < queries1.size(); ++i) {
state.push_back(false);
}
for (int i = 0; i < queries1.size(); ++i) {
bool found = false;
for (int j = 0; j < queries2.size(); ++j) {
if (queries1[i].first == queries2[j].first &&
queries1[i].second == queries2[j].second) {
if (state[j]) {
return false;
}
state[j] = true;
found = true;
break;
}
}
if (!found) {
return false;
}
}
if (url1.GetFragment() != url2.GetFragment()) {
return false;
}
return true;
}
} // namespace network
} // namespace nearby
} // namespace location
+84
View File
@@ -0,0 +1,84 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_NETWORK_URL_H_
#define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_URL_H_
#include <iostream>
#include <ostream>
#include <string>
#include <utility>
#include <vector>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
namespace network {
class Url {
public:
using QueryParameters = std::vector<std::pair<std::string, std::string>>;
Url() = default;
~Url() = default;
Url(const Url&) = default;
Url& operator=(const Url&) = default;
Url(Url&&) = default;
Url& operator=(Url&&) = default;
static absl::StatusOr<Url> Create(absl::string_view url_string);
bool SetUrlPath(absl::string_view url_path);
std::string GetUrlPath() const;
absl::string_view GetScheme() const;
absl::string_view GetHostName() const;
absl::string_view GetPath() const;
uint16_t GetPort() const;
absl::string_view GetFragment() const;
void AddQueryParameter(absl::string_view query, absl::string_view value);
void RemoveQueryParameter(absl::string_view query);
std::vector<std::string> GetQueryValues(absl::string_view query) const;
const QueryParameters& GetAllQueryStrings() const;
private:
bool ApplyUrlString(absl::string_view url_string);
std::string GetQueryString() const;
std::string GetPortString() const;
std::string GetFragmentString() const;
// The absolute requested URL encoded in ASCII per the rules of RFC-2396.
std::string scheme_;
std::string host_;
uint16_t port_;
std::string path_;
std::string fragment_;
// Query strings of the request, no URL encode
QueryParameters query_parameters_;
};
std::ostream& operator<<(std::ostream& os, const Url& url);
bool operator==(const Url& url1, const Url& url2);
} // namespace network
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_NETWORK_URL_H_
+159
View File
@@ -0,0 +1,159 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/network/url.h"
#include <sstream>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
namespace location {
namespace nearby {
namespace network {
namespace {
TEST(Url, TestCreateUrl) {
auto url = Url::Create("http://www.google.com");
ASSERT_TRUE(url.ok());
EXPECT_EQ(url->GetScheme(), "http");
EXPECT_EQ(url->GetPort(), 80);
EXPECT_EQ(url->GetHostName(), "www.google.com");
url = Url::Create("https://www.google.com");
ASSERT_TRUE(url.ok());
EXPECT_EQ(url->GetScheme(), "https");
EXPECT_EQ(url->GetPort(), 443);
url = Url::Create("https://www.google.com:8443");
ASSERT_TRUE(url.ok());
EXPECT_EQ(url->GetPort(), 8443);
EXPECT_EQ(url->GetUrlPath(), "https://www.google.com:8443");
}
TEST(Url, TestUrlWithPath) {
auto url = Url::Create("http://www.google.com/users/user/1234");
ASSERT_TRUE(url.ok());
EXPECT_EQ(url->GetPath(), "/users/user/1234");
}
TEST(Url, TestUrlWithQuery) {
auto url = Url::Create("http://www.google.com/user?name=google&age=45");
ASSERT_TRUE(url.ok());
auto query_values = url->GetQueryValues("name");
EXPECT_THAT(query_values, testing::SizeIs(1));
EXPECT_EQ(query_values[0], "google");
}
TEST(Url, TestUrlWithOneQuery) {
auto url = Url::Create("http://www.google.com/user?name=google&");
ASSERT_TRUE(url.ok());
auto query_values = url->GetQueryValues("name");
EXPECT_EQ(1u, query_values.size());
EXPECT_EQ(query_values[0], "google");
}
TEST(Url, TestUrlWithFragment) {
auto url =
Url::Create("http://www.google.com/user?name=google&pos=mtv#hello");
ASSERT_TRUE(url.ok());
auto query_values = url->GetQueryValues("pos");
EXPECT_EQ(1u, query_values.size());
EXPECT_EQ(query_values[0], "mtv");
EXPECT_EQ(url->GetUrlPath(),
"http://www.google.com/user?name=google&pos=mtv#hello");
url->RemoveQueryParameter("pos");
EXPECT_EQ(0u, url->GetQueryValues("pos").size());
}
TEST(Url, TestGetUrl) {
auto url = Url::Create("http://www.google.com/user?name=google&pos=mtv");
ASSERT_TRUE(url.ok());
EXPECT_EQ(url->GetUrlPath(),
"http://www.google.com/user?name=google&pos=mtv");
}
TEST(Url, TestAddQueryString) {
auto url = Url::Create("http://www.google.com/user?name=google&pos=mtv");
ASSERT_TRUE(url.ok());
url->AddQueryParameter("test", "good");
auto new_url = Url::Create(url->GetUrlPath());
ASSERT_TRUE(new_url.ok());
auto query_values = new_url->GetQueryValues("test");
EXPECT_EQ(1u, query_values.size());
EXPECT_EQ(query_values[0], "good");
}
TEST(Url, TestAddQueryStringWithEncode) {
auto url = Url::Create("http://www.google.com");
ASSERT_TRUE(url.ok());
url->AddQueryParameter("test", "good & bad");
EXPECT_EQ(url->GetUrlPath(), "http://www.google.com?test=good%20%26%20bad");
auto new_url = Url::Create(url->GetUrlPath());
ASSERT_TRUE(new_url.ok());
auto query_values = new_url->GetQueryValues("test");
EXPECT_EQ(1u, query_values.size());
EXPECT_EQ(query_values[0], "good & bad");
}
TEST(Url, TestInvalidUrl) {
auto url = Url::Create("http:/www.google.com");
ASSERT_FALSE(url.ok());
url = Url::Create("ftp://www.google.com");
ASSERT_FALSE(url.ok());
url = Url::Create("::::hjskoiskjk");
ASSERT_FALSE(url.ok());
}
TEST(Url, TestStreamOutput) {
std::ostringstream stream;
auto url = Url::Create("https://www.google.com");
ASSERT_TRUE(url.ok());
stream << url.value();
EXPECT_EQ(stream.str(), "https://www.google.com");
}
TEST(Url, TestCompareUrl) {
auto url1 = Url::Create("https://www.google.com");
auto url2 = Url::Create("https://www.google.com/");
ASSERT_TRUE(url1.ok());
ASSERT_TRUE(url2.ok());
ASSERT_EQ(url1, url2);
url1 = Url::Create("https://www.google.com/home?name=test&age=38");
ASSERT_NE(url1, url2);
url2 = Url::Create("https://www.google.com/home?age=38&name=test");
ASSERT_EQ(url1, url2);
url2 = Url::Create("https://www.google.com/home?age=38&name=test&grade=5");
ASSERT_NE(url1, url2);
url2 = Url::Create("https://www.google.com/home?age=38&name=test#fragment");
ASSERT_NE(url1, url2);
url2 = Url::Create("https://www.google.com/home?age1=38&name1=test");
ASSERT_NE(url1, url2);
url2 = Url::Create("http://www.google.com/home?age1=38&name1=test");
ASSERT_NE(url1, url2);
url2 = Url::Create("https://www.google1.com/home?age1=38&name1=test");
ASSERT_NE(url1, url2);
url2 = Url::Create("https://www.google.com:8433/home?age=38&name=test");
ASSERT_NE(url1, url2);
url2 = Url::Create("https://www.google.com/home?age=38&age=38");
ASSERT_NE(url2, url1);
url2 = Url::Create("https://www.google.com/home?age=38&name=test&kk&=888");
ASSERT_EQ(url1, url2);
}
} // namespace
} // namespace network
} // namespace nearby
} // namespace location
+92
View File
@@ -0,0 +1,92 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/network/utils.h"
#include <cctype>
#include <iomanip>
#include <ios>
#include <sstream>
#include <string>
namespace location {
namespace nearby {
namespace network {
// Encodes string to URL-encoded string.
//
// If a character c is a decimal digit, an uppercase or lowercase letter, or in
// [-_.!~*'()] then nothing is done; otherwise c is encoded as %XX where XX is
// the hex value of the character c.
std::string UrlEncode(absl::string_view str) {
std::ostringstream encoded_string_stream;
encoded_string_stream.fill(0);
encoded_string_stream << std::hex;
auto it = str.begin();
while (it != str.end()) {
char ch = (*it);
if (std::isalnum(ch) || ch == '-' || ch == '_' || ch == '.' || ch == '!' ||
ch == '~' || ch == '*' || ch == '\'' || ch == '(' || ch == ')') {
encoded_string_stream << ch;
} else {
encoded_string_stream << std::uppercase;
encoded_string_stream << '%' << std::setw(2) << (ch & 0xFF);
encoded_string_stream << std::nouppercase;
}
++it;
}
return encoded_string_stream.str();
}
// Decodes URL string to normal string.
//
// Does the reverse operation comparing to UrlEncode.
// More details can refer to https://www.ietf.org/rfc/rfc2396.txt
std::string UrlDecode(absl::string_view url_string) {
std::ostringstream decoded_string_stream;
decoded_string_stream.fill(0);
decoded_string_stream << std::hex;
auto it = url_string.begin();
while (it != url_string.end()) {
char ch = (*it);
if (ch == '%') {
if (it + 1 != url_string.end() && it + 2 != url_string.end()) {
char chh = *(it + 1);
char chl = *(it + 2);
ch = (chh >= '0' && chh <= '9' ? chh - '0'
: std::tolower(chh) - 'a' + 10)
<< 4 |
(chl >= '0' && chl <= '9' ? chl - '0'
: std::tolower(chl) - 'a' + 10);
decoded_string_stream << ch;
it += 3;
continue;
}
} else {
decoded_string_stream << ch;
}
++it;
}
return decoded_string_stream.str();
}
} // namespace network
} // namespace nearby
} // namespace location
+45
View File
@@ -0,0 +1,45 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_NETWORK_UTILS_H_
#define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_UTILS_H_
#include <string>
#include "absl/strings/string_view.h"
#include "internal/network/url.h"
namespace location {
namespace nearby {
namespace network {
// Encodes string to URL-encoded format. URLs can only be sent over the Internet
// using the ASCII character-set. This method converts characters into a format
// that can be transmitted over the Internet.
//
// @param str The string to be encoded.
// @return Encoded URL string from input.
std::string UrlEncode(absl::string_view str);
// Decodes URL string to normal string.
//
// @param url_string URL string to be decoded.
// @return Decoded string.
std::string UrlDecode(absl::string_view url_string);
} // namespace network
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_NETWORK_UTILS_H_
+48
View File
@@ -0,0 +1,48 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/network/utils.h"
#include <string>
#include "gtest/gtest.h"
namespace location {
namespace nearby {
namespace network {
namespace {
TEST(UrlEncode, TestEncode) {
EXPECT_EQ(UrlEncode("abc12&()*t"), "abc12%26()*t");
}
TEST(UrlDecode, TestDecode) {
EXPECT_EQ(UrlDecode("abc12%26()*t"), "abc12&()*t");
}
TEST(UrlDecode, TestDecodeMatch) {
std::string encode =
UrlEncode("fsfs 1892427891$^%$*#$@ZDRIYIUHiheiuah bfd~+_()[]\\");
std::string decode = UrlDecode(encode);
EXPECT_EQ(decode, "fsfs 1892427891$^%$*#$@ZDRIYIUHiheiuah bfd~+_()[]\\");
EXPECT_EQ(encode,
"fsfs%201892427891%24%5E%25%24*%23%24%40ZDRIYIUHiheiuah%20bfd~%2B_("
")%5B%5D%5C%7C%C2%A9");
}
} // namespace
} // namespace network
} // namespace nearby
} // namespace location
+4 -2
View File
@@ -100,7 +100,9 @@ cc_library(
visibility = [
"//connections:__subpackages__",
"//fastpair:__subpackages__",
"//internal:__pkg__",
"//internal/crypto:__subpackages__",
"//internal/network:__subpackages__",
"//internal/platform:__subpackages__",
"//internal/proto/analytics:__subpackages__",
"//location/nearby/analytics/cpp:__subpackages__",
@@ -393,11 +395,11 @@ cc_library(
"//presence:__subpackages__",
],
deps = [
":base",
":cancellation_flag",
":logging",
":types",
":uuid",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"@com_google_absl//absl/container:flat_hash_map",
+9
View File
@@ -59,6 +59,7 @@ cc_library(
"bluetooth_classic.h",
"credential_callbacks.h",
"credential_storage.h",
"http_loader.h",
"server_sync.h",
"wifi.h",
"wifi_direct.h",
@@ -74,6 +75,8 @@ cc_library(
defines = ["NO_WEBRTC"],
visibility = [
"//connections/implementation:__subpackages__",
"//internal:__pkg__",
"//internal/network:__subpackages__",
"//internal/platform:__pkg__",
"//internal/platform/implementation:__subpackages__",
"//presence:__pkg__",
@@ -88,6 +91,7 @@ cc_library(
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
],
@@ -101,15 +105,20 @@ cc_library(
defines = ["NO_WEBRTC"],
visibility = [
"//connections/implementation:__subpackages__",
"//fastpair:__subpackages__",
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//internal:__pkg__",
"//internal/network:__subpackages__",
"//internal/platform:__pkg__",
"//internal/platform/implementation:__subpackages__",
"//location/nearby/analytics/cpp:__subpackages__",
"//location/nearby/cpp/fastpair:__subpackages__",
],
deps = [
":comm",
":types",
"//internal/platform:base",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
],
)
@@ -15,6 +15,7 @@
#include "internal/platform/implementation/platform.h"
#include <string>
#include <memory>
#include "internal/platform/implementation/apple/atomic_boolean.h"
#include "internal/platform/implementation/apple/atomic_uint32.h"
@@ -170,6 +171,12 @@ std::unique_ptr<WifiDirectMedium> ImplementationPlatform::CreateWifiDirectMedium
std::unique_ptr<WebRtcMedium> ImplementationPlatform::CreateWebRtcMedium() { return nullptr; }
#endif
// TODO(b/261511669): Add implementation.
absl::StatusOr<WebResponse> ImplementationPlatform::SendRequest(
const WebRequest& request) {
return absl::UnimplementedError("");
}
} // namespace api
} // namespace nearby
} // namespace location
@@ -122,7 +122,9 @@ cc_library(
visibility = [
"//connections:__subpackages__",
"//fastpair:__subpackages__",
"//internal:__pkg__",
"//internal/analytics:__subpackages__",
"//internal/network:__subpackages__",
"//internal/platform:__subpackages__",
"//internal/proto/analytics:__subpackages__",
"//location/nearby/cpp/fastpair:__subpackages__",
@@ -140,7 +142,9 @@ cc_library(
"//internal/platform/implementation/shared:count_down_latch",
"//internal/platform/implementation/shared:file",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
],
@@ -21,7 +21,9 @@
#include "file/base/path.h"
#include "absl/memory/memory.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "internal/platform/implementation/atomic_boolean.h"
#include "internal/platform/implementation/atomic_reference.h"
@@ -205,6 +207,11 @@ std::unique_ptr<WebRtcMedium> ImplementationPlatform::CreateWebRtcMedium() {
}
#endif
absl::StatusOr<WebResponse> ImplementationPlatform::SendRequest(
const api::WebRequest& request) {
return absl::UnimplementedError("");
}
std::unique_ptr<Mutex> ImplementationPlatform::CreateMutex(Mutex::Mode mode) {
if (mode == Mutex::Mode::kRecursive)
return std::make_unique<g3::RecursiveMutex>();
@@ -0,0 +1,43 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_HTTP_LOADER_H_
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_HTTP_LOADER_H_
#include <map>
#include <string>
namespace location {
namespace nearby {
namespace api {
struct WebRequest {
std::string url;
std::string method;
std::multimap<std::string, std::string> headers;
std::string body;
};
struct WebResponse {
int status_code;
std::string status_text;
std::multimap<std::string, std::string> headers;
std::string body;
};
} // namespace api
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_HTTP_LOADER_H_
@@ -19,6 +19,7 @@
#include <memory>
#include <string>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/atomic_boolean.h"
#include "internal/platform/implementation/atomic_reference.h"
@@ -30,6 +31,7 @@
#include "internal/platform/implementation/count_down_latch.h"
#include "internal/platform/implementation/credential_storage.h"
#include "internal/platform/implementation/crypto.h"
#include "internal/platform/implementation/http_loader.h"
#include "internal/platform/implementation/input_file.h"
#include "internal/platform/implementation/log_message.h"
#include "internal/platform/implementation/mutex.h"
@@ -130,6 +132,15 @@ class ImplementationPlatform {
#ifndef NO_WEBRTC
static std::unique_ptr<WebRtcMedium> CreateWebRtcMedium();
#endif
// Gets HTTP response from remote server.
//
// @param request Webrequest
//
// @return returns absl::FailedPreconditionError if having platform error.
// return WebResponse if HTTP status code between 200 and 300.
// other cases will return absl Status in error.
static absl::StatusOr<WebResponse> SendRequest(const WebRequest& request);
};
} // namespace api
@@ -62,6 +62,7 @@ cc_library(
"executor.h",
"file.h",
"file_path.h",
"http_loader.h",
"mutex.h",
"scheduled_executor.h",
"server_sync.h",
@@ -84,6 +85,9 @@ cc_library(
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/types:optional",
],
@@ -128,6 +132,7 @@ cc_library(
"executor.cc",
"file.cc",
"file_path.cc",
"http_loader.cc",
"platform.cc",
"scheduled_executor.cc",
"submittable_executor.cc",
@@ -157,6 +162,7 @@ cc_library(
":types",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:logging",
"//internal/platform:types",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:types",
@@ -164,6 +170,8 @@ cc_library(
"//internal/platform/implementation/shared:file",
"//internal/platform/implementation/windows/generated:types",
"//internal/platform/implementation/windows/json:types",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
],
@@ -199,6 +207,7 @@ cc_test(
"crypto_test.cc",
"executor_test.cc",
"file_path_test.cc",
"http_loader_test.cc",
"scheduled_executor_test.cc",
"submittable_executor_test.cc",
"thread_pool_test.cc",
@@ -216,6 +225,8 @@ cc_test(
"//internal/platform/implementation/windows",
"//internal/platform/implementation/windows/generated:types",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
@@ -16,6 +16,7 @@ licenses(["notice"])
cc_library(
name = "types",
linkopts = [
"wininet.lib",
"advapi32.lib",
"comdlg32.lib",
"gdi32.lib",
@@ -0,0 +1,413 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/windows/http_loader.h"
#include <iostream>
#include <string>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/ascii.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "internal/platform/logging.h"
namespace location {
namespace nearby {
namespace windows {
namespace {
constexpr DWORD kSchemaMaximumLength = 10;
constexpr DWORD kHostNameMaximumLength = 256;
using ::location::nearby::api::WebResponse;
} // namespace
absl::StatusOr<WebResponse> HttpLoader::GetResponse() {
absl::Status status;
status = ParseUrl();
if (!status.ok()) {
return status;
}
status = ConnectWebServer();
if (!status.ok()) {
return status;
}
// Sends request to web server.
status = SendRequest();
if (!status.ok()) {
return status;
}
// Processes response from web server
absl::StatusOr<WebResponse> result = ProcessResponse();
if (!result.ok()) {
return result;
}
DisconnectWebServer();
return result;
}
absl::StatusOr<int> HttpLoader::QueryStatusCode(HINTERNET file_handle) {
int result;
std::string status_code;
absl::Status status;
status = QueryResponseInfo(file_handle, HTTP_QUERY_STATUS_CODE, status_code);
if (!status.ok()) {
return status;
}
if (!absl::SimpleAtoi(
absl::string_view(status_code.data(), status_code.size() - 1),
&result)) {
return absl::InternalError("Failed to parse status code.");
}
if (result < 0) {
return absl::InternalError("Invalid status code.");
}
return result;
}
absl::StatusOr<std::string> HttpLoader::QueryStatusText(
HINTERNET request_handle) {
absl::Status status;
std::string status_text;
status =
QueryResponseInfo(request_handle, HTTP_QUERY_STATUS_TEXT, status_text);
if (!status.ok()) {
return status;
}
// status_text is ended with char '\0', remove it in returned result.
return status_text.substr(0, status_text.size() - 1);
}
absl::StatusOr<std::multimap<std::string, std::string>>
HttpLoader::QueryResponseHeaders(HINTERNET request_handle) {
absl::Status status;
std::string headers_string;
status = QueryResponseInfo(request_handle, HTTP_QUERY_RAW_HEADERS_CRLF,
headers_string);
if (!status.ok()) {
return status;
}
std::multimap<std::string, std::string> headers;
// Parse headers in response
size_t start = 0;
size_t pos = 0;
while ((pos = headers_string.find("\r\n", start)) != std::string::npos) {
std::string header = headers_string.substr(start, pos - start);
// Get key and value in header
size_t split_pos = 0;
if ((split_pos = header.find(": ")) != std::string::npos) {
std::string key = header.substr(0, split_pos);
std::string value = header.substr(split_pos + 2);
headers.emplace(key, value);
}
start = pos + 2;
}
return headers;
}
absl::Status HttpLoader::QueryResponseInfo(HINTERNET request_handle,
DWORD info_level,
std::string& info) {
DWORD buffer_size = 0;
BOOL query_result = HttpQueryInfoA(request_handle, info_level, nullptr,
&buffer_size, nullptr);
if (query_result) {
return absl::OkStatus();
}
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
info.resize(buffer_size);
query_result = HttpQueryInfoA(request_handle, info_level, info.data(),
&buffer_size, nullptr);
if (query_result) {
return absl::OkStatus();
}
}
return absl::InvalidArgumentError("Failed to query HTTP information.");
}
absl::Status HttpLoader::ParseUrl() {
const std::string& url = request_.url;
URL_COMPONENTSA url_components;
char schema[kSchemaMaximumLength];
char host_name[kHostNameMaximumLength];
std::string url_path;
url_path.resize(url.size());
memset(&url_components, 0, sizeof(URL_COMPONENTSA));
url_components.dwStructSize = sizeof(URL_COMPONENTSA);
url_components.lpszScheme = schema;
url_components.dwSchemeLength = kSchemaMaximumLength;
url_components.lpszHostName = host_name;
url_components.dwHostNameLength = kHostNameMaximumLength;
url_components.lpszUrlPath = url_path.data();
url_components.dwUrlPathLength = url.size();
if (!InternetCrackUrlA(url.data(), url.size(), 0, &url_components)) {
return absl::InvalidArgumentError("Invalid URL.");
}
schema_.assign(url_components.lpszScheme, url_components.dwSchemeLength);
if (!(schema_ == "http" || schema_ == "https")) {
return absl::InvalidArgumentError("URL supports HTTP and HTTPS only.");
}
if (schema_ == "https") {
is_secure_ = true;
}
host_.assign(url_components.lpszHostName, url_components.dwHostNameLength);
path_.assign(url_components.lpszUrlPath, url_components.dwUrlPathLength);
port_ = url_components.nPort;
return absl::OkStatus();
}
absl::Status HttpLoader::ConnectWebServer() {
internet_handle_ = InternetOpenA("Mozilla/5.0", /*Agent*/
INTERNET_OPEN_TYPE_PRECONFIG, /*Access Type*/
nullptr, /*Proxy*/
nullptr, /*Proxy bypass*/
0); /*Flags*/
if (internet_handle_ == nullptr) {
NEARBY_LOGS(ERROR) << "Failed to open internet with error "
<< GetLastError() << ".";
return absl::FailedPreconditionError(absl::StrCat(GetLastError()));
}
connect_handle_ = InternetConnectA(internet_handle_, /*Internet*/
host_.c_str(), /*Server name*/
port_, /*Port*/
nullptr, /*User name*/
nullptr, /*Password*/
INTERNET_SERVICE_HTTP, /*Service*/
0, /*Flags*/
0); /*Context*/
if (connect_handle_ == nullptr) {
NEARBY_LOGS(ERROR) << "Failed to connect remote web server with error "
<< GetLastError() << ".";
InternetCloseHandle(internet_handle_);
return absl::FailedPreconditionError(absl::StrCat(GetLastError()));
}
return absl::OkStatus();
}
absl::Status HttpLoader::SendRequest() {
DWORD flags = INTERNET_FLAG_NO_AUTO_REDIRECT;
if (is_secure_) {
flags |= INTERNET_FLAG_SECURE;
}
request_handle_ =
HttpOpenRequestA(connect_handle_, request_.method.c_str(), /*Method*/
path_.c_str(), /*Path*/
nullptr, /*HTTP version*/
nullptr, /*Referrer*/
nullptr, /*Accept types*/
flags, /*Internet options*/
0);
if (request_handle_ == nullptr) {
NEARBY_LOGS(ERROR)
<< "Failed to open request to remote web server with error "
<< GetLastError() << ".";
InternetCloseHandle(internet_handle_);
InternetCloseHandle(connect_handle_);
return absl::FailedPreconditionError(absl::StrCat(GetLastError()));
}
// Prepare headers
LPCSTR headers_ptr = nullptr;
DWORD headers_size = 0;
std::string request_headers;
for (const auto& header : request_.headers) {
if (header.second.empty()) {
continue;
}
request_headers.append(header.first + ": " + header.second + "\r\n");
}
if (!request_headers.empty()) {
headers_ptr = request_headers.data();
headers_size = request_headers.size();
}
LPVOID data_ptr = nullptr;
DWORD data_size = 0;
// Prepare request data
if (!request_.body.empty()) {
data_ptr = (LPVOID)(request_.body.data());
data_size = request_.body.size();
}
BOOL result = HttpSendRequestA(request_handle_, /*Request*/
headers_ptr, /*Headers*/
headers_size, /*Header size*/
data_ptr, /*Data*/
data_size); /*Data size*/
if (result == FALSE) {
NEARBY_LOGS(ERROR)
<< "Failed to send request to remote web server with error "
<< GetLastError() << ".";
InternetCloseHandle(request_handle_);
InternetCloseHandle(connect_handle_);
InternetCloseHandle(internet_handle_);
return absl::FailedPreconditionError(absl::StrCat(GetLastError()));
}
return absl::OkStatus();
}
absl::StatusOr<WebResponse> HttpLoader::ProcessResponse() {
absl::Status status;
WebResponse web_response;
auto status_code = QueryStatusCode(request_handle_);
if (!status_code.ok()) {
return absl::InternalError("Failed to read HTTP status");
}
web_response.status_code = status_code.value();
auto status_text = QueryStatusText(request_handle_);
if (!status_text.ok()) {
return absl::InternalError("Failed to read HTTP status");
}
web_response.status_text = status_text.value();
auto headers = QueryResponseHeaders(request_handle_);
if (!headers.ok()) {
headers.status();
}
web_response.headers = *headers;
// Get response data
char buffer[kReceiveBufferSize];
while (true) {
DWORD read_size;
BOOL read_result = InternetReadFile(request_handle_, buffer,
kReceiveBufferSize, &read_size);
if (read_result) {
if (read_size == 0) {
break;
} else {
// Append data to response
web_response.body.append(buffer, read_size);
}
} else {
NEARBY_LOGS(ERROR)
<< "Failed to read response from remote web server with error "
<< GetLastError() << ".";
InternetCloseHandle(request_handle_);
InternetCloseHandle(connect_handle_);
InternetCloseHandle(internet_handle_);
return absl::FailedPreconditionError(absl::StrCat(GetLastError()));
}
}
status = HTTPCodeToStatus(web_response.status_code, web_response.status_text);
if (!status.ok()) {
return status;
}
return web_response;
}
void HttpLoader::DisconnectWebServer() {
if (request_handle_ != nullptr) {
InternetCloseHandle(request_handle_);
request_handle_ = nullptr;
}
if (connect_handle_ != nullptr) {
InternetCloseHandle(connect_handle_);
connect_handle_ = nullptr;
}
if (internet_handle_ != nullptr) {
InternetCloseHandle(internet_handle_);
internet_handle_ = nullptr;
}
}
absl::Status HttpLoader::HTTPCodeToStatus(int status_code,
absl::string_view status_message) {
switch (status_code) {
case 400:
return absl::InvalidArgumentError(status_message);
case 401:
return absl::UnauthenticatedError(status_message);
case 403:
return absl::PermissionDeniedError(status_message);
case 404:
return absl::NotFoundError(status_message);
case 409:
return absl::AbortedError(status_message);
case 416:
return absl::OutOfRangeError(status_message);
case 429:
return absl::ResourceExhaustedError(status_message);
case 499:
return absl::CancelledError(status_message);
case 504:
return absl::DeadlineExceededError(status_message);
case 501:
return absl::UnimplementedError(status_message);
case 503:
return absl::UnavailableError(status_message);
default:
break;
}
if (status_code >= 200 && status_code < 300) {
return absl::OkStatus();
} else if (status_code >= 400 && status_code < 500) {
return absl::FailedPreconditionError(status_message);
} else if (status_code >= 500 && status_code < 600) {
return absl::InternalError(status_message);
}
return absl::UnknownError(status_message);
}
} // namespace windows
} // namespace nearby
} // namespace location
@@ -0,0 +1,87 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_HTTP_LOADER_H_
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_HTTP_LOADER_H_
#include <windows.h> // NOLINT
#include <wininet.h>
#include <string>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/http_loader.h"
namespace location {
namespace nearby {
namespace windows {
// HttpLoader is used to get HTTP response from remote server.
//
// HttpLoader gets HTTP request information from caller, and calling Windows
// WinInet APIs to get HTTP response. The platform handles HTTP/HTTPS sessions.
class HttpLoader {
public:
explicit HttpLoader(const location::nearby::api::WebRequest& request)
: request_(request) {}
~HttpLoader() = default;
absl::StatusOr<location::nearby::api::WebResponse> GetResponse();
private:
// Defines the buffer size. It is used to init a buffer for receiving HTTP
// response. The unit is byte.
static constexpr int kReceiveBufferSize = 8 * 1024;
absl::Status ConnectWebServer();
absl::Status SendRequest();
absl::StatusOr<location::nearby::api::WebResponse> ProcessResponse();
void DisconnectWebServer();
absl::StatusOr<int> QueryStatusCode(HINTERNET file_handle);
absl::StatusOr<std::string> QueryStatusText(HINTERNET request_handle);
absl::StatusOr<std::multimap<std::string, std::string>> QueryResponseHeaders(
HINTERNET request_handle);
absl::Status QueryResponseInfo(HINTERNET request_handle, DWORD info_level,
std::string& info);
absl::Status ParseUrl();
// Converts HTTP status code to absl Status.
//
// @param status_code HTTP status code, such 200, 404 etc.
// @param status_message short description of the status code.
// @return converted absl status.
absl::Status HTTPCodeToStatus(int status_code,
absl::string_view status_message);
location::nearby::api::WebRequest request_;
std::string host_;
std::string path_;
std::string schema_;
bool is_secure_ = false;
int port_ = 80;
HINTERNET internet_handle_ = nullptr;
HINTERNET connect_handle_ = nullptr;
HINTERNET request_handle_ = nullptr;
};
} // namespace windows
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_HTTP_LOADER_H_
@@ -0,0 +1,53 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/windows/http_loader.h"
#include <string>
#include "gtest/gtest.h"
namespace location {
namespace nearby {
namespace windows {
namespace {
using ::location::nearby::api::WebRequest;
TEST(HttpLoader, DISABLED_TestGetUrl) {
WebRequest request;
request.url = "https://www.google.com?id=456#fragment";
request.method = "GET";
auto response = HttpLoader(request).GetResponse();
ASSERT_TRUE(response.ok());
EXPECT_EQ(response->status_code, 200);
}
TEST(HttpLoader, DISABLED_TestGetNotExistingUrl) {
WebRequest request;
request.url = "https://www.abcdefgabcdefg.com";
request.method = "GET";
EXPECT_FALSE(HttpLoader(request).GetResponse().ok());
}
TEST(HttpLoader, DISABLED_TestInvalidUrl) {
WebRequest request;
request.url = "https:/www.abcdefgabcdefg.com/name?id=456";
request.method = "GET";
EXPECT_FALSE(HttpLoader(request).GetResponse().ok());
}
} // namespace
} // namespace windows
} // namespace nearby
} // namespace location
@@ -33,6 +33,9 @@
#include <sstream>
#include <string>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/http_loader.h"
#include "internal/platform/implementation/shared/count_down_latch.h"
#include "internal/platform/implementation/windows/atomic_boolean.h"
#include "internal/platform/implementation/windows/atomic_reference.h"
@@ -45,6 +48,7 @@
#include "internal/platform/implementation/windows/file.h"
#include "internal/platform/implementation/windows/file_path.h"
#include "internal/platform/implementation/windows/future.h"
#include "internal/platform/implementation/windows/http_loader.h"
#include "internal/platform/implementation/windows/listenable_future.h"
#include "internal/platform/implementation/windows/log_message.h"
#include "internal/platform/implementation/windows/mutex.h"
@@ -298,6 +302,12 @@ std::unique_ptr<WebRtcMedium> ImplementationPlatform::CreateWebRtcMedium() {
return absl::make_unique<windows::WebRtcMedium>();
}
absl::StatusOr<WebResponse> ImplementationPlatform::SendRequest(
const WebRequest& request) {
windows::HttpLoader http_loader{request};
return http_loader.GetResponse();
}
} // namespace api
} // namespace nearby
} // namespace location