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

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 10 matching lines...) Expand all
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
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"
dcheng 2017/05/06 01:17:00 Nit: I think this can also be removed
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, DisableFormElements) {
307 String mhtml = GenerateMHTMLFromHtml("http://www.test.com", "form.html");
308
309 const char kDisabledAttr[] = "disabled=3D\"\"";
310 int matches =
311 MatchSubstring(mhtml, kDisabledAttr, arraysize(kDisabledAttr) - 1);
312 EXPECT_EQ(21, matches);
313 }
314
315 TEST_F(WebFrameSerializerSanitizationTest, RemoveHiddenElements) {
316 String mhtml =
317 GenerateMHTMLFromHtml("http://www.test.com", "hidden_elements.html");
318
319 // The element with hidden attribute should be removed.
320 EXPECT_EQ(WTF::kNotFound, mhtml.Find("<p id=3D\"hidden_id\""));
321
322 // The hidden form element should be removed.
323 EXPECT_EQ(WTF::kNotFound, mhtml.Find("<input type=3D\"hidden\""));
324
325 // All other hidden elements should not be removed.
326 EXPECT_NE(WTF::kNotFound, mhtml.Find("<html"));
327 EXPECT_NE(WTF::kNotFound, mhtml.Find("<head"));
328 EXPECT_NE(WTF::kNotFound, mhtml.Find("<style"));
329 EXPECT_NE(WTF::kNotFound, mhtml.Find("<title"));
330 EXPECT_NE(WTF::kNotFound, mhtml.Find("<h1"));
331 EXPECT_NE(WTF::kNotFound, mhtml.Find("<h2"));
332 EXPECT_NE(WTF::kNotFound, mhtml.Find("<datalist"));
333 EXPECT_NE(WTF::kNotFound, mhtml.Find("<option"));
334 // One for meta in head and another for meta in body.
335 EXPECT_EQ(2, MatchSubstring(mhtml, "<meta", 5));
336 // One for style in head and another for style in body.
337 EXPECT_EQ(2, MatchSubstring(mhtml, "<style", 6));
338 // One for link in head and another for link in body.
339 EXPECT_EQ(2, MatchSubstring(mhtml, "<link", 5));
340
341 // These visible elements should remain intact.
342 EXPECT_NE(WTF::kNotFound, mhtml.Find("<p id=3D\"visible_id\""));
343 EXPECT_NE(WTF::kNotFound, mhtml.Find("<form"));
344 EXPECT_NE(WTF::kNotFound, mhtml.Find("<input type=3D\"text\""));
345 EXPECT_NE(WTF::kNotFound, mhtml.Find("<div"));
346 }
347
348 // Regression test for crbug.com/678893, where in some cases serializing an
349 // image document could cause code to pick an element from an empty container.
350 TEST_F(WebFrameSerializerSanitizationTest, FromBrokenImageDocument) {
351 // This test only cares that the result of the parts generation is empty so it
352 // is simpler to not generate only that instead of the full MHTML.
353 String mhtml =
354 GenerateMHTMLPartsFromPng("http://www.test.com", "broken-image.png");
355 EXPECT_TRUE(mhtml.IsEmpty());
356 }
357
358 TEST_F(WebFrameSerializerSanitizationTest, ImageLoadedFromSrcsetForHiDPI) {
359 RegisterMockedFileURLLoad(
360 KURL(kParsedURLString, "http://www.test.com/1x.png"),
361 "frameserialization/1x.png");
362 RegisterMockedFileURLLoad(
363 KURL(kParsedURLString, "http://www.test.com/2x.png"),
364 "frameserialization/2x.png");
365
366 // Set high DPR in order to load image from srcset, instead of src.
367 WebView()->SetDeviceScaleFactor(2.0f);
368
369 String mhtml =
370 GenerateMHTMLFromHtml("http://www.test.com", "img_srcset.html");
371
372 // srcset attribute should be skipped.
373 EXPECT_EQ(WTF::kNotFound, mhtml.Find("srcset="));
374
375 // Width and height attributes should be set when none is present in <img>.
376 EXPECT_NE(WTF::kNotFound,
377 mhtml.Find("id=3D\"i1\" width=3D\"6\" height=3D\"6\">"));
378
379 // Height attribute should not be set if width attribute is already present in
380 // <img>
381 EXPECT_NE(WTF::kNotFound, mhtml.Find("id=3D\"i2\" width=3D\"8\">"));
382 }
383
384 TEST_F(WebFrameSerializerSanitizationTest, ImageLoadedFromSrcForNormalDPI) {
385 RegisterMockedFileURLLoad(
386 KURL(kParsedURLString, "http://www.test.com/1x.png"),
387 "frameserialization/1x.png");
388 RegisterMockedFileURLLoad(
389 KURL(kParsedURLString, "http://www.test.com/2x.png"),
390 "frameserialization/2x.png");
391
392 String mhtml =
393 GenerateMHTMLFromHtml("http://www.test.com", "img_srcset.html");
394
395 // srcset attribute should be skipped.
396 EXPECT_EQ(WTF::kNotFound, mhtml.Find("srcset="));
397
398 // New width and height attributes should not be set.
399 EXPECT_NE(WTF::kNotFound, mhtml.Find("id=3D\"i1\">"));
400 EXPECT_NE(WTF::kNotFound, mhtml.Find("id=3D\"i2\" width=3D\"8\">"));
401 }
402
403 TEST_F(WebFrameSerializerSanitizationTest, RemovePopupOverlayIfRequested) {
404 WebView()->Resize(WebSize(500, 500));
405 SetRemovePopupOverlay(true);
406 String mhtml = GenerateMHTMLFromHtml("http://www.test.com", "popup.html");
407 EXPECT_EQ(WTF::kNotFound, mhtml.Find("class=3D\"overlay"));
408 EXPECT_EQ(WTF::kNotFound, mhtml.Find("class=3D\"modal"));
409 histogram_tester_.ExpectUniqueSample(
410 "PageSerialization.MhtmlGeneration.PopupOverlaySkipped", true, 1);
411 }
412
413 TEST_F(WebFrameSerializerSanitizationTest, PopupOverlayNotFound) {
414 WebView()->Resize(WebSize(500, 500));
415 SetRemovePopupOverlay(true);
416 String mhtml =
417 GenerateMHTMLFromHtml("http://www.test.com", "text_only_page.html");
418 histogram_tester_.ExpectUniqueSample(
419 "PageSerialization.MhtmlGeneration.PopupOverlaySkipped", false, 1);
420 }
421
422 TEST_F(WebFrameSerializerSanitizationTest, KeepPopupOverlayIfNotRequested) {
423 WebView()->Resize(WebSize(500, 500));
424 SetRemovePopupOverlay(false);
425 String mhtml = GenerateMHTMLFromHtml("http://www.test.com", "popup.html");
426 EXPECT_NE(WTF::kNotFound, mhtml.Find("class=3D\"overlay"));
427 EXPECT_NE(WTF::kNotFound, mhtml.Find("class=3D\"modal"));
428 histogram_tester_.ExpectTotalCount(
429 "PageSerialization.MhtmlGeneration.PopupOverlaySkipped", 0);
430 }
431
432 TEST_F(WebFrameSerializerSanitizationTest, RemoveElements) {
433 String mhtml =
434 GenerateMHTMLFromHtml("http://www.test.com", "remove_elements.html");
435
436 EXPECT_EQ(WTF::kNotFound, mhtml.Find("<script"));
437 EXPECT_EQ(WTF::kNotFound, mhtml.Find("<noscript"));
438
439 // Only the meta element containing "Content-Security-Policy" is removed.
440 // Other meta elements should be preserved.
441 EXPECT_EQ(WTF::kNotFound,
442 mhtml.Find("<meta http-equiv=3D\"Content-Security-Policy"));
443 EXPECT_NE(WTF::kNotFound, mhtml.Find("<meta name=3D\"description"));
444 EXPECT_NE(WTF::kNotFound, mhtml.Find("<meta http-equiv=3D\"refresh"));
445
446 // If an element is removed, its children should also be skipped.
447 EXPECT_EQ(WTF::kNotFound, mhtml.Find("<select"));
448 EXPECT_EQ(WTF::kNotFound, mhtml.Find("<option"));
449 }
450
451 } // 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