blob: a8cd455b971acd2b5603ca21903191255c7a39fd [file] [log] [blame]
// Copyright 2015 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 "flutter/tonic/dart_library_provider_files.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/strings/string_util.h"
#include "base/threading/worker_pool.h"
#include "lib/tonic/converter/dart_converter.h"
#include "mojo/data_pipe_utils/data_pipe_utils.h"
namespace sky {
namespace shell {
namespace {
void CopyComplete(base::FilePath file, std::string uri, bool success) {
if (!success)
LOG(FATAL) << "Failed to load " << file.AsUTF8Unsafe() << " (" << uri
<< ")";
}
// Extract the scheme prefix ('package:' or 'file:' from )
static std::string ExtractSchemePrefix(std::string url) {
if (base::StartsWithASCII(url, "package:", true)) {
return "package:";
} else if (base::StartsWithASCII(url, "file:", true)) {
return "file:";
}
return "";
}
// Extract the path from a package: or file: url.
static std::string ExtractPath(std::string url) {
if (base::StartsWithASCII(url, "package:", true)) {
base::ReplaceFirstSubstringAfterOffset(&url, 0, "package:", "");
} else if (base::StartsWithASCII(url, "file:", true)) {
base::ReplaceFirstSubstringAfterOffset(&url, 0, "file:", "");
}
return url;
}
base::FilePath SimplifyPath(const base::FilePath& path) {
std::vector<base::FilePath::StringType> components;
path.GetComponents(&components);
auto it = components.begin();
base::FilePath result(*it++);
for (; it != components.end(); it++) {
auto& component = *it;
if (component == base::FilePath::kCurrentDirectory)
continue;
if (component == base::FilePath::kParentDirectory)
result = result.DirName();
else
result = result.Append(component);
}
return result;
}
} // namespace
DartLibraryProviderFiles::DartLibraryProviderFiles() {}
DartLibraryProviderFiles::~DartLibraryProviderFiles() {}
void DartLibraryProviderFiles::LoadPackagesMap(const std::string& packages) {
packages_ = base::FilePath(packages);
std::string packages_source;
if (!base::ReadFileToString(base::MakeAbsoluteFilePath(packages_),
&packages_source)) {
LOG(ERROR) << "error: Unable to load .packages file '"
<< packages_.AsUTF8Unsafe() << "'.";
exit(1);
}
std::string error;
if (!packages_map_.Parse(packages_source, &error)) {
LOG(ERROR) << "error: Unable to parse .packages file '"
<< packages_.AsUTF8Unsafe() << "'.\n"
<< error;
exit(1);
}
}
blink::DartLibraryStream DartLibraryProviderFiles::GetLibraryAsStream(
const std::string& name) {
mojo::DataPipe pipe;
base::FilePath path = GetFilePathForURL(name);
base::FilePath source = base::MakeAbsoluteFilePath(path);
blink::DartLibraryStream result;
result.handle = std::move(pipe.consumer_handle);
result.resolved_url = "file://" + source.value();
scoped_refptr<base::TaskRunner> runner =
base::WorkerPool::GetTaskRunner(true);
mojo::common::CopyFromFile(source, pipe.producer_handle.Pass(), 0,
runner.get(),
base::Bind(&CopyComplete, source, name));
return result;
}
Dart_Handle DartLibraryProviderFiles::CanonicalizeURL(Dart_Handle library,
Dart_Handle url) {
std::string string = tonic::StdStringFromDart(url);
if (base::StartsWithASCII(string, "dart:", true))
return url;
if (base::StartsWithASCII(string, "package:", true))
return url;
if (base::StartsWithASCII(string, "file:", true)) {
base::ReplaceFirstSubstringAfterOffset(&string, 0, "file:", "");
return tonic::StdStringToDart(string);
;
}
std::string library_url = tonic::StdStringFromDart(Dart_LibraryUrl(library));
std::string prefix = ExtractSchemePrefix(library_url);
std::string path = ExtractPath(library_url);
base::FilePath base_path(path);
base::FilePath resolved_path = base_path.DirName().Append(string);
base::FilePath normalized_path = SimplifyPath(resolved_path);
return tonic::StdStringToDart(prefix + normalized_path.AsUTF8Unsafe());
}
base::FilePath DartLibraryProviderFiles::GetFilePathForURL(std::string url) {
if (base::StartsWithASCII(url, "package:", true))
return GetFilePathForPackageURL(url);
if (base::StartsWithASCII(url, "file:", true))
return GetFilePathForFileURL(url);
return base::FilePath(url);
}
base::FilePath DartLibraryProviderFiles::GetFilePathForPackageURL(
std::string url) {
DCHECK(base::StartsWithASCII(url, "package:", true));
base::ReplaceFirstSubstringAfterOffset(&url, 0, "package:", "");
size_t slash = url.find('/');
if (slash == std::string::npos)
return base::FilePath();
std::string package = url.substr(0, slash);
std::string library_path = url.substr(slash + 1);
std::string package_path = packages_map_.Resolve(package);
if (package_path.empty())
return base::FilePath();
if (base::StartsWithASCII(package_path, "file://", true)) {
base::ReplaceFirstSubstringAfterOffset(&package_path, 0, "file://", "");
return base::FilePath(package_path + library_path);
}
return packages_.DirName().Append(package_path).Append(library_path);
}
base::FilePath DartLibraryProviderFiles::GetFilePathForFileURL(
std::string url) {
DCHECK(base::StartsWithASCII(url, "file://", true));
base::ReplaceFirstSubstringAfterOffset(&url, 0, "file://", "");
return base::FilePath(url);
}
} // namespace shell
} // namespace sky