OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |