blob: 09dd29077a9e0adc9f11267716036479b39275d5 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/policy/test_support/test_server_helpers.h"
#include <algorithm>
#include <ranges>
#include <utility>
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "net/base/url_util.h"
#include "net/http/http_status_code.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "third_party/re2/src/re2/re2.h"
namespace policy {
using ::net::test_server::BasicHttpResponse;
using ::net::test_server::HttpRequest;
using ::net::test_server::HttpResponse;
namespace em = enterprise_management;
namespace {
// C++ does not offer a mechanism to check if a given status code is present in
// net::HttpStatusCode enum. To allow distinguishing standard HTTP status code
// from custom ones, we define this array that will contain all standard codes.
constexpr net::HttpStatusCode kStandardHttpStatusCodes[] = {
#define HTTP_STATUS_ENUM_VALUE(label, code, reason) net::HttpStatusCode(code),
#include "net/http/http_status_code_list.h"
#undef HTTP_STATUS_ENUM_VALUE
};
std::unique_ptr<HttpResponse> CreateHttpResponse(
net::HttpStatusCode code,
const std::string& content,
const std::string& content_type) {
auto response = std::make_unique<CustomHttpResponse>();
response->set_content_type(content_type);
response->set_code(code);
response->set_content(content);
return response;
}
} // namespace
void CustomHttpResponse::SendResponse(
base::WeakPtr<net::test_server::HttpResponseDelegate> delegate) {
std::string reason = "Custom";
// The implementation of the BasicHttpResponse::reason() calls
// net::GetHttpReasonPhrase, which requires status code to be a standard HTTP
// status code and crashes otherwise. Hence we avoid calling it if a custom
// HTTP code is used.
// TODO(crbug.com/40209048): Make GetHttpReasonPhrase support custom codes
// instead.
if (std::find(std::begin(kStandardHttpStatusCodes),
std::end(kStandardHttpStatusCodes),
code()) != std::end(kStandardHttpStatusCodes)) {
reason = BasicHttpResponse::reason();
}
delegate->SendHeadersContentAndFinish(code(), reason, BuildHeaders(),
content());
}
std::string KeyValueFromUrl(GURL url, const std::string& key) {
std::string value;
return net::GetValueForKeyInQuery(url, key, &value) ? value : std::string();
}
bool MeetsServerSideRequirements(GURL url) {
std::string device_id = KeyValueFromUrl(url, dm_protocol::kParamDeviceID);
return KeyValueFromUrl(url, dm_protocol::kParamDeviceType) ==
dm_protocol::kValueDeviceType &&
KeyValueFromUrl(url, dm_protocol::kParamAppType) ==
dm_protocol::kValueAppType &&
!device_id.empty() && device_id.size() <= 64;
}
bool GetTokenFromAuthorization(const HttpRequest& request,
const std::string& token_header_prefix,
std::string* out) {
auto authorization = request.headers.find(dm_protocol::kAuthHeader);
return authorization != request.headers.end() &&
re2::RE2::FullMatch(authorization->second,
token_header_prefix + "(.+)", out);
}
bool GetEnrollmentTokenFromRequest(const HttpRequest& request,
std::string* out) {
return GetTokenFromAuthorization(
request, dm_protocol::kEnrollmentTokenAuthHeaderPrefix, out);
}
bool GetDeviceTokenFromRequest(const HttpRequest& request, std::string* out) {
return GetTokenFromAuthorization(request,
dm_protocol::kDMTokenAuthHeaderPrefix, out);
}
bool GetGoogleLoginFromRequest(const net::test_server::HttpRequest& request,
std::string* out) {
return net::GetValueForKeyInQuery(request.GetURL(), "oauth_token", out) ||
GetTokenFromAuthorization(
request, dm_protocol::kServiceTokenAuthHeaderPrefix, out) ||
GetTokenFromAuthorization(request,
dm_protocol::kOAuthTokenHeaderPrefix, out);
}
bool GetProfileIdFromRequest(const net::test_server::HttpRequest& request,
std::string* out) {
std::string profile_id =
KeyValueFromUrl(request.GetURL(), dm_protocol::kParamProfileID);
if (profile_id.empty()) {
return false;
}
*out = profile_id;
return true;
}
std::unique_ptr<HttpResponse> CreateHttpResponse(
net::HttpStatusCode code,
const em::DeviceManagementResponse& proto_content) {
return CreateHttpResponse(code, proto_content.SerializeAsString(),
"application/x-protobuffer");
}
std::unique_ptr<HttpResponse> CreateHttpResponse(
net::HttpStatusCode code,
const std::string& text_content) {
return CreateHttpResponse(code, text_content, "text/plain");
}
} // namespace policy