| // Copyright 2019 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 "content/public/browser/network_context_client_base.h" |
| |
| #include "base/bind.h" |
| #include "base/files/file.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/path_service.h" |
| #include "base/test/task_environment.h" |
| #include "base/test/test_file_util.h" |
| #include "build/build_config.h" |
| #include "content/browser/child_process_security_policy_impl.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "content/public/test/test_browser_context.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| struct UploadResponse { |
| UploadResponse() |
| : callback(base::BindOnce(&UploadResponse::OnComplete, |
| base::Unretained(this))) {} |
| |
| void OnComplete(int error_code, std::vector<base::File> opened_files) { |
| this->error_code = error_code; |
| this->opened_files = std::move(opened_files); |
| } |
| |
| network::mojom::NetworkContextClient::OnFileUploadRequestedCallback callback; |
| int error_code; |
| std::vector<base::File> opened_files; |
| }; |
| |
| void GrantAccess(const base::FilePath& file, int process_id) { |
| ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(process_id, file); |
| } |
| |
| void CreateFile(const base::FilePath& path, const char* content) { |
| base::File file(path, base::File::FLAG_CREATE | base::File::FLAG_WRITE); |
| ASSERT_TRUE(file.IsValid()); |
| int content_size = strlen(content); |
| int bytes_written = file.Write(0, content, content_size); |
| EXPECT_EQ(bytes_written, content_size); |
| } |
| |
| void ValidateFileContents(base::File& file, |
| base::StringPiece expected_content) { |
| int expected_length = expected_content.size(); |
| ASSERT_EQ(file.GetLength(), expected_length); |
| char content[expected_length]; |
| file.Read(0, content, expected_length); |
| EXPECT_EQ(0, strncmp(content, expected_content.data(), expected_length)); |
| } |
| |
| const int kBrowserProcessId = 0; |
| const int kRendererProcessId = 1; |
| const char kFileContent1[] = "test file content one"; |
| const char kFileContent2[] = "test file content two"; |
| |
| } // namespace |
| |
| class NetworkContextClientBaseTest : public testing::Test { |
| public: |
| NetworkContextClientBaseTest() {} |
| |
| void SetUp() override { |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| ChildProcessSecurityPolicyImpl::GetInstance()->Add(kRendererProcessId, |
| &browser_context_); |
| } |
| |
| void TearDown() override { |
| ChildProcessSecurityPolicyImpl::GetInstance()->Remove(kRendererProcessId); |
| } |
| |
| protected: |
| BrowserTaskEnvironment task_environment_; |
| TestBrowserContext browser_context_; |
| NetworkContextClientBase client_; |
| base::ScopedTempDir temp_dir_; |
| }; |
| |
| TEST_F(NetworkContextClientBaseTest, UploadNoFiles) { |
| UploadResponse response; |
| client_.OnFileUploadRequested(kRendererProcessId, true, {}, |
| std::move(response.callback)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(net::OK, response.error_code); |
| EXPECT_EQ(0U, response.opened_files.size()); |
| } |
| |
| TEST_F(NetworkContextClientBaseTest, UploadOneValidAsyncFile) { |
| base::FilePath path = temp_dir_.GetPath().AppendASCII("filename"); |
| CreateFile(path, kFileContent1); |
| GrantAccess(path, kRendererProcessId); |
| |
| UploadResponse response; |
| client_.OnFileUploadRequested(kRendererProcessId, true, {path}, |
| std::move(response.callback)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(net::OK, response.error_code); |
| ASSERT_EQ(1U, response.opened_files.size()); |
| EXPECT_TRUE(response.opened_files[0].async()); |
| } |
| |
| TEST_F(NetworkContextClientBaseTest, UploadOneValidFile) { |
| base::FilePath path = temp_dir_.GetPath().AppendASCII("filename"); |
| CreateFile(path, kFileContent1); |
| GrantAccess(path, kRendererProcessId); |
| |
| UploadResponse response; |
| client_.OnFileUploadRequested(kRendererProcessId, false, {path}, |
| std::move(response.callback)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(net::OK, response.error_code); |
| ASSERT_EQ(1U, response.opened_files.size()); |
| EXPECT_FALSE(response.opened_files[0].async()); |
| ValidateFileContents(response.opened_files[0], kFileContent1); |
| } |
| |
| #if defined(OS_ANDROID) |
| // Flakily fails on Android bots. See http://crbug.com/1027790 |
| TEST_F(NetworkContextClientBaseTest, |
| DISABLED_UploadOneValidFileWithContentUri) { |
| base::FilePath image_path; |
| EXPECT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &image_path)); |
| image_path = image_path.AppendASCII("content") |
| .AppendASCII("test") |
| .AppendASCII("data") |
| .AppendASCII("blank.jpg"); |
| EXPECT_TRUE(base::PathExists(image_path)); |
| base::FilePath content_path = base::InsertImageIntoMediaStore(image_path); |
| EXPECT_TRUE(content_path.IsContentUri()); |
| EXPECT_TRUE(base::PathExists(content_path)); |
| GrantAccess(content_path, kRendererProcessId); |
| |
| UploadResponse response; |
| client_.OnFileUploadRequested(kRendererProcessId, false, {content_path}, |
| std::move(response.callback)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(net::OK, response.error_code); |
| ASSERT_EQ(1U, response.opened_files.size()); |
| EXPECT_FALSE(response.opened_files[0].async()); |
| std::string contents; |
| EXPECT_TRUE(base::ReadFileToString(image_path, &contents)); |
| ValidateFileContents(response.opened_files[0], contents); |
| } |
| #endif |
| |
| TEST_F(NetworkContextClientBaseTest, UploadTwoValidFiles) { |
| base::FilePath path1 = temp_dir_.GetPath().AppendASCII("filename1"); |
| base::FilePath path2 = temp_dir_.GetPath().AppendASCII("filename2"); |
| CreateFile(path1, kFileContent1); |
| CreateFile(path2, kFileContent2); |
| GrantAccess(path1, kRendererProcessId); |
| GrantAccess(path2, kRendererProcessId); |
| |
| UploadResponse response; |
| client_.OnFileUploadRequested(kRendererProcessId, false, {path1, path2}, |
| std::move(response.callback)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(net::OK, response.error_code); |
| ASSERT_EQ(2U, response.opened_files.size()); |
| ValidateFileContents(response.opened_files[0], kFileContent1); |
| ValidateFileContents(response.opened_files[1], kFileContent2); |
| } |
| |
| TEST_F(NetworkContextClientBaseTest, UploadOneUnauthorizedFile) { |
| base::FilePath path = temp_dir_.GetPath().AppendASCII("filename"); |
| CreateFile(path, kFileContent1); |
| |
| UploadResponse response; |
| client_.OnFileUploadRequested(kRendererProcessId, false, {path}, |
| std::move(response.callback)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, response.error_code); |
| EXPECT_EQ(0U, response.opened_files.size()); |
| } |
| |
| TEST_F(NetworkContextClientBaseTest, UploadOneValidFileAndOneUnauthorized) { |
| base::FilePath path1 = temp_dir_.GetPath().AppendASCII("filename1"); |
| base::FilePath path2 = temp_dir_.GetPath().AppendASCII("filename2"); |
| CreateFile(path1, kFileContent1); |
| CreateFile(path2, kFileContent2); |
| GrantAccess(path1, kRendererProcessId); |
| |
| UploadResponse response; |
| client_.OnFileUploadRequested(kRendererProcessId, false, {path1, path2}, |
| std::move(response.callback)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(net::ERR_ACCESS_DENIED, response.error_code); |
| EXPECT_EQ(0U, response.opened_files.size()); |
| } |
| |
| TEST_F(NetworkContextClientBaseTest, UploadOneValidFileAndOneNotFound) { |
| base::FilePath path1 = temp_dir_.GetPath().AppendASCII("filename1"); |
| base::FilePath path2 = temp_dir_.GetPath().AppendASCII("filename2"); |
| CreateFile(path1, kFileContent1); |
| GrantAccess(path1, kRendererProcessId); |
| GrantAccess(path2, kRendererProcessId); |
| |
| UploadResponse response; |
| client_.OnFileUploadRequested(kRendererProcessId, false, {path1, path2}, |
| std::move(response.callback)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(net::ERR_FILE_NOT_FOUND, response.error_code); |
| EXPECT_EQ(0U, response.opened_files.size()); |
| } |
| |
| TEST_F(NetworkContextClientBaseTest, UploadFromBrowserProcess) { |
| base::FilePath path = temp_dir_.GetPath().AppendASCII("filename"); |
| CreateFile(path, kFileContent1); |
| // No grant necessary for browser process. |
| |
| UploadResponse response; |
| client_.OnFileUploadRequested(kBrowserProcessId, false, {path}, |
| std::move(response.callback)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(net::OK, response.error_code); |
| ASSERT_EQ(1U, response.opened_files.size()); |
| ValidateFileContents(response.opened_files[0], kFileContent1); |
| } |
| |
| } // namespace content |