| // Copyright 2017 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 "storage/browser/blob/blob_url_store_impl.h" |
| |
| #include "base/bind.h" |
| #include "mojo/public/cpp/bindings/strong_binding.h" |
| #include "storage/browser/blob/blob_impl.h" |
| #include "storage/browser/blob/blob_storage_context.h" |
| #include "storage/browser/blob/blob_url_loader_factory.h" |
| #include "storage/browser/blob/blob_url_utils.h" |
| |
| namespace storage { |
| |
| // Self deletes when the last binding to it is closed. |
| class BlobURLTokenImpl : public blink::mojom::BlobURLToken { |
| public: |
| BlobURLTokenImpl(base::WeakPtr<BlobStorageContext> context, |
| const GURL& url, |
| std::unique_ptr<BlobDataHandle> blob, |
| blink::mojom::BlobURLTokenRequest request) |
| : context_(std::move(context)), |
| url_(url), |
| blob_(std::move(blob)), |
| token_(base::UnguessableToken::Create()) { |
| bindings_.AddBinding(this, std::move(request)); |
| bindings_.set_connection_error_handler(base::BindRepeating( |
| &BlobURLTokenImpl::OnConnectionError, base::Unretained(this))); |
| if (context_) { |
| context_->mutable_registry()->AddTokenMapping(token_, url_, |
| blob_->uuid()); |
| } |
| } |
| |
| ~BlobURLTokenImpl() override { |
| if (context_) |
| context_->mutable_registry()->RemoveTokenMapping(token_); |
| } |
| |
| void GetToken(GetTokenCallback callback) override { |
| std::move(callback).Run(token_); |
| } |
| |
| void Clone(blink::mojom::BlobURLTokenRequest request) override { |
| bindings_.AddBinding(this, std::move(request)); |
| } |
| |
| private: |
| void OnConnectionError() { |
| if (!bindings_.empty()) |
| return; |
| delete this; |
| } |
| |
| base::WeakPtr<BlobStorageContext> context_; |
| mojo::BindingSet<blink::mojom::BlobURLToken> bindings_; |
| const GURL url_; |
| const std::unique_ptr<BlobDataHandle> blob_; |
| const base::UnguessableToken token_; |
| }; |
| |
| BlobURLStoreImpl::BlobURLStoreImpl(base::WeakPtr<BlobStorageContext> context, |
| BlobRegistryImpl::Delegate* delegate) |
| : context_(std::move(context)), |
| delegate_(delegate), |
| weak_ptr_factory_(this) {} |
| |
| BlobURLStoreImpl::~BlobURLStoreImpl() { |
| if (context_) { |
| for (const auto& url : urls_) |
| context_->RevokePublicBlobURL(url); |
| } |
| } |
| |
| void BlobURLStoreImpl::Register(blink::mojom::BlobPtr blob, |
| const GURL& url, |
| RegisterCallback callback) { |
| if (!url.SchemeIsBlob()) { |
| mojo::ReportBadMessage("Invalid scheme passed to BlobURLStore::Register"); |
| std::move(callback).Run(); |
| return; |
| } |
| // Only report errors when we don't have permission to commit and |
| // the process is valid. The process check is a temporary solution to |
| // handle cases where this method is run after the |
| // process associated with |delegate_| has been destroyed. |
| // See https://crbug.com/933089 for details. |
| if (!delegate_->CanCommitURL(url) && delegate_->IsProcessValid()) { |
| mojo::ReportBadMessage( |
| "Non committable URL passed to BlobURLStore::Register"); |
| std::move(callback).Run(); |
| return; |
| } |
| if (BlobUrlUtils::UrlHasFragment(url)) { |
| mojo::ReportBadMessage( |
| "URL with fragment passed to BlobURLStore::Register"); |
| std::move(callback).Run(); |
| return; |
| } |
| |
| blink::mojom::Blob* blob_ptr = blob.get(); |
| blob_ptr->GetInternalUUID(base::BindOnce( |
| &BlobURLStoreImpl::RegisterWithUUID, weak_ptr_factory_.GetWeakPtr(), |
| std::move(blob), url, std::move(callback))); |
| } |
| |
| void BlobURLStoreImpl::Revoke(const GURL& url) { |
| if (!url.SchemeIsBlob()) { |
| mojo::ReportBadMessage("Invalid scheme passed to BlobURLStore::Revoke"); |
| return; |
| } |
| // Only report errors when we don't have permission to commit and |
| // the process is valid. The process check is a temporary solution to |
| // handle cases where this method is run after the |
| // process associated with |delegate_| has been destroyed. |
| // See https://crbug.com/933089 for details. |
| if (!delegate_->CanCommitURL(url) && delegate_->IsProcessValid()) { |
| mojo::ReportBadMessage( |
| "Non committable URL passed to BlobURLStore::Revoke"); |
| return; |
| } |
| if (BlobUrlUtils::UrlHasFragment(url)) { |
| mojo::ReportBadMessage("URL with fragment passed to BlobURLStore::Revoke"); |
| return; |
| } |
| |
| if (context_) |
| context_->RevokePublicBlobURL(url); |
| urls_.erase(url); |
| } |
| |
| void BlobURLStoreImpl::Resolve(const GURL& url, ResolveCallback callback) { |
| if (!context_) { |
| std::move(callback).Run(nullptr); |
| return; |
| } |
| blink::mojom::BlobPtr blob; |
| std::unique_ptr<BlobDataHandle> blob_handle = |
| context_->GetBlobDataFromPublicURL(url); |
| if (blob_handle) |
| BlobImpl::Create(std::move(blob_handle), MakeRequest(&blob)); |
| std::move(callback).Run(std::move(blob)); |
| } |
| |
| void BlobURLStoreImpl::ResolveAsURLLoaderFactory( |
| const GURL& url, |
| network::mojom::URLLoaderFactoryRequest request) { |
| BlobURLLoaderFactory::Create( |
| context_ ? context_->GetBlobDataFromPublicURL(url) : nullptr, url, |
| std::move(request)); |
| } |
| |
| void BlobURLStoreImpl::ResolveForNavigation( |
| const GURL& url, |
| blink::mojom::BlobURLTokenRequest token) { |
| if (!context_) |
| return; |
| std::unique_ptr<BlobDataHandle> blob_handle = |
| context_->GetBlobDataFromPublicURL(url); |
| if (!blob_handle) |
| return; |
| new BlobURLTokenImpl(context_, url, std::move(blob_handle), std::move(token)); |
| } |
| |
| void BlobURLStoreImpl::RegisterWithUUID(blink::mojom::BlobPtr blob, |
| const GURL& url, |
| RegisterCallback callback, |
| const std::string& uuid) { |
| // |blob| is unused, but is passed here to be kept alive until |
| // RegisterPublicBlobURL increments the refcount of it via the uuid. |
| if (context_) |
| context_->RegisterPublicBlobURL(url, uuid); |
| urls_.insert(url); |
| std::move(callback).Run(); |
| } |
| |
| } // namespace storage |