blob: 6e063d5b18a217fae719c7121ddc9da7eb883829 [file] [log] [blame]
/*
* Copyright 2017 The Cobalt Authors. All Rights Reserved.
*
* 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
*
* http://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 COBALT_LOADER_CORS_PREFLIGHT_CACHE_H_
#define COBALT_LOADER_CORS_PREFLIGHT_CACHE_H_
#include <memory>
#include <queue>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
#include "base/containers/hash_tables.h"
#include "base/time/time.h"
#include "net/http/http_request_headers.h"
#include "net/url_request/url_fetcher.h"
#include "starboard/common/string.h"
#include "url/gurl.h"
namespace cobalt {
namespace loader {
// https://fetch.spec.whatwg.org/#concept-cache
class CORSPreflightCache : public base::RefCounted<CORSPreflightCache> {
public:
// An entry is appended at the end of every preflight to avoid same
// preflight request in the near future.
void AppendEntry(const std::string& url_str, const std::string& origin,
int max_age, bool has_credentials,
const std::vector<std::string>& methods_vec,
const std::vector<std::string>& headernames_vec);
// Check if there is a preflight cache match. This method does not include
// checking for CORS-safelisted method and request-header.
bool HaveEntry(const std::string& url_str, const std::string& origin,
bool credentials_mode_is_include,
const net::URLFetcher::RequestType& new_request_method,
const std::vector<std::string>& unsafe_headernames);
private:
// Case-insensitive comparator.
struct CaseInsensitiveCompare {
bool operator()(const std::string& lhs, const std::string& rhs) const {
return SbStringCompareNoCase(lhs.c_str(), rhs.c_str()) < 0;
}
};
// The spec wants a cache entry for every method and for every header which is
// a little unnecessarily expensive. We create an entry for each request and
// If there is an old entry in the new entry's place we simply push the old
// one out which potentially increases cache misses slightly but reduces
// memory cost. Chromium also takes this approach.
// The map's first key is entry's request url and second is entry's origin.
struct CORSPreflightCacheEntry
: public base::RefCounted<CORSPreflightCacheEntry> {
bool credentials;
// True if response has "Access-Control-Allow-Methods: *".
bool allow_all_methods;
// True if response has "Access-Control-Allow-Headers: *".
// Non-wildcard request-header name is "Authentication".
bool allow_all_headers_except_non_wildcard;
base::Time expiration_time;
std::set<net::URLFetcher::RequestType> methods;
std::set<std::string, CaseInsensitiveCompare> headernames;
CORSPreflightCacheEntry()
: credentials(false),
allow_all_methods(false),
allow_all_headers_except_non_wildcard(false) {}
};
struct ExpirationHeapEntry {
base::Time expiration_time;
std::string url_str;
std::string origin;
bool operator>(const ExpirationHeapEntry& rhs) const {
return expiration_time > rhs.expiration_time;
}
bool operator<(const ExpirationHeapEntry& rhs) const {
return expiration_time < rhs.expiration_time;
}
};
// This operator constructs a min-heap.
class ExpirationMinHeapComparator {
public:
bool operator()(const ExpirationHeapEntry& lhs,
const ExpirationHeapEntry& rhs) {
return lhs > rhs;
}
};
void ClearObsoleteEntries();
// TODO: Replace scoped_refptr with std::unique_ptr when possible or replace
// the map as a 'scoped_map'.
base::hash_map<
std::string,
base::hash_map<std::string, scoped_refptr<CORSPreflightCacheEntry> > >
content_;
std::priority_queue<ExpirationHeapEntry, std::vector<ExpirationHeapEntry>,
ExpirationMinHeapComparator>
expiration_time_heap_;
THREAD_CHECKER(thread_checker_);
};
} // namespace loader
} // namespace cobalt
#endif // COBALT_LOADER_CORS_PREFLIGHT_CACHE_H_