| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/image_decoder.h" | 5 #include "chrome/browser/image_decoder.h" |
| 6 | 6 |
| 7 #include "base/macros.h" | 7 #include "base/macros.h" |
| 8 #include "build/build_config.h" | 8 #include "build/build_config.h" |
| 9 #include "chrome/grit/generated_resources.h" | 9 #include "chrome/grit/generated_resources.h" |
| 10 #include "chrome/test/base/in_process_browser_test.h" | 10 #include "chrome/test/base/in_process_browser_test.h" |
| 11 #include "content/public/browser/browser_child_process_observer.h" | 11 #include "content/public/browser/browser_child_process_observer.h" |
| 12 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
| 13 #include "content/public/browser/child_process_data.h" | 13 #include "content/public/browser/child_process_data.h" |
| 14 #include "content/public/test/test_utils.h" | 14 #include "content/public/test/test_utils.h" |
| 15 #include "ui/base/l10n/l10n_util.h" | 15 #include "ui/base/l10n/l10n_util.h" |
| 16 | 16 |
| 17 using content::BrowserThread; | 17 using content::BrowserThread; |
| 18 | 18 |
| 19 namespace { | 19 namespace { |
| 20 | 20 |
| 21 std::string GetValidPngString() { | 21 std::vector<uint8_t> GetValidPngData() { |
| 22 // 1x1 PNG. Does not get much smaller than this. | 22 // 1x1 PNG. Does not get much smaller than this. |
| 23 static const char kPngData[] = | 23 static const char kPngData[] = |
| 24 "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" | 24 "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" |
| 25 "\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90\x77\x53" | 25 "\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90\x77\x53" |
| 26 "\xde\x00\x00\x00\x0c\x49\x44\x41\x54\x08\xd7\x63\xf8\xff\xff\x3f" | 26 "\xde\x00\x00\x00\x0c\x49\x44\x41\x54\x08\xd7\x63\xf8\xff\xff\x3f" |
| 27 "\x00\x05\xfe\x02\xfe\xdc\xcc\x59\xe7\x00\x00\x00\x00\x49\x45\x4e" | 27 "\x00\x05\xfe\x02\xfe\xdc\xcc\x59\xe7\x00\x00\x00\x00\x49\x45\x4e" |
| 28 "\x44\xae\x42\x60\x82"; | 28 "\x44\xae\x42\x60\x82"; |
| 29 // Need to specify the buffer size because it contains NULs. | 29 // Need to specify the buffer size because it contains NULs. |
| 30 return std::string(kPngData, sizeof(kPngData) - 1); | 30 return std::vector<uint8_t>(kPngData, kPngData + sizeof(kPngData) - 1); |
| 31 } | 31 } |
| 32 | 32 |
| 33 #if defined(OS_CHROMEOS) | 33 #if defined(OS_CHROMEOS) |
| 34 | 34 |
| 35 std::string GetValidJpgString() { | 35 std::vector<uint8_t> GetValidJpgData() { |
| 36 // 1x1 JPG created from the 1x1 PNG above. | 36 // 1x1 JPG created from the 1x1 PNG above. |
| 37 static const char kJpgData[] = | 37 static const char kJpgData[] = |
| 38 "\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00\x01\x01\x01\x00\x48" | 38 "\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00\x01\x01\x01\x00\x48" |
| 39 "\x00\x48\x00\x00\xFF\xDB\x00\x43\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF" | 39 "\x00\x48\x00\x00\xFF\xDB\x00\x43\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF" |
| 40 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" | 40 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" |
| 41 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" | 41 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" |
| 42 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" | 42 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" |
| 43 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xDB\x00\x43\x01\xFF\xFF" | 43 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xDB\x00\x43\x01\xFF\xFF" |
| 44 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" | 44 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" |
| 45 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" | 45 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" |
| 46 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" | 46 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" |
| 47 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC0" | 47 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC0" |
| 48 "\x00\x11\x08\x00\x01\x00\x01\x03\x01\x22\x00\x02\x11\x01\x03\x11" | 48 "\x00\x11\x08\x00\x01\x00\x01\x03\x01\x22\x00\x02\x11\x01\x03\x11" |
| 49 "\x01\xFF\xC4\x00\x15\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00" | 49 "\x01\xFF\xC4\x00\x15\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00" |
| 50 "\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xC4\x00\x14\x10\x01\x00\x00" | 50 "\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xC4\x00\x14\x10\x01\x00\x00" |
| 51 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xC4" | 51 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xC4" |
| 52 "\x00\x14\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | 52 "\x00\x14\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" |
| 53 "\x00\x00\x00\x00\xFF\xC4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00" | 53 "\x00\x00\x00\x00\xFF\xC4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00" |
| 54 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xDA\x00\x0C\x03\x01" | 54 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xDA\x00\x0C\x03\x01" |
| 55 "\x00\x02\x11\x03\x11\x00\x3F\x00\xA0\x00\xFF\xD9"; | 55 "\x00\x02\x11\x03\x11\x00\x3F\x00\xA0\x00\xFF\xD9"; |
| 56 // Need to specify the buffer size because it contains NULs. | 56 // Need to specify the buffer size because it contains NULs. |
| 57 return std::string(kJpgData, sizeof(kJpgData) - 1); | 57 return std::vector<uint8_t>(kJpgData, kJpgData + sizeof(kJpgData) - 1); |
| 58 } | 58 } |
| 59 | 59 |
| 60 #endif // defined(OS_CHROMEOS) | 60 #endif // defined(OS_CHROMEOS) |
| 61 | 61 |
| 62 class TestImageRequest : public ImageDecoder::ImageRequest { | 62 class TestImageRequest : public ImageDecoder::ImageRequest { |
| 63 public: | 63 public: |
| 64 explicit TestImageRequest(const base::Closure& quit_closure) | 64 explicit TestImageRequest(const base::Closure& quit_closure) |
| 65 : decode_succeeded_(false), | 65 : decode_succeeded_(false), |
| 66 quit_closure_(quit_closure), | 66 quit_closure_(quit_closure), |
| 67 quit_called_(false) { | 67 quit_called_(false) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 | 156 |
| 157 } // namespace | 157 } // namespace |
| 158 | 158 |
| 159 class ImageDecoderBrowserTest : public InProcessBrowserTest { | 159 class ImageDecoderBrowserTest : public InProcessBrowserTest { |
| 160 }; | 160 }; |
| 161 | 161 |
| 162 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, Basic) { | 162 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, Basic) { |
| 163 scoped_refptr<content::MessageLoopRunner> runner = | 163 scoped_refptr<content::MessageLoopRunner> runner = |
| 164 new content::MessageLoopRunner; | 164 new content::MessageLoopRunner; |
| 165 TestImageRequest test_request(runner->QuitClosure()); | 165 TestImageRequest test_request(runner->QuitClosure()); |
| 166 ImageDecoder::Start(&test_request, std::string()); | 166 ImageDecoder::Start(&test_request, std::vector<uint8_t>()); |
| 167 runner->Run(); | 167 runner->Run(); |
| 168 EXPECT_FALSE(test_request.decode_succeeded()); | 168 EXPECT_FALSE(test_request.decode_succeeded()); |
| 169 } | 169 } |
| 170 | 170 |
| 171 #if defined(OS_CHROMEOS) | 171 #if defined(OS_CHROMEOS) |
| 172 | 172 |
| 173 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, BasicDecodeWithOptionsString) { |
| 174 scoped_refptr<content::MessageLoopRunner> runner = |
| 175 new content::MessageLoopRunner; |
| 176 TestImageRequest test_request(runner->QuitClosure()); |
| 177 const std::vector<uint8_t> data = GetValidPngData(); |
| 178 ImageDecoder::StartWithOptions(&test_request, |
| 179 std::string(data.begin(), data.end()), |
| 180 ImageDecoder::ROBUST_PNG_CODEC, |
| 181 false /* shrink_to_fit */); |
| 182 runner->Run(); |
| 183 EXPECT_TRUE(test_request.decode_succeeded()); |
| 184 } |
| 185 |
| 173 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, RobustJpegCodecWithJpegData) { | 186 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, RobustJpegCodecWithJpegData) { |
| 174 scoped_refptr<content::MessageLoopRunner> runner = | 187 scoped_refptr<content::MessageLoopRunner> runner = |
| 175 new content::MessageLoopRunner; | 188 new content::MessageLoopRunner; |
| 176 TestImageRequest test_request(runner->QuitClosure()); | 189 TestImageRequest test_request(runner->QuitClosure()); |
| 177 ImageDecoder::StartWithOptions(&test_request, GetValidJpgString(), | 190 ImageDecoder::StartWithOptions(&test_request, GetValidJpgData(), |
| 178 ImageDecoder::ROBUST_JPEG_CODEC, | 191 ImageDecoder::ROBUST_JPEG_CODEC, |
| 179 false /* shrink_to_fit */); | 192 false /* shrink_to_fit */); |
| 180 runner->Run(); | 193 runner->Run(); |
| 181 EXPECT_TRUE(test_request.decode_succeeded()); | 194 EXPECT_TRUE(test_request.decode_succeeded()); |
| 182 } | 195 } |
| 183 | 196 |
| 184 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, RobustJpegCodecWithPngData) { | 197 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, RobustJpegCodecWithPngData) { |
| 185 scoped_refptr<content::MessageLoopRunner> runner = | 198 scoped_refptr<content::MessageLoopRunner> runner = |
| 186 new content::MessageLoopRunner; | 199 new content::MessageLoopRunner; |
| 187 TestImageRequest test_request(runner->QuitClosure()); | 200 TestImageRequest test_request(runner->QuitClosure()); |
| 188 ImageDecoder::StartWithOptions(&test_request, GetValidPngString(), | 201 ImageDecoder::StartWithOptions(&test_request, GetValidPngData(), |
| 189 ImageDecoder::ROBUST_JPEG_CODEC, | 202 ImageDecoder::ROBUST_JPEG_CODEC, |
| 190 false /* shrink_to_fit */); | 203 false /* shrink_to_fit */); |
| 191 runner->Run(); | 204 runner->Run(); |
| 192 // Should fail with PNG data because only JPEG data is allowed. | 205 // Should fail with PNG data because only JPEG data is allowed. |
| 193 EXPECT_FALSE(test_request.decode_succeeded()); | 206 EXPECT_FALSE(test_request.decode_succeeded()); |
| 194 } | 207 } |
| 195 | 208 |
| 196 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, RobustPngCodecWithPngData) { | 209 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, RobustPngCodecWithPngData) { |
| 197 scoped_refptr<content::MessageLoopRunner> runner = | 210 scoped_refptr<content::MessageLoopRunner> runner = |
| 198 new content::MessageLoopRunner; | 211 new content::MessageLoopRunner; |
| 199 TestImageRequest test_request(runner->QuitClosure()); | 212 TestImageRequest test_request(runner->QuitClosure()); |
| 200 ImageDecoder::StartWithOptions(&test_request, GetValidPngString(), | 213 ImageDecoder::StartWithOptions(&test_request, GetValidPngData(), |
| 201 ImageDecoder::ROBUST_PNG_CODEC, | 214 ImageDecoder::ROBUST_PNG_CODEC, |
| 202 false /* shrink_to_fit */); | 215 false /* shrink_to_fit */); |
| 203 runner->Run(); | 216 runner->Run(); |
| 204 EXPECT_TRUE(test_request.decode_succeeded()); | 217 EXPECT_TRUE(test_request.decode_succeeded()); |
| 205 } | 218 } |
| 206 | 219 |
| 207 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, RobustPngCodecWithJpegData) { | 220 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, RobustPngCodecWithJpegData) { |
| 208 scoped_refptr<content::MessageLoopRunner> runner = | 221 scoped_refptr<content::MessageLoopRunner> runner = |
| 209 new content::MessageLoopRunner; | 222 new content::MessageLoopRunner; |
| 210 TestImageRequest test_request(runner->QuitClosure()); | 223 TestImageRequest test_request(runner->QuitClosure()); |
| 211 ImageDecoder::StartWithOptions(&test_request, GetValidJpgString(), | 224 ImageDecoder::StartWithOptions(&test_request, GetValidJpgData(), |
| 212 ImageDecoder::ROBUST_PNG_CODEC, | 225 ImageDecoder::ROBUST_PNG_CODEC, |
| 213 false /* shrink_to_fit */); | 226 false /* shrink_to_fit */); |
| 214 runner->Run(); | 227 runner->Run(); |
| 215 // Should fail with JPEG data because only PNG data is allowed. | 228 // Should fail with JPEG data because only PNG data is allowed. |
| 216 EXPECT_FALSE(test_request.decode_succeeded()); | 229 EXPECT_FALSE(test_request.decode_succeeded()); |
| 217 } | 230 } |
| 218 | 231 |
| 219 #endif // defined(OS_CHROMEOS) | 232 #endif // defined(OS_CHROMEOS) |
| 220 | 233 |
| 221 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, BasicDecode) { | 234 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, BasicDecode) { |
| 222 scoped_refptr<content::MessageLoopRunner> runner = | 235 scoped_refptr<content::MessageLoopRunner> runner = |
| 223 new content::MessageLoopRunner; | 236 new content::MessageLoopRunner; |
| 224 TestImageRequest test_request(runner->QuitClosure()); | 237 TestImageRequest test_request(runner->QuitClosure()); |
| 225 ImageDecoder::Start(&test_request, GetValidPngString()); | 238 ImageDecoder::Start(&test_request, GetValidPngData()); |
| 226 runner->Run(); | 239 runner->Run(); |
| 227 EXPECT_TRUE(test_request.decode_succeeded()); | 240 EXPECT_TRUE(test_request.decode_succeeded()); |
| 228 } | 241 } |
| 242 |
| 243 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, BasicDecodeString) { |
| 244 scoped_refptr<content::MessageLoopRunner> runner = |
| 245 new content::MessageLoopRunner; |
| 246 TestImageRequest test_request(runner->QuitClosure()); |
| 247 const std::vector<uint8_t> data = GetValidPngData(); |
| 248 ImageDecoder::Start(&test_request, std::string(data.begin(), data.end())); |
| 249 runner->Run(); |
| 250 EXPECT_TRUE(test_request.decode_succeeded()); |
| 251 } |
| 229 | 252 |
| 230 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndDestroy) { | 253 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndDestroy) { |
| 231 scoped_refptr<content::MessageLoopRunner> runner = | 254 scoped_refptr<content::MessageLoopRunner> runner = |
| 232 new content::MessageLoopRunner; | 255 new content::MessageLoopRunner; |
| 233 std::unique_ptr<TestImageRequest> test_request( | 256 std::unique_ptr<TestImageRequest> test_request( |
| 234 new TestImageRequest(runner->QuitClosure())); | 257 new TestImageRequest(runner->QuitClosure())); |
| 235 ImageDecoder::Start(test_request.get(), std::string()); | 258 ImageDecoder::Start(test_request.get(), std::vector<uint8_t>()); |
| 236 test_request.reset(); | 259 test_request.reset(); |
| 237 runner->Run(); | 260 runner->Run(); |
| 238 } | 261 } |
| 239 | 262 |
| 240 // Killing the utility process counts as a crash. Thus the request fails. | 263 // Killing the utility process counts as a crash. Thus the request fails. |
| 241 // If ImageDecoder did not handle the crash properly, the request never finishes | 264 // If ImageDecoder did not handle the crash properly, the request never finishes |
| 242 // and this test would hang. | 265 // and this test would hang. |
| 243 // Note: This test is inherently racy because KillProcessObserver lives on the | 266 // Note: This test is inherently racy because KillProcessObserver lives on the |
| 244 // UI thread but ImageDecoder does its work mainly on the IO thread. So the test | 267 // UI thread but ImageDecoder does its work mainly on the IO thread. So the test |
| 245 // checks for both possible valid outcomes. | 268 // checks for both possible valid outcomes. |
| 246 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndKillProcess) { | 269 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndKillProcess) { |
| 247 KillProcessObserver observer; | 270 KillProcessObserver observer; |
| 248 scoped_refptr<content::MessageLoopRunner> runner = | 271 scoped_refptr<content::MessageLoopRunner> runner = |
| 249 new content::MessageLoopRunner; | 272 new content::MessageLoopRunner; |
| 250 TestImageRequest test_request(runner->QuitClosure()); | 273 TestImageRequest test_request(runner->QuitClosure()); |
| 251 ImageDecoder::Start(&test_request, GetValidPngString()); | 274 ImageDecoder::Start(&test_request, GetValidPngData()); |
| 252 runner->Run(); | 275 runner->Run(); |
| 253 if (!test_request.decode_succeeded()) { | 276 if (!test_request.decode_succeeded()) { |
| 254 // The UI thread won the race. Make sure the utility process did get killed. | 277 // The UI thread won the race. Make sure the utility process did get killed. |
| 255 EXPECT_TRUE(observer.did_kill()); | 278 EXPECT_TRUE(observer.did_kill()); |
| 256 } | 279 } |
| 257 // Else the IO thread won the race and the image got decoded. Oh well. | 280 // Else the IO thread won the race and the image got decoded. Oh well. |
| 258 } | 281 } |
| OLD | NEW |