| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/webui/web_applications/webui_test_prod_util.h" |
| |
| #include "ash/constants/ash_switches.h" |
| #include "base/command_line.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/logging.h" |
| #include "base/memory/ref_counted_memory.h" |
| #include "base/no_destructor.h" |
| #include "base/task/task_traits.h" |
| #include "base/task/thread_pool.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "content/public/common/content_switches.h" |
| |
| using content::WebUIDataSource; |
| |
| namespace { |
| |
| WebUIDataSource::ShouldHandleRequestCallback& GetTestShouldHandleRequest() { |
| static base::NoDestructor<WebUIDataSource::ShouldHandleRequestCallback> |
| callback; |
| return *callback; |
| } |
| |
| WebUIDataSource::HandleRequestCallback& GetTestRequestFilterHandler() { |
| static base::NoDestructor<WebUIDataSource::HandleRequestCallback> callback; |
| return *callback; |
| } |
| |
| bool InvokeTestShouldHandleRequestCallback( |
| const WebUIDataSource::ShouldHandleRequestCallback& |
| real_should_handle_request_callback, |
| const std::string& path) { |
| const auto& test_callback = GetTestShouldHandleRequest(); |
| if (test_callback && test_callback.Run(path)) { |
| return true; |
| } |
| return real_should_handle_request_callback && |
| real_should_handle_request_callback.Run(path); |
| } |
| |
| void InvokeTestFileRequestFilterCallback( |
| const WebUIDataSource::HandleRequestCallback& real_handle_request_callback, |
| const std::string& path, |
| WebUIDataSource::GotDataCallback callback) { |
| // First, check whether this was request for a test-only resource. This |
| // requires the test handler to be installed by |
| // SetTestableDataSourceRequestHandlerForTesting() and for it to have returned |
| // true. Otherwise assume, that since the request was directed to the filter, |
| // that it is a request for the "real" filter installed by |
| // MaybeConfigureTestableDataSource(). |
| const auto& test_callback = GetTestShouldHandleRequest(); |
| if (test_callback && test_callback.Run(path)) { |
| GetTestRequestFilterHandler().Run(path, std::move(callback)); |
| } else { |
| DCHECK(!real_handle_request_callback.is_null()); |
| real_handle_request_callback.Run(path, std::move(callback)); |
| } |
| } |
| |
| // Determines whether, when attempting to load a path, we want to, instead of |
| // using the regular handler, load it from a file on disk. |
| bool ShouldLoadResponseFromDisk(const base::FilePath& root, |
| const std::string& path) { |
| const base::FilePath expanded = root.Append(path); |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| const bool exists = base::PathExists(expanded); |
| if (exists) { |
| VLOG(1) << "Loading test data from " << expanded << " for " << path; |
| } else { |
| VLOG(1) << "Unable to load test data from " << expanded << " for " << path |
| << ", as the file doesn't exist."; |
| } |
| return exists; |
| } |
| |
| void LoadFileFromDisk(const base::FilePath& path, |
| content::WebUIDataSource::GotDataCallback callback) { |
| std::string result; |
| CHECK(base::ReadFileToString(path, &result)); |
| |
| std::move(callback).Run(new base::RefCountedBytes( |
| reinterpret_cast<const unsigned char*>(result.data()), result.size())); |
| } |
| |
| void LoadResponseFromDisk(const base::FilePath& root, |
| const std::string& path, |
| content::WebUIDataSource::GotDataCallback callback) { |
| base::ThreadPool::PostTask( |
| FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, |
| base::BindOnce(LoadFileFromDisk, root.Append(path), std::move(callback))); |
| } |
| |
| } // namespace |
| |
| bool MaybeConfigureTestableDataSource( |
| WebUIDataSource* host_source, |
| const std::string& handler_name, |
| const WebUIDataSource::ShouldHandleRequestCallback& |
| real_should_handle_request_callback, |
| const WebUIDataSource::HandleRequestCallback& |
| real_handle_request_callback) { |
| const base::CommandLine& cmd = *base::CommandLine::ForCurrentProcess(); |
| bool has_test_handler = false; |
| if (cmd.HasSwitch(::ash::switches::kWebUiDataSourcePathForTesting) && |
| !handler_name.empty()) { |
| const base::FilePath root = |
| cmd.GetSwitchValuePath(::ash::switches::kWebUiDataSourcePathForTesting) |
| .Append(handler_name); |
| GetTestShouldHandleRequest() = |
| base::BindRepeating(ShouldLoadResponseFromDisk, root); |
| GetTestRequestFilterHandler() = |
| base::BindRepeating(LoadResponseFromDisk, root); |
| has_test_handler = true; |
| } else if (cmd.HasSwitch(::switches::kTestType)) { |
| has_test_handler = true; |
| } |
| |
| if (has_test_handler) { |
| host_source->SetRequestFilter( |
| base::BindRepeating(&InvokeTestShouldHandleRequestCallback, |
| real_should_handle_request_callback), |
| base::BindRepeating(&InvokeTestFileRequestFilterCallback, |
| real_handle_request_callback)); |
| } else { |
| host_source->SetRequestFilter(real_should_handle_request_callback, |
| real_handle_request_callback); |
| } |
| return has_test_handler; |
| } |
| |
| void SetTestableDataSourceRequestHandlerForTesting( // IN-TEST |
| WebUIDataSource::ShouldHandleRequestCallback should_handle, |
| WebUIDataSource::HandleRequestCallback handler) { |
| GetTestShouldHandleRequest() = std::move(should_handle); |
| GetTestRequestFilterHandler() = std::move(handler); |
| } |