Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp

Issue 2858873007: Split WebFrameSerializerSanitizationTest into its own file. (Closed)
Patch Set: Rebase. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/web/tests/WebFrameSerializerSanitizationTest.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved. 2 * Copyright (C) 2017 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer 11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the 12 * in the documentation and/or other materials provided with the
(...skipping 11 matching lines...) Expand all
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31 #include "public/web/WebFrameSerializer.h" 31 #include "public/web/WebFrameSerializer.h"
32 32
33 #include "core/exported/WebViewBase.h" 33 #include "core/exported/WebViewBase.h"
34 #include "platform/mhtml/MHTMLArchive.h"
35 #include "platform/mhtml/MHTMLParser.h"
36 #include "platform/testing/HistogramTester.h"
37 #include "platform/testing/URLTestHelpers.h" 34 #include "platform/testing/URLTestHelpers.h"
38 #include "platform/testing/UnitTestHelpers.h" 35 #include "platform/testing/UnitTestHelpers.h"
39 #include "platform/weborigin/KURL.h" 36 #include "platform/weborigin/KURL.h"
40 #include "platform/wtf/text/StringBuilder.h" 37 #include "platform/wtf/text/StringBuilder.h"
41 #include "public/platform/Platform.h" 38 #include "public/platform/Platform.h"
42 #include "public/platform/WebCString.h" 39 #include "public/platform/WebCString.h"
43 #include "public/platform/WebCache.h"
44 #include "public/platform/WebString.h" 40 #include "public/platform/WebString.h"
45 #include "public/platform/WebURL.h" 41 #include "public/platform/WebURL.h"
46 #include "public/platform/WebURLLoaderMockFactory.h" 42 #include "public/platform/WebURLLoaderMockFactory.h"
47 #include "public/web/WebFrameSerializerClient.h" 43 #include "public/web/WebFrameSerializerClient.h"
48 #include "testing/gtest/include/gtest/gtest.h" 44 #include "testing/gtest/include/gtest/gtest.h"
49 #include "web/WebLocalFrameImpl.h" 45 #include "web/WebLocalFrameImpl.h"
50 #include "web/tests/FrameTestHelpers.h" 46 #include "web/tests/FrameTestHelpers.h"
51 47
52 namespace blink { 48 namespace blink {
53 49
54 namespace { 50 namespace {
51
55 class SimpleWebFrameSerializerClient final : public WebFrameSerializerClient { 52 class SimpleWebFrameSerializerClient final : public WebFrameSerializerClient {
56 public: 53 public:
57 String ToString() { return builder_.ToString(); } 54 String ToString() { return builder_.ToString(); }
58 55
59 private: 56 private:
60 void DidSerializeDataForFrame(const WebCString& data, 57 void DidSerializeDataForFrame(const WebCString& data,
61 FrameSerializationStatus) final { 58 FrameSerializationStatus) final {
62 builder_.Append(data.Data(), data.length()); 59 builder_.Append(data.Data(), data.length());
63 } 60 }
64 61
65 StringBuilder builder_; 62 StringBuilder builder_;
66 }; 63 };
67 64
68 class SimpleMHTMLPartsGenerationDelegate
69 : public WebFrameSerializer::MHTMLPartsGenerationDelegate {
70 public:
71 SimpleMHTMLPartsGenerationDelegate() : remove_popup_overlay_(false) {}
72
73 void SetRemovePopupOverlay(bool remove_popup_overlay) {
74 remove_popup_overlay_ = remove_popup_overlay;
75 }
76
77 private:
78 bool ShouldSkipResource(const WebURL&) final { return false; }
79
80 WebString GetContentID(WebFrame*) final { return WebString("<cid>"); }
81
82 WebFrameSerializerCacheControlPolicy CacheControlPolicy() final {
83 return WebFrameSerializerCacheControlPolicy::kNone;
84 }
85
86 bool UseBinaryEncoding() final { return false; }
87 bool RemovePopupOverlay() final { return remove_popup_overlay_; }
88
89 bool remove_popup_overlay_;
90 };
91
92 // Returns the count of match for substring |pattern| in string |str|.
93 int MatchSubstring(const String& str, const char* pattern, size_t size) {
94 int matches = 0;
95 size_t start = 0;
96 while (true) {
97 size_t pos = str.Find(pattern, start);
98 if (pos == WTF::kNotFound)
99 break;
100 matches++;
101 start = pos + size;
102 }
103 return matches;
104 }
105
106 } // namespace 65 } // namespace
107 66
108 class WebFrameSerializerTest : public ::testing::Test { 67 class WebFrameSerializerTest : public ::testing::Test {
109 protected: 68 protected:
110 WebFrameSerializerTest() { helper_.Initialize(); } 69 WebFrameSerializerTest() { helper_.Initialize(); }
111 70
112 ~WebFrameSerializerTest() override { 71 ~WebFrameSerializerTest() override {
113 Platform::Current() 72 Platform::Current()
114 ->GetURLLoaderMockFactory() 73 ->GetURLLoaderMockFactory()
115 ->UnregisterAllURLsAndClearMemoryCache(); 74 ->UnregisterAllURLsAndClearMemoryCache();
116 } 75 }
117 76
118 void RegisterMockedImageURLLoad(const String& url) { 77 void RegisterMockedImageURLLoad(const String& url) {
119 // Image resources need to be mocked, but irrelevant here what image they 78 // Image resources need to be mocked, but irrelevant here what image they
120 // map to. 79 // map to.
121 RegisterMockedFileURLLoad(URLTestHelpers::ToKURL(url.Utf8().data()), 80 RegisterMockedFileURLLoad(URLTestHelpers::ToKURL(url.Utf8().data()),
122 "frameserialization/awesome.png"); 81 "frameserialization/awesome.png");
123 } 82 }
83
124 void RegisterMockedFileURLLoad(const KURL& url, 84 void RegisterMockedFileURLLoad(const KURL& url,
125 const String& file_path, 85 const String& file_path,
126 const String& mime_type = "image/png") { 86 const String& mime_type = "image/png") {
127 URLTestHelpers::RegisterMockedURLLoad( 87 URLTestHelpers::RegisterMockedURLLoad(
128 url, testing::WebTestDataPath(file_path.Utf8().data()), mime_type); 88 url, testing::WebTestDataPath(file_path.Utf8().data()), mime_type);
129 } 89 }
130 90
131 class SingleLinkRewritingDelegate 91 class SingleLinkRewritingDelegate
132 : public WebFrameSerializer::LinkRewritingDelegate { 92 : public WebFrameSerializer::LinkRewritingDelegate {
133 public: 93 public:
(...skipping 23 matching lines...) Expand all
157 String file_path("frameserialization/" + file_name); 117 String file_path("frameserialization/" + file_name);
158 RegisterMockedFileURLLoad(parsed_url, file_path, "text/html"); 118 RegisterMockedFileURLLoad(parsed_url, file_path, "text/html");
159 FrameTestHelpers::LoadFrame(MainFrameImpl(), url.Utf8().data()); 119 FrameTestHelpers::LoadFrame(MainFrameImpl(), url.Utf8().data());
160 SingleLinkRewritingDelegate delegate(parsed_url, WebString("local")); 120 SingleLinkRewritingDelegate delegate(parsed_url, WebString("local"));
161 SimpleWebFrameSerializerClient serializer_client; 121 SimpleWebFrameSerializerClient serializer_client;
162 WebFrameSerializer::Serialize(MainFrameImpl(), &serializer_client, 122 WebFrameSerializer::Serialize(MainFrameImpl(), &serializer_client,
163 &delegate); 123 &delegate);
164 return serializer_client.ToString(); 124 return serializer_client.ToString();
165 } 125 }
166 126
167 WebViewBase* WebView() { return helper_.WebView(); }
168
169 WebLocalFrameImpl* MainFrameImpl() { 127 WebLocalFrameImpl* MainFrameImpl() {
170 return helper_.WebView()->MainFrameImpl(); 128 return helper_.WebView()->MainFrameImpl();
171 } 129 }
172 130
173 private: 131 private:
174 FrameTestHelpers::WebViewHelper helper_; 132 FrameTestHelpers::WebViewHelper helper_;
175 }; 133 };
176 134
177 TEST_F(WebFrameSerializerTest, URLAttributeValues) { 135 TEST_F(WebFrameSerializerTest, URLAttributeValues) {
178 RegisterMockedImageURLLoad("javascript:\""); 136 RegisterMockedImageURLLoad("javascript:\"");
(...skipping 29 matching lines...) Expand all
208 EXPECT_EQ(expected_html, actual_html); 166 EXPECT_EQ(expected_html, actual_html);
209 } 167 }
210 168
211 TEST_F(WebFrameSerializerTest, FromUrlWithMinusMinus) { 169 TEST_F(WebFrameSerializerTest, FromUrlWithMinusMinus) {
212 String actual_html = 170 String actual_html =
213 SerializeFile("http://www.test.com?--x--", "text_only_page.html"); 171 SerializeFile("http://www.test.com?--x--", "text_only_page.html");
214 EXPECT_EQ("<!-- saved from url=(0030)http://www.test.com/?-%2Dx-%2D -->", 172 EXPECT_EQ("<!-- saved from url=(0030)http://www.test.com/?-%2Dx-%2D -->",
215 actual_html.Substring(1, 60)); 173 actual_html.Substring(1, 60));
216 } 174 }
217 175
218 class WebFrameSerializerSanitizationTest : public WebFrameSerializerTest {
219 protected:
220 WebFrameSerializerSanitizationTest() {}
221
222 ~WebFrameSerializerSanitizationTest() override {}
223
224 String GenerateMHTMLFromHtml(const String& url, const String& file_name) {
225 return GenerateMHTML(url, file_name, "text/html", false);
226 }
227
228 String GenerateMHTMLPartsFromPng(const String& url, const String& file_name) {
229 return GenerateMHTML(url, file_name, "image/png", true);
230 }
231
232 String GenerateMHTML(const String& url,
233 const String& file_name,
234 const String& mime_type,
235 const bool only_body_parts) {
236 KURL parsed_url(kParsedURLString, url);
237 String file_path("frameserialization/" + file_name);
238 RegisterMockedFileURLLoad(parsed_url, file_path, mime_type);
239 FrameTestHelpers::LoadFrame(MainFrameImpl(), url.Utf8().data());
240 // Boundaries are normally randomly generated but this one is predefined for
241 // simplicity and as good as any other. Plus it gets used in almost all the
242 // examples in the MHTML spec - RFC 2557.
243 const WebString boundary("boundary-example");
244 StringBuilder mhtml;
245 if (!only_body_parts) {
246 WebThreadSafeData header_result = WebFrameSerializer::GenerateMHTMLHeader(
247 boundary, MainFrameImpl(), &mhtml_delegate_);
248 mhtml.Append(header_result.Data(), header_result.size());
249 }
250
251 WebThreadSafeData body_result = WebFrameSerializer::GenerateMHTMLParts(
252 boundary, MainFrameImpl(), &mhtml_delegate_);
253 mhtml.Append(body_result.Data(), body_result.size());
254
255 if (!only_body_parts) {
256 RefPtr<RawData> footer_data = RawData::Create();
257 MHTMLArchive::GenerateMHTMLFooterForTesting(boundary,
258 *footer_data->MutableData());
259 mhtml.Append(footer_data->data(), footer_data->length());
260 }
261
262 String mhtml_string = mhtml.ToString();
263 if (!only_body_parts) {
264 // Validate the generated MHTML.
265 MHTMLParser parser(SharedBuffer::Create(mhtml_string.Characters8(),
266 size_t(mhtml_string.length())));
267 EXPECT_FALSE(parser.ParseArchive().IsEmpty())
268 << "Generated MHTML is not well formed";
269 }
270 return mhtml_string;
271 }
272
273 void SetRemovePopupOverlay(bool remove_popup_overlay) {
274 mhtml_delegate_.SetRemovePopupOverlay(remove_popup_overlay);
275 }
276
277 protected:
278 HistogramTester histogram_tester_;
279
280 private:
281 SimpleMHTMLPartsGenerationDelegate mhtml_delegate_;
282 };
283
284 TEST_F(WebFrameSerializerSanitizationTest, RemoveInlineScriptInAttributes) {
285 String mhtml =
286 GenerateMHTMLFromHtml("http://www.test.com", "script_in_attributes.html");
287
288 // These scripting attributes should be removed.
289 EXPECT_EQ(WTF::kNotFound, mhtml.Find("onload="));
290 EXPECT_EQ(WTF::kNotFound, mhtml.Find("ONLOAD="));
291 EXPECT_EQ(WTF::kNotFound, mhtml.Find("onclick="));
292 EXPECT_EQ(WTF::kNotFound, mhtml.Find("href="));
293 EXPECT_EQ(WTF::kNotFound, mhtml.Find("from="));
294 EXPECT_EQ(WTF::kNotFound, mhtml.Find("to="));
295 EXPECT_EQ(WTF::kNotFound, mhtml.Find("javascript:"));
296
297 // These non-scripting attributes should remain intact.
298 EXPECT_NE(WTF::kNotFound, mhtml.Find("class="));
299 EXPECT_NE(WTF::kNotFound, mhtml.Find("id="));
300
301 // srcdoc attribute of frame element should be replaced with src attribute.
302 EXPECT_EQ(WTF::kNotFound, mhtml.Find("srcdoc="));
303 EXPECT_NE(WTF::kNotFound, mhtml.Find("src="));
304 }
305
306 TEST_F(WebFrameSerializerSanitizationTest, RemoveOtherAttributes) {
307 String mhtml =
308 GenerateMHTMLFromHtml("http://www.test.com", "remove_attributes.html");
309 EXPECT_EQ(WTF::kNotFound, mhtml.Find("ping="));
310 }
311
312 TEST_F(WebFrameSerializerSanitizationTest, DisableFormElements) {
313 String mhtml = GenerateMHTMLFromHtml("http://www.test.com", "form.html");
314
315 const char kDisabledAttr[] = "disabled=3D\"\"";
316 int matches =
317 MatchSubstring(mhtml, kDisabledAttr, arraysize(kDisabledAttr) - 1);
318 EXPECT_EQ(21, matches);
319 }
320
321 TEST_F(WebFrameSerializerSanitizationTest, RemoveHiddenElements) {
322 String mhtml =
323 GenerateMHTMLFromHtml("http://www.test.com", "hidden_elements.html");
324
325 // The element with hidden attribute should be removed.
326 EXPECT_EQ(WTF::kNotFound, mhtml.Find("<p id=3D\"hidden_id\""));
327
328 // The hidden form element should be removed.
329 EXPECT_EQ(WTF::kNotFound, mhtml.Find("<input type=3D\"hidden\""));
330
331 // All other hidden elements should not be removed.
332 EXPECT_NE(WTF::kNotFound, mhtml.Find("<html"));
333 EXPECT_NE(WTF::kNotFound, mhtml.Find("<head"));
334 EXPECT_NE(WTF::kNotFound, mhtml.Find("<style"));
335 EXPECT_NE(WTF::kNotFound, mhtml.Find("<title"));
336 EXPECT_NE(WTF::kNotFound, mhtml.Find("<h1"));
337 EXPECT_NE(WTF::kNotFound, mhtml.Find("<h2"));
338 EXPECT_NE(WTF::kNotFound, mhtml.Find("<datalist"));
339 EXPECT_NE(WTF::kNotFound, mhtml.Find("<option"));
340 // One for meta in head and another for meta in body.
341 EXPECT_EQ(2, MatchSubstring(mhtml, "<meta", 5));
342 // One for style in head and another for style in body.
343 EXPECT_EQ(2, MatchSubstring(mhtml, "<style", 6));
344 // One for link in head and another for link in body.
345 EXPECT_EQ(2, MatchSubstring(mhtml, "<link", 5));
346
347 // These visible elements should remain intact.
348 EXPECT_NE(WTF::kNotFound, mhtml.Find("<p id=3D\"visible_id\""));
349 EXPECT_NE(WTF::kNotFound, mhtml.Find("<form"));
350 EXPECT_NE(WTF::kNotFound, mhtml.Find("<input type=3D\"text\""));
351 EXPECT_NE(WTF::kNotFound, mhtml.Find("<div"));
352 }
353
354 // Regression test for crbug.com/678893, where in some cases serializing an
355 // image document could cause code to pick an element from an empty container.
356 TEST_F(WebFrameSerializerSanitizationTest, FromBrokenImageDocument) {
357 // This test only cares that the result of the parts generation is empty so it
358 // is simpler to not generate only that instead of the full MHTML.
359 String mhtml =
360 GenerateMHTMLPartsFromPng("http://www.test.com", "broken-image.png");
361 EXPECT_TRUE(mhtml.IsEmpty());
362 }
363
364 TEST_F(WebFrameSerializerSanitizationTest, ImageLoadedFromSrcsetForHiDPI) {
365 RegisterMockedFileURLLoad(
366 KURL(kParsedURLString, "http://www.test.com/1x.png"),
367 "frameserialization/1x.png");
368 RegisterMockedFileURLLoad(
369 KURL(kParsedURLString, "http://www.test.com/2x.png"),
370 "frameserialization/2x.png");
371
372 // Set high DPR in order to load image from srcset, instead of src.
373 WebView()->SetDeviceScaleFactor(2.0f);
374
375 String mhtml =
376 GenerateMHTMLFromHtml("http://www.test.com", "img_srcset.html");
377
378 // srcset attribute should be skipped.
379 EXPECT_EQ(WTF::kNotFound, mhtml.Find("srcset="));
380
381 // Width and height attributes should be set when none is present in <img>.
382 EXPECT_NE(WTF::kNotFound,
383 mhtml.Find("id=3D\"i1\" width=3D\"6\" height=3D\"6\">"));
384
385 // Height attribute should not be set if width attribute is already present in
386 // <img>
387 EXPECT_NE(WTF::kNotFound, mhtml.Find("id=3D\"i2\" width=3D\"8\">"));
388 }
389
390 TEST_F(WebFrameSerializerSanitizationTest, ImageLoadedFromSrcForNormalDPI) {
391 RegisterMockedFileURLLoad(
392 KURL(kParsedURLString, "http://www.test.com/1x.png"),
393 "frameserialization/1x.png");
394 RegisterMockedFileURLLoad(
395 KURL(kParsedURLString, "http://www.test.com/2x.png"),
396 "frameserialization/2x.png");
397
398 String mhtml =
399 GenerateMHTMLFromHtml("http://www.test.com", "img_srcset.html");
400
401 // srcset attribute should be skipped.
402 EXPECT_EQ(WTF::kNotFound, mhtml.Find("srcset="));
403
404 // New width and height attributes should not be set.
405 EXPECT_NE(WTF::kNotFound, mhtml.Find("id=3D\"i1\">"));
406 EXPECT_NE(WTF::kNotFound, mhtml.Find("id=3D\"i2\" width=3D\"8\">"));
407 }
408
409 TEST_F(WebFrameSerializerSanitizationTest, RemovePopupOverlayIfRequested) {
410 WebView()->Resize(WebSize(500, 500));
411 SetRemovePopupOverlay(true);
412 String mhtml = GenerateMHTMLFromHtml("http://www.test.com", "popup.html");
413 EXPECT_EQ(WTF::kNotFound, mhtml.Find("class=3D\"overlay"));
414 EXPECT_EQ(WTF::kNotFound, mhtml.Find("class=3D\"modal"));
415 histogram_tester_.ExpectUniqueSample(
416 "PageSerialization.MhtmlGeneration.PopupOverlaySkipped", true, 1);
417 }
418
419 TEST_F(WebFrameSerializerSanitizationTest, PopupOverlayNotFound) {
420 WebView()->Resize(WebSize(500, 500));
421 SetRemovePopupOverlay(true);
422 String mhtml =
423 GenerateMHTMLFromHtml("http://www.test.com", "text_only_page.html");
424 histogram_tester_.ExpectUniqueSample(
425 "PageSerialization.MhtmlGeneration.PopupOverlaySkipped", false, 1);
426 }
427
428 TEST_F(WebFrameSerializerSanitizationTest, KeepPopupOverlayIfNotRequested) {
429 WebView()->Resize(WebSize(500, 500));
430 SetRemovePopupOverlay(false);
431 String mhtml = GenerateMHTMLFromHtml("http://www.test.com", "popup.html");
432 EXPECT_NE(WTF::kNotFound, mhtml.Find("class=3D\"overlay"));
433 EXPECT_NE(WTF::kNotFound, mhtml.Find("class=3D\"modal"));
434 histogram_tester_.ExpectTotalCount(
435 "PageSerialization.MhtmlGeneration.PopupOverlaySkipped", 0);
436 }
437
438 TEST_F(WebFrameSerializerSanitizationTest, RemoveElements) {
439 String mhtml =
440 GenerateMHTMLFromHtml("http://www.test.com", "remove_elements.html");
441
442 EXPECT_EQ(WTF::kNotFound, mhtml.Find("<script"));
443 EXPECT_EQ(WTF::kNotFound, mhtml.Find("<noscript"));
444
445 // Only the meta element containing "Content-Security-Policy" is removed.
446 // Other meta elements should be preserved.
447 EXPECT_EQ(WTF::kNotFound,
448 mhtml.Find("<meta http-equiv=3D\"Content-Security-Policy"));
449 EXPECT_NE(WTF::kNotFound, mhtml.Find("<meta name=3D\"description"));
450 EXPECT_NE(WTF::kNotFound, mhtml.Find("<meta http-equiv=3D\"refresh"));
451
452 // If an element is removed, its children should also be skipped.
453 EXPECT_EQ(WTF::kNotFound, mhtml.Find("<select"));
454 EXPECT_EQ(WTF::kNotFound, mhtml.Find("<option"));
455 }
456
457 } // namespace blink 176 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/web/tests/WebFrameSerializerSanitizationTest.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698