blob: b415684a1f8e1e249158df2574f51cfff71fabe0 [file]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/renderer/resource_bundle_source_map.h"
#include <algorithm>
#include <functional>
#include <ostream>
#include <string_view>
#include "base/notreached.h"
#include "extensions/renderer/static_v8_external_one_byte_string_resource.h"
#include "third_party/zlib/google/compression_utils.h"
#include "ui/base/resource/resource_bundle.h"
#include "v8/include/v8-primitive.h"
namespace extensions {
namespace {
v8::Local<v8::String> ConvertString(v8::Isolate* isolate,
std::string_view string) {
// v8 takes ownership of the StaticV8ExternalOneByteStringResource (see
// v8::String::NewExternalOneByte()).
return v8::String::NewExternalOneByte(
isolate, new StaticV8ExternalOneByteStringResource(string))
.FromMaybe(v8::Local<v8::String>());
}
} // namespace
ResourceBundleSourceMap::ResourceBundleSourceMap(
const ui::ResourceBundle* resource_bundle)
: resource_bundle_(resource_bundle) {}
ResourceBundleSourceMap::~ResourceBundleSourceMap() = default;
v8::Local<v8::String> ResourceBundleSourceMap::GetSource(
v8::Isolate* isolate,
std::string_view name) const {
base::AutoLock lock(lock_);
std::optional<int> resource_id = FindResourceId(name);
if (!resource_id) {
DUMP_WILL_BE_NOTREACHED()
<< "No module is registered with name \"" << name << "\"";
return v8::Local<v8::String>();
}
auto cached = cached_sources_.find(*resource_id);
if (cached != cached_sources_.end()) {
return ConvertString(isolate, cached->second);
}
std::string_view resource =
resource_bundle_->GetRawDataResource(*resource_id);
if (resource.empty()) {
DUMP_WILL_BE_NOTREACHED()
<< "Module resource registered as \"" << name << "\" not found";
return v8::Local<v8::String>();
}
bool is_gzipped = resource_bundle_->IsGzipped(*resource_id);
if (is_gzipped) {
std::string& cached_source = cached_sources_[*resource_id];
if (!compression::GzipUncompress(resource, &cached_source)) {
// Leave an empty string in the cache so later requests return directly
// instead of trying to uncompress again.
cached_source.clear();
return v8::Local<v8::String>();
}
resource = cached_source;
}
return ConvertString(isolate, resource);
}
bool ResourceBundleSourceMap::Contains(std::string_view name) const {
base::AutoLock lock(lock_);
return FindResourceId(name).has_value();
}
std::optional<int> ResourceBundleSourceMap::FindResourceId(
std::string_view name) const {
for (const SourceTable& table : source_tables_) {
auto source = std::ranges::lower_bound(table, name, std::less<>(),
&SourceEntry::first);
if (source != table.end() && source->first == name) {
return source->second;
}
}
return std::nullopt;
}
} // namespace extensions