This source file includes following definitions.
- GetParentDirectory
- CheckPathIsValid
- IsEnclosingPath
- CheckOriginIsValid
- RecordLookupPosition
- RecordLookupByPathPosition
- Lookup
- LookupByPath
- Add
- UpdateStaleChallenge
- nonce_count_
- AddPath
- HasEnclosingPath
- Remove
- UpdateStaleChallenge
- UpdateAllFrom
#include "net/http/http_auth_cache.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
namespace {
std::string GetParentDirectory(const std::string& path) {
std::string::size_type last_slash = path.rfind("/");
if (last_slash == std::string::npos) {
DCHECK(path.empty());
return path;
}
return path.substr(0, last_slash + 1);
}
void CheckPathIsValid(const std::string& path) {
DCHECK(path.empty() || path[0] == '/');
}
bool IsEnclosingPath(const std::string& container, const std::string& path) {
DCHECK(container.empty() || *(container.end() - 1) == '/');
return ((container.empty() && path.empty()) ||
(!container.empty() && StartsWithASCII(path, container, true)));
}
void CheckOriginIsValid(const GURL& origin) {
DCHECK(origin.is_valid());
DCHECK(origin.SchemeIsHTTPOrHTTPS() || origin.SchemeIs("ftp") ||
origin.SchemeIsWSOrWSS());
DCHECK(origin.GetOrigin() == origin);
}
struct IsEnclosedBy {
explicit IsEnclosedBy(const std::string& path) : path(path) { }
bool operator() (const std::string& x) const {
return IsEnclosingPath(path, x);
}
const std::string& path;
};
void RecordLookupPosition(int position) {
UMA_HISTOGRAM_COUNTS_100("Net.HttpAuthCacheLookupPosition", position);
}
void RecordLookupByPathPosition(int position) {
UMA_HISTOGRAM_COUNTS_100("Net.HttpAuthCacheLookupByPathPosition", position);
}
}
namespace net {
HttpAuthCache::HttpAuthCache() {
}
HttpAuthCache::~HttpAuthCache() {
}
HttpAuthCache::Entry* HttpAuthCache::Lookup(const GURL& origin,
const std::string& realm,
HttpAuth::Scheme scheme) {
CheckOriginIsValid(origin);
int entries_examined = 0;
for (EntryList::iterator it = entries_.begin(); it != entries_.end(); ++it) {
++entries_examined;
if (it->origin() == origin && it->realm() == realm &&
it->scheme() == scheme) {
it->last_use_time_ = base::TimeTicks::Now();
RecordLookupPosition(entries_examined);
return &(*it);
}
}
RecordLookupPosition(0);
return NULL;
}
HttpAuthCache::Entry* HttpAuthCache::LookupByPath(const GURL& origin,
const std::string& path) {
HttpAuthCache::Entry* best_match = NULL;
size_t best_match_length = 0;
int best_match_position = 0;
CheckOriginIsValid(origin);
CheckPathIsValid(path);
std::string parent_dir = GetParentDirectory(path);
int entries_examined = 0;
for (EntryList::iterator it = entries_.begin(); it != entries_.end(); ++it) {
++entries_examined;
size_t len = 0;
if (it->origin() == origin && it->HasEnclosingPath(parent_dir, &len) &&
(!best_match || len > best_match_length)) {
best_match = &(*it);
best_match_length = len;
best_match_position = entries_examined;
}
}
if (best_match)
best_match->last_use_time_ = base::TimeTicks::Now();
RecordLookupByPathPosition(best_match_position);
return best_match;
}
HttpAuthCache::Entry* HttpAuthCache::Add(const GURL& origin,
const std::string& realm,
HttpAuth::Scheme scheme,
const std::string& auth_challenge,
const AuthCredentials& credentials,
const std::string& path) {
CheckOriginIsValid(origin);
CheckPathIsValid(path);
base::TimeTicks now = base::TimeTicks::Now();
HttpAuthCache::Entry* entry = Lookup(origin, realm, scheme);
if (!entry) {
bool evicted = false;
if (entries_.size() >= kMaxNumRealmEntries) {
LOG(WARNING) << "Num auth cache entries reached limit -- evicting";
UMA_HISTOGRAM_LONG_TIMES("Net.HttpAuthCacheAddEvictedCreation",
now - entries_.back().creation_time_);
UMA_HISTOGRAM_LONG_TIMES("Net.HttpAuthCacheAddEvictedLastUse",
now - entries_.back().last_use_time_);
entries_.pop_back();
evicted = true;
}
UMA_HISTOGRAM_BOOLEAN("Net.HttpAuthCacheAddEvicted", evicted);
entries_.push_front(Entry());
entry = &entries_.front();
entry->origin_ = origin;
entry->realm_ = realm;
entry->scheme_ = scheme;
entry->creation_time_ = now;
}
DCHECK_EQ(origin, entry->origin_);
DCHECK_EQ(realm, entry->realm_);
DCHECK_EQ(scheme, entry->scheme_);
entry->auth_challenge_ = auth_challenge;
entry->credentials_ = credentials;
entry->nonce_count_ = 1;
entry->AddPath(path);
entry->last_use_time_ = now;
return entry;
}
HttpAuthCache::Entry::~Entry() {
}
void HttpAuthCache::Entry::UpdateStaleChallenge(
const std::string& auth_challenge) {
auth_challenge_ = auth_challenge;
nonce_count_ = 1;
}
HttpAuthCache::Entry::Entry()
: scheme_(HttpAuth::AUTH_SCHEME_MAX),
nonce_count_(0) {
}
void HttpAuthCache::Entry::AddPath(const std::string& path) {
std::string parent_dir = GetParentDirectory(path);
if (!HasEnclosingPath(parent_dir, NULL)) {
paths_.remove_if(IsEnclosedBy(parent_dir));
bool evicted = false;
if (paths_.size() >= kMaxNumPathsPerRealmEntry) {
LOG(WARNING) << "Num path entries for " << origin()
<< " has grown too large -- evicting";
paths_.pop_back();
evicted = true;
}
UMA_HISTOGRAM_BOOLEAN("Net.HttpAuthCacheAddPathEvicted", evicted);
paths_.push_front(parent_dir);
}
}
bool HttpAuthCache::Entry::HasEnclosingPath(const std::string& dir,
size_t* path_len) {
DCHECK(GetParentDirectory(dir) == dir);
for (PathList::const_iterator it = paths_.begin(); it != paths_.end();
++it) {
if (IsEnclosingPath(*it, dir)) {
if (path_len)
*path_len = it->length();
return true;
}
}
return false;
}
bool HttpAuthCache::Remove(const GURL& origin,
const std::string& realm,
HttpAuth::Scheme scheme,
const AuthCredentials& credentials) {
for (EntryList::iterator it = entries_.begin(); it != entries_.end(); ++it) {
if (it->origin() == origin && it->realm() == realm &&
it->scheme() == scheme) {
if (credentials.Equals(it->credentials())) {
entries_.erase(it);
return true;
}
return false;
}
}
return false;
}
bool HttpAuthCache::UpdateStaleChallenge(const GURL& origin,
const std::string& realm,
HttpAuth::Scheme scheme,
const std::string& auth_challenge) {
HttpAuthCache::Entry* entry = Lookup(origin, realm, scheme);
if (!entry)
return false;
entry->UpdateStaleChallenge(auth_challenge);
entry->last_use_time_ = base::TimeTicks::Now();
return true;
}
void HttpAuthCache::UpdateAllFrom(const HttpAuthCache& other) {
for (EntryList::const_iterator it = other.entries_.begin();
it != other.entries_.end(); ++it) {
DCHECK(it->paths_.size() > 0);
Entry* entry = Add(it->origin(), it->realm(), it->scheme(),
it->auth_challenge(), it->credentials(),
it->paths_.back());
for (Entry::PathList::const_reverse_iterator it2 = ++it->paths_.rbegin();
it2 != it->paths_.rend(); ++it2)
entry->AddPath(*it2);
entry->nonce_count_ = it->nonce_count_;
}
}
}