Commit 9d02277d authored by Hiroki Nakagawa's avatar Hiroki Nakagawa Committed by Commit Bot

Blob: Clarify URLSecurityOriginMap is used for blob URLs in "null" origins

|URLSecurityOriginMap* g_url_origin_map| in security_origin.cc is used only for
keeping pairs of blob URLs and origins serialized to "null" (i.e. opaque
origins, or origins of file URLs). To clarify it, this CL renames class/variable
names, adds implementation comments, and puts some DCHECKs.

Change-Id: Ifbc27caa90f9696d6d2db490157e12824d4fb113
Bug: 987130
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1772933
Commit-Queue: Hiroki Nakagawa <nhiroki@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#705858}
parent e7c63a0f
...@@ -46,56 +46,64 @@ namespace blink { ...@@ -46,56 +46,64 @@ namespace blink {
namespace { namespace {
// When a blob URL is created in a unique origin the origin is serialized into // When a blob URL is created in an opaque origin or something whose
// the URL as "null". Since that makes it impossible to parse the origin back // SecurityOrigin::SerializesAsNull() returns true, the origin is serialized
// out and compare it against a context's origin (to check if a context is // into the URL as "null". Since that makes it impossible to parse the origin
// back out and compare it against a context's origin (to check if a context is
// allowed to dereference the URL) we store a map of blob URL to SecurityOrigin // allowed to dereference the URL) we store a map of blob URL to SecurityOrigin
// instance for blob URLs with unique origins. // instance for blob URLs with such the origins.
class BlobOriginMap : public URLSecurityOriginMap { class BlobURLNullOriginMap final : public URLSecurityOriginMap {
public: public:
BlobOriginMap(); BlobURLNullOriginMap();
SecurityOrigin* GetOrigin(const KURL&) override;
// If the given blob URL has a "null" origin, returns SecurityOrigin that
// represents the "null" origin. Otherwise, returns nullptr.
SecurityOrigin* GetOrigin(const KURL& blob_url) override;
}; };
typedef HashMap<String, scoped_refptr<SecurityOrigin>> BlobURLOriginMap; typedef HashMap<String, scoped_refptr<SecurityOrigin>> BlobURLOriginMap;
static ThreadSpecific<BlobURLOriginMap>& OriginMap() { static ThreadSpecific<BlobURLOriginMap>& OriginMap() {
// We want to create the BlobOriginMap exactly once because it is shared by // We want to create the BlobURLNullOriginMap exactly once because it is
// all the threads. // shared by all the threads.
DEFINE_THREAD_SAFE_STATIC_LOCAL(BlobOriginMap, cache, ()); DEFINE_THREAD_SAFE_STATIC_LOCAL(BlobURLNullOriginMap, cache, ());
(void)cache; // BlobOriginMap's constructor does the interesting work. // BlobURLNullOriginMap's constructor does the interesting work.
(void)cache;
DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<BlobURLOriginMap>, map, ()); DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<BlobURLOriginMap>, map, ());
return map; return map;
} }
static void SaveToOriginMap(SecurityOrigin* origin, const KURL& url) { static void SaveToOriginMap(SecurityOrigin* origin, const KURL& blob_url) {
// If the blob URL contains null origin, as in the context with unique DCHECK(blob_url.ProtocolIs("blob"));
DCHECK(!blob_url.HasFragmentIdentifier());
// If the blob URL contains "null" origin, as in the context with opaque
// security origin or file URL, save the mapping between url and origin so // security origin or file URL, save the mapping between url and origin so
// that the origin can be retrieved when doing security origin check. // that the origin can be retrieved when doing security origin check.
// //
// See the definition of the origin of a Blob URL in the File API spec. // See the definition of the origin of a Blob URL in the File API spec.
DCHECK(!url.HasFragmentIdentifier()); if (origin && origin->SerializesAsNull()) {
if (origin && BlobURL::GetOrigin(url) == "null") DCHECK_EQ(BlobURL::GetOrigin(blob_url), "null");
OriginMap()->insert(url.GetString(), origin); OriginMap()->insert(blob_url.GetString(), origin);
}
} }
static void RemoveFromOriginMap(const KURL& url) { static void RemoveFromOriginMap(const KURL& blob_url) {
if (BlobURL::GetOrigin(url) == "null") DCHECK(blob_url.ProtocolIs("blob"));
OriginMap()->erase(url.GetString()); if (BlobURL::GetOrigin(blob_url) == "null")
OriginMap()->erase(blob_url.GetString());
} }
BlobOriginMap::BlobOriginMap() { BlobURLNullOriginMap::BlobURLNullOriginMap() {
SecurityOrigin::SetMap(this); SecurityOrigin::SetBlobURLNullOriginMap(this);
} }
SecurityOrigin* BlobOriginMap::GetOrigin(const KURL& url) { SecurityOrigin* BlobURLNullOriginMap::GetOrigin(const KURL& blob_url) {
if (url.ProtocolIs("blob")) { DCHECK(blob_url.ProtocolIs("blob"));
KURL url_without_fragment = url; KURL blob_url_without_fragment = blob_url;
url_without_fragment.RemoveFragmentIdentifier(); blob_url_without_fragment.RemoveFragmentIdentifier();
return OriginMap()->at(url_without_fragment.GetString()); return OriginMap()->at(blob_url_without_fragment.GetString());
}
return nullptr;
} }
} // namespace } // namespace
......
...@@ -63,11 +63,12 @@ const String& EnsureNonNull(const String& string) { ...@@ -63,11 +63,12 @@ const String& EnsureNonNull(const String& string) {
} // namespace } // namespace
static URLSecurityOriginMap* g_url_origin_map = nullptr; static URLSecurityOriginMap* g_blob_url_null_origin_map = nullptr;
static SecurityOrigin* GetOriginFromMap(const KURL& url) { static SecurityOrigin* GetNullOriginFromBlobURL(const KURL& blob_url) {
if (g_url_origin_map) DCHECK(blob_url.ProtocolIs("blob"));
return g_url_origin_map->GetOrigin(url); if (g_blob_url_null_origin_map)
return g_blob_url_null_origin_map->GetOrigin(blob_url);
return nullptr; return nullptr;
} }
...@@ -93,8 +94,10 @@ KURL SecurityOrigin::ExtractInnerURL(const KURL& url) { ...@@ -93,8 +94,10 @@ KURL SecurityOrigin::ExtractInnerURL(const KURL& url) {
return KURL(url.GetPath()); return KURL(url.GetPath());
} }
void SecurityOrigin::SetMap(URLSecurityOriginMap* map) { void SecurityOrigin::SetBlobURLNullOriginMap(
g_url_origin_map = map; URLSecurityOriginMap* blob_url_null_origin_map) {
DCHECK(!g_blob_url_null_origin_map);
g_blob_url_null_origin_map = blob_url_null_origin_map;
} }
static bool ShouldTreatAsOpaqueOrigin(const KURL& url) { static bool ShouldTreatAsOpaqueOrigin(const KURL& url) {
...@@ -202,8 +205,10 @@ SecurityOrigin::SecurityOrigin(const SecurityOrigin* other, ...@@ -202,8 +205,10 @@ SecurityOrigin::SecurityOrigin(const SecurityOrigin* other,
scoped_refptr<SecurityOrigin> SecurityOrigin::CreateWithReferenceOrigin( scoped_refptr<SecurityOrigin> SecurityOrigin::CreateWithReferenceOrigin(
const KURL& url, const KURL& url,
const SecurityOrigin* reference_origin) { const SecurityOrigin* reference_origin) {
if (scoped_refptr<SecurityOrigin> origin = GetOriginFromMap(url)) if (url.ProtocolIs("blob")) {
return origin; if (scoped_refptr<SecurityOrigin> origin = GetNullOriginFromBlobURL(url))
return origin;
}
if (ShouldTreatAsOpaqueOrigin(url)) { if (ShouldTreatAsOpaqueOrigin(url)) {
if (!reference_origin) if (!reference_origin)
...@@ -318,16 +323,6 @@ bool SecurityOrigin::IsSecure(const KURL& url) { ...@@ -318,16 +323,6 @@ bool SecurityOrigin::IsSecure(const KURL& url) {
return false; return false;
} }
bool SecurityOrigin::SerializesAsNull() const {
if (IsOpaque())
return true;
if (IsLocal() && block_local_access_from_local_origin_)
return true;
return false;
}
base::Optional<base::UnguessableToken> base::Optional<base::UnguessableToken>
SecurityOrigin::GetNonceForSerialization() const { SecurityOrigin::GetNonceForSerialization() const {
// The call to token() forces initialization of the |nonce_if_opaque_| if // The call to token() forces initialization of the |nonce_if_opaque_| if
...@@ -421,11 +416,15 @@ bool SecurityOrigin::CanRequest(const KURL& url) const { ...@@ -421,11 +416,15 @@ bool SecurityOrigin::CanRequest(const KURL& url) const {
if (universal_access_) if (universal_access_)
return true; return true;
if (GetOriginFromMap(url) == this) if (SerializesAsNull()) {
return true; // Allow the request if the URL is blob and it has the same "null" origin
// with |this|.
if (IsOpaque()) // TODO(nhiroki): Probably we should check the equality by
// SecurityOrigin::IsSameSchemeHostPort().
if (url.ProtocolIs("blob") && GetNullOriginFromBlobURL(url) == this)
return true;
return false; return false;
}
scoped_refptr<const SecurityOrigin> target_origin = scoped_refptr<const SecurityOrigin> target_origin =
SecurityOrigin::Create(url); SecurityOrigin::Create(url);
...@@ -707,4 +706,14 @@ scoped_refptr<SecurityOrigin> SecurityOrigin::GetOriginForAgentCluster( ...@@ -707,4 +706,14 @@ scoped_refptr<SecurityOrigin> SecurityOrigin::GetOriginForAgentCluster(
return result; return result;
} }
bool SecurityOrigin::SerializesAsNull() const {
if (IsOpaque())
return true;
if (IsLocal() && block_local_access_from_local_origin_)
return true;
return false;
}
} // namespace blink } // namespace blink
...@@ -95,7 +95,9 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted<SecurityOrigin> { ...@@ -95,7 +95,9 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted<SecurityOrigin> {
static scoped_refptr<SecurityOrigin> CreateFromUrlOrigin(const url::Origin&); static scoped_refptr<SecurityOrigin> CreateFromUrlOrigin(const url::Origin&);
url::Origin ToUrlOrigin() const; url::Origin ToUrlOrigin() const;
static void SetMap(URLSecurityOriginMap*); // Sets the map to look up a SecurityOrigin instance serialized to "null" from
// a blob URL.
static void SetBlobURLNullOriginMap(URLSecurityOriginMap*);
// Some URL schemes use nested URLs for their security context. For example, // Some URL schemes use nested URLs for their security context. For example,
// filesystem URLs look like the following: // filesystem URLs look like the following:
...@@ -334,6 +336,9 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted<SecurityOrigin> { ...@@ -334,6 +336,9 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted<SecurityOrigin> {
return agent_cluster_id_; return agent_cluster_id_;
} }
// Returns true if this security origin is serialized to "null".
bool SerializesAsNull() const;
private: private:
constexpr static const uint16_t kInvalidPort = 0; constexpr static const uint16_t kInvalidPort = 0;
...@@ -365,8 +370,6 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted<SecurityOrigin> { ...@@ -365,8 +370,6 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted<SecurityOrigin> {
bool PassesFileCheck(const SecurityOrigin*) const; bool PassesFileCheck(const SecurityOrigin*) const;
void BuildRawString(StringBuilder&) const; void BuildRawString(StringBuilder&) const;
bool SerializesAsNull() const;
// Get the nonce associated with this origin, if it is unique. This should be // Get the nonce associated with this origin, if it is unique. This should be
// used only when trying to send an Origin across an IPC pipe. // used only when trying to send an Origin across an IPC pipe.
base::Optional<base::UnguessableToken> GetNonceForSerialization() const; base::Optional<base::UnguessableToken> GetNonceForSerialization() const;
......
...@@ -45,6 +45,9 @@ class URLSecurityOriginMap { ...@@ -45,6 +45,9 @@ class URLSecurityOriginMap {
public: public:
URLSecurityOriginMap() = default; URLSecurityOriginMap() = default;
virtual ~URLSecurityOriginMap() = default; virtual ~URLSecurityOriginMap() = default;
// Returns a SecurityOrigin instance that represents the origin of the given
// URL. May return nullptr.
virtual SecurityOrigin* GetOrigin(const KURL&) = 0; virtual SecurityOrigin* GetOrigin(const KURL&) = 0;
private: private:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment