1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/public/browser/network_context_client_base.h"
6
7 #include "base/bind.h"
8 #include "base/files/file.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/path_service.h"
13 #include "base/test/task_environment.h"
14 #include "base/test/test_file_util.h"
15 #include "build/build_config.h"
16 #include "content/browser/child_process_security_policy_impl.h"
17 #include "content/public/test/browser_task_environment.h"
18 #include "content/public/test/test_browser_context.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace content {
22
23 namespace {
24
25 struct UploadResponse {
UploadResponsecontent::__anon6729f0ec0111::UploadResponse26 UploadResponse()
27 : callback(base::BindOnce(&UploadResponse::OnComplete,
28 base::Unretained(this))) {}
29
OnCompletecontent::__anon6729f0ec0111::UploadResponse30 void OnComplete(int error_code, std::vector<base::File> opened_files) {
31 this->error_code = error_code;
32 this->opened_files = std::move(opened_files);
33 }
34
35 network::mojom::NetworkContextClient::OnFileUploadRequestedCallback callback;
36 int error_code;
37 std::vector<base::File> opened_files;
38 };
39
GrantAccess(const base::FilePath & file,int process_id)40 void GrantAccess(const base::FilePath& file, int process_id) {
41 ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(process_id, file);
42 }
43
CreateFile(const base::FilePath & path,const char * content)44 void CreateFile(const base::FilePath& path, const char* content) {
45 base::File file(path, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
46 ASSERT_TRUE(file.IsValid());
47 int content_size = strlen(content);
48 int bytes_written = file.Write(0, content, content_size);
49 EXPECT_EQ(bytes_written, content_size);
50 }
51
ValidateFileContents(base::File & file,base::StringPiece expected_content)52 void ValidateFileContents(base::File& file,
53 base::StringPiece expected_content) {
54 int expected_length = expected_content.size();
55 ASSERT_EQ(file.GetLength(), expected_length);
56 char content[expected_length];
57 file.Read(0, content, expected_length);
58 EXPECT_EQ(0, strncmp(content, expected_content.data(), expected_length));
59 }
60
61 const int kBrowserProcessId = 0;
62 const int kRendererProcessId = 1;
63 const char kFileContent1[] = "test file content one";
64 const char kFileContent2[] = "test file content two";
65
66 } // namespace
67
68 class NetworkContextClientBaseTest : public testing::Test {
69 public:
NetworkContextClientBaseTest()70 NetworkContextClientBaseTest() {}
71
SetUp()72 void SetUp() override {
73 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
74 ChildProcessSecurityPolicyImpl::GetInstance()->Add(kRendererProcessId,
75 &browser_context_);
76 }
77
TearDown()78 void TearDown() override {
79 ChildProcessSecurityPolicyImpl::GetInstance()->Remove(kRendererProcessId);
80 }
81
82 protected:
83 BrowserTaskEnvironment task_environment_;
84 TestBrowserContext browser_context_;
85 NetworkContextClientBase client_;
86 base::ScopedTempDir temp_dir_;
87 };
88
TEST_F(NetworkContextClientBaseTest,UploadNoFiles)89 TEST_F(NetworkContextClientBaseTest, UploadNoFiles) {
90 UploadResponse response;
91 client_.OnFileUploadRequested(kRendererProcessId, true, {},
92 std::move(response.callback));
93 task_environment_.RunUntilIdle();
94 EXPECT_EQ(net::OK, response.error_code);
95 EXPECT_EQ(0U, response.opened_files.size());
96 }
97
TEST_F(NetworkContextClientBaseTest,UploadOneValidAsyncFile)98 TEST_F(NetworkContextClientBaseTest, UploadOneValidAsyncFile) {
99 base::FilePath path = temp_dir_.GetPath().AppendASCII("filename");
100 CreateFile(path, kFileContent1);
101 GrantAccess(path, kRendererProcessId);
102
103 UploadResponse response;
104 client_.OnFileUploadRequested(kRendererProcessId, true, {path},
105 std::move(response.callback));
106 task_environment_.RunUntilIdle();
107 EXPECT_EQ(net::OK, response.error_code);
108 ASSERT_EQ(1U, response.opened_files.size());
109 EXPECT_TRUE(response.opened_files[0].async());
110 }
111
TEST_F(NetworkContextClientBaseTest,UploadOneValidFile)112 TEST_F(NetworkContextClientBaseTest, UploadOneValidFile) {
113 base::FilePath path = temp_dir_.GetPath().AppendASCII("filename");
114 CreateFile(path, kFileContent1);
115 GrantAccess(path, kRendererProcessId);
116
117 UploadResponse response;
118 client_.OnFileUploadRequested(kRendererProcessId, false, {path},
119 std::move(response.callback));
120 task_environment_.RunUntilIdle();
121 EXPECT_EQ(net::OK, response.error_code);
122 ASSERT_EQ(1U, response.opened_files.size());
123 EXPECT_FALSE(response.opened_files[0].async());
124 ValidateFileContents(response.opened_files[0], kFileContent1);
125 }
126
127 #if defined(OS_ANDROID)
128 // Flakily fails on Android bots. See http://crbug.com/1027790
TEST_F(NetworkContextClientBaseTest,DISABLED_UploadOneValidFileWithContentUri)129 TEST_F(NetworkContextClientBaseTest,
130 DISABLED_UploadOneValidFileWithContentUri) {
131 base::FilePath image_path;
132 EXPECT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &image_path));
133 image_path = image_path.AppendASCII("content")
134 .AppendASCII("test")
135 .AppendASCII("data")
136 .AppendASCII("blank.jpg");
137 EXPECT_TRUE(base::PathExists(image_path));
138 base::FilePath content_path = base::InsertImageIntoMediaStore(image_path);
139 EXPECT_TRUE(content_path.IsContentUri());
140 EXPECT_TRUE(base::PathExists(content_path));
141 GrantAccess(content_path, kRendererProcessId);
142
143 UploadResponse response;
144 client_.OnFileUploadRequested(kRendererProcessId, false, {content_path},
145 std::move(response.callback));
146 task_environment_.RunUntilIdle();
147 EXPECT_EQ(net::OK, response.error_code);
148 ASSERT_EQ(1U, response.opened_files.size());
149 EXPECT_FALSE(response.opened_files[0].async());
150 std::string contents;
151 EXPECT_TRUE(base::ReadFileToString(image_path, &contents));
152 ValidateFileContents(response.opened_files[0], contents);
153 }
154 #endif
155
TEST_F(NetworkContextClientBaseTest,UploadTwoValidFiles)156 TEST_F(NetworkContextClientBaseTest, UploadTwoValidFiles) {
157 base::FilePath path1 = temp_dir_.GetPath().AppendASCII("filename1");
158 base::FilePath path2 = temp_dir_.GetPath().AppendASCII("filename2");
159 CreateFile(path1, kFileContent1);
160 CreateFile(path2, kFileContent2);
161 GrantAccess(path1, kRendererProcessId);
162 GrantAccess(path2, kRendererProcessId);
163
164 UploadResponse response;
165 client_.OnFileUploadRequested(kRendererProcessId, false, {path1, path2},
166 std::move(response.callback));
167 task_environment_.RunUntilIdle();
168 EXPECT_EQ(net::OK, response.error_code);
169 ASSERT_EQ(2U, response.opened_files.size());
170 ValidateFileContents(response.opened_files[0], kFileContent1);
171 ValidateFileContents(response.opened_files[1], kFileContent2);
172 }
173
TEST_F(NetworkContextClientBaseTest,UploadOneUnauthorizedFile)174 TEST_F(NetworkContextClientBaseTest, UploadOneUnauthorizedFile) {
175 base::FilePath path = temp_dir_.GetPath().AppendASCII("filename");
176 CreateFile(path, kFileContent1);
177
178 UploadResponse response;
179 client_.OnFileUploadRequested(kRendererProcessId, false, {path},
180 std::move(response.callback));
181 task_environment_.RunUntilIdle();
182 EXPECT_EQ(net::ERR_ACCESS_DENIED, response.error_code);
183 EXPECT_EQ(0U, response.opened_files.size());
184 }
185
TEST_F(NetworkContextClientBaseTest,UploadOneValidFileAndOneUnauthorized)186 TEST_F(NetworkContextClientBaseTest, UploadOneValidFileAndOneUnauthorized) {
187 base::FilePath path1 = temp_dir_.GetPath().AppendASCII("filename1");
188 base::FilePath path2 = temp_dir_.GetPath().AppendASCII("filename2");
189 CreateFile(path1, kFileContent1);
190 CreateFile(path2, kFileContent2);
191 GrantAccess(path1, kRendererProcessId);
192
193 UploadResponse response;
194 client_.OnFileUploadRequested(kRendererProcessId, false, {path1, path2},
195 std::move(response.callback));
196 task_environment_.RunUntilIdle();
197 EXPECT_EQ(net::ERR_ACCESS_DENIED, response.error_code);
198 EXPECT_EQ(0U, response.opened_files.size());
199 }
200
TEST_F(NetworkContextClientBaseTest,UploadOneValidFileAndOneNotFound)201 TEST_F(NetworkContextClientBaseTest, UploadOneValidFileAndOneNotFound) {
202 base::FilePath path1 = temp_dir_.GetPath().AppendASCII("filename1");
203 base::FilePath path2 = temp_dir_.GetPath().AppendASCII("filename2");
204 CreateFile(path1, kFileContent1);
205 GrantAccess(path1, kRendererProcessId);
206 GrantAccess(path2, kRendererProcessId);
207
208 UploadResponse response;
209 client_.OnFileUploadRequested(kRendererProcessId, false, {path1, path2},
210 std::move(response.callback));
211 task_environment_.RunUntilIdle();
212 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, response.error_code);
213 EXPECT_EQ(0U, response.opened_files.size());
214 }
215
TEST_F(NetworkContextClientBaseTest,UploadFromBrowserProcess)216 TEST_F(NetworkContextClientBaseTest, UploadFromBrowserProcess) {
217 base::FilePath path = temp_dir_.GetPath().AppendASCII("filename");
218 CreateFile(path, kFileContent1);
219 // No grant necessary for browser process.
220
221 UploadResponse response;
222 client_.OnFileUploadRequested(kBrowserProcessId, false, {path},
223 std::move(response.callback));
224 task_environment_.RunUntilIdle();
225 EXPECT_EQ(net::OK, response.error_code);
226 ASSERT_EQ(1U, response.opened_files.size());
227 ValidateFileContents(response.opened_files[0], kFileContent1);
228 }
229
230 } // namespace content
231