| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "services/network/public/cpp/cors/origin_access_list.h" |
| |
| #include "services/network/public/mojom/cors_origin_pattern.mojom.h" |
| |
| namespace network { |
| |
| namespace cors { |
| |
| OriginAccessList::OriginAccessList() = default; |
| OriginAccessList::~OriginAccessList() = default; |
| |
| void OriginAccessList::SetAllowListForOrigin( |
| const url::Origin& source_origin, |
| const std::vector<CorsOriginPatternPtr>& patterns) { |
| SetForOrigin(source_origin, patterns, &allow_list_); |
| } |
| |
| void OriginAccessList::AddAllowListEntryForOrigin( |
| const url::Origin& source_origin, |
| const std::string& protocol, |
| const std::string& domain, |
| const mojom::CorsOriginAccessMatchMode mode, |
| const mojom::CorsOriginAccessMatchPriority priority) { |
| AddForOrigin(source_origin, |
| mojom::CorsOriginPattern::New(protocol, domain, mode, priority), |
| &allow_list_); |
| } |
| |
| void OriginAccessList::ClearAllowListForOrigin( |
| const url::Origin& source_origin) { |
| SetForOrigin(source_origin, std::vector<mojom::CorsOriginPatternPtr>(), |
| &allow_list_); |
| } |
| |
| void OriginAccessList::ClearAllowList() { |
| allow_list_.clear(); |
| } |
| |
| void OriginAccessList::SetBlockListForOrigin( |
| const url::Origin& source_origin, |
| const std::vector<CorsOriginPatternPtr>& patterns) { |
| SetForOrigin(source_origin, patterns, &block_list_); |
| } |
| |
| void OriginAccessList::AddBlockListEntryForOrigin( |
| const url::Origin& source_origin, |
| const std::string& protocol, |
| const std::string& domain, |
| const mojom::CorsOriginAccessMatchMode mode, |
| const mojom::CorsOriginAccessMatchPriority priority) { |
| AddForOrigin(source_origin, |
| mojom::CorsOriginPattern::New(protocol, domain, mode, priority), |
| &block_list_); |
| } |
| |
| void OriginAccessList::ClearBlockListForOrigin( |
| const url::Origin& source_origin) { |
| SetForOrigin(source_origin, std::vector<mojom::CorsOriginPatternPtr>(), |
| &block_list_); |
| } |
| |
| void OriginAccessList::ClearBlockList() { |
| block_list_.clear(); |
| } |
| |
| OriginAccessList::AccessState OriginAccessList::CheckAccessState( |
| const url::Origin& source_origin, |
| const GURL& destination) const { |
| if (source_origin.opaque()) |
| return AccessState::kBlocked; |
| |
| std::string source = source_origin.Serialize(); |
| url::Origin destination_origin = url::Origin::Create(destination); |
| network::mojom::CorsOriginAccessMatchPriority allow_list_priority = |
| GetHighestPriorityOfRuleForOrigin(source, destination_origin, |
| allow_list_); |
| network::mojom::CorsOriginAccessMatchPriority block_list_priority = |
| GetHighestPriorityOfRuleForOrigin(source, destination_origin, |
| block_list_); |
| |
| if (allow_list_priority == |
| network::mojom::CorsOriginAccessMatchPriority::kNoMatchingOrigin) { |
| return block_list_priority == |
| network::mojom::CorsOriginAccessMatchPriority:: |
| kNoMatchingOrigin |
| ? AccessState::kNotListed |
| : AccessState::kBlocked; |
| } |
| |
| if (block_list_priority == |
| network::mojom::CorsOriginAccessMatchPriority::kNoMatchingOrigin) |
| return AccessState::kAllowed; |
| |
| return (allow_list_priority > block_list_priority) ? AccessState::kAllowed |
| : AccessState::kBlocked; |
| } |
| |
| std::vector<mojo::StructPtr<mojom::CorsOriginAccessPatterns>> |
| OriginAccessList::CreateCorsOriginAccessPatternsList() const { |
| std::set<std::string> origins; |
| for (const auto& allow_map : allow_list_) |
| origins.insert(allow_map.first); |
| for (const auto& block_map : block_list_) |
| origins.insert(block_map.first); |
| |
| std::vector<mojom::CorsOriginAccessPatternsPtr> access_patterns; |
| for (const auto& origin : origins) { |
| std::vector<mojom::CorsOriginPatternPtr> allow_patterns; |
| const auto& allow_entries = allow_list_.find(origin); |
| if (allow_entries != allow_list_.end()) { |
| for (const auto& pattern : allow_entries->second) |
| allow_patterns.push_back(pattern.CreateCorsOriginPattern()); |
| } |
| std::vector<mojom::CorsOriginPatternPtr> block_patterns; |
| const auto& block_entries = block_list_.find(origin); |
| if (block_entries != block_list_.end()) { |
| for (const auto& pattern : block_entries->second) |
| block_patterns.push_back(pattern.CreateCorsOriginPattern()); |
| } |
| access_patterns.push_back(mojom::CorsOriginAccessPatterns::New( |
| origin, std::move(allow_patterns), std::move(block_patterns))); |
| } |
| return access_patterns; |
| } |
| |
| // static |
| void OriginAccessList::SetForOrigin( |
| const url::Origin& source_origin, |
| const std::vector<CorsOriginPatternPtr>& patterns, |
| PatternMap* map) { |
| DCHECK(map); |
| DCHECK(!source_origin.opaque()); |
| |
| std::string source = source_origin.Serialize(); |
| map->erase(source); |
| if (patterns.empty()) |
| return; |
| |
| Patterns& native_patterns = (*map)[source]; |
| for (const auto& pattern : patterns) { |
| native_patterns.push_back(OriginAccessEntry( |
| pattern->protocol, pattern->domain, pattern->mode, pattern->priority)); |
| } |
| } |
| |
| // static |
| void OriginAccessList::AddForOrigin(const url::Origin& source_origin, |
| const CorsOriginPatternPtr& pattern, |
| PatternMap* map) { |
| DCHECK(map); |
| DCHECK(!source_origin.opaque()); |
| |
| std::string source = source_origin.Serialize(); |
| (*map)[source].push_back(OriginAccessEntry(pattern->protocol, pattern->domain, |
| pattern->mode, pattern->priority)); |
| } |
| |
| // static |
| // TODO(nrpeter): Sort OriginAccessEntry entries on edit then we can return the |
| // first match which will be the top priority. |
| network::mojom::CorsOriginAccessMatchPriority |
| OriginAccessList::GetHighestPriorityOfRuleForOrigin( |
| const std::string& source, |
| const url::Origin& destination_origin, |
| const PatternMap& map) { |
| network::mojom::CorsOriginAccessMatchPriority highest_priority = |
| network::mojom::CorsOriginAccessMatchPriority::kNoMatchingOrigin; |
| auto patterns_for_origin_it = map.find(source); |
| if (patterns_for_origin_it == map.end()) |
| return highest_priority; |
| for (const auto& entry : patterns_for_origin_it->second) { |
| if (entry.MatchesOrigin(destination_origin) != |
| OriginAccessEntry::kDoesNotMatchOrigin) { |
| highest_priority = std::max(highest_priority, entry.priority()); |
| } |
| } |
| return highest_priority; |
| } |
| |
| } // namespace cors |
| |
| } // namespace network |