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