"Fossies" - the Fresh Open Source Software Archive 
Member "incubator-pagespeed-mod-1.14.36.1/net/instaweb/rewriter/add_instrumentation_filter_test.cc" (28 Feb 2020, 13246 Bytes) of package /linux/www/apache_httpd_modules/incubator-pagespeed-mod-1.14.36.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "add_instrumentation_filter_test.cc" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
1.13.35.2_vs_1.14.36.1.
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20
21 #include "net/instaweb/rewriter/public/add_instrumentation_filter.h"
22
23 #include "net/instaweb/http/public/request_context.h"
24 #include "net/instaweb/http/public/request_timing_info.h"
25 #include "net/instaweb/rewriter/public/rewrite_driver.h"
26 #include "net/instaweb/rewriter/public/rewrite_options.h"
27 #include "net/instaweb/rewriter/public/rewrite_test_base.h"
28 #include "net/instaweb/rewriter/public/server_context.h"
29 #include "pagespeed/kernel/base/escaping.h"
30 #include "pagespeed/kernel/base/gtest.h"
31 #include "pagespeed/kernel/base/null_message_handler.h"
32 #include "pagespeed/kernel/base/ref_counted_ptr.h"
33 #include "pagespeed/kernel/base/statistics.h"
34 #include "pagespeed/kernel/html/amp_document_filter.h"
35 #include "pagespeed/kernel/html/html_keywords.h"
36 #include "pagespeed/kernel/html/html_name.h"
37 #include "pagespeed/kernel/html/html_parse_test_base.h"
38 #include "pagespeed/kernel/http/google_url.h"
39 #include "pagespeed/kernel/http/http_names.h"
40 #include "pagespeed/kernel/http/response_headers.h"
41 #include "pagespeed/kernel/http/user_agent_matcher_test_base.h"
42
43 namespace net_instaweb {
44
45 class AddInstrumentationFilterTest : public RewriteTestBase {
46 protected:
47 AddInstrumentationFilterTest() {}
48
49 virtual void SetUp() {
50 options()->set_beacon_url("http://example.com/beacon?org=xxx");
51 AddInstrumentationFilter::InitStats(statistics());
52 options()->EnableFilter(RewriteOptions::kAddInstrumentation);
53 RewriteTestBase::SetUp();
54 report_unload_time_ = false;
55 xhtml_mode_ = false;
56 cdata_mode_ = false;
57 https_mode_ = false;
58 }
59
60 virtual bool AddBody() const { return false; }
61
62 void AddFilters() {
63 AddFiltersWithUserAgent(UserAgentMatcherTestBase::kChrome18UserAgent);
64 }
65
66 void AddFiltersWithUserAgent(StringPiece user_agent) {
67 SetCurrentUserAgent(user_agent);
68 SetDriverRequestHeaders();
69 rewrite_driver()->AddFilters();
70 }
71
72 void RunInjection() {
73 options()->set_report_unload_time(report_unload_time_);
74 AddFilters();
75 ParseUrl(GetTestUrl(),
76 "<head></head><head></head><body></body><body></body>");
77 EXPECT_EQ(1, statistics()->GetVariable(
78 AddInstrumentationFilter::kInstrumentationScriptAddedCount)->Get());
79 }
80
81 void SetMimetypeToXhtml() {
82 SetXhtmlMimetype();
83 xhtml_mode_ = !cdata_mode_;
84 }
85
86 void DoNotRelyOnContentType() {
87 cdata_mode_ = true;
88 server_context()->set_response_headers_finalized(false);
89 }
90
91 void AssumeHttps() {
92 https_mode_ = true;
93 }
94
95 GoogleString GetTestUrl() {
96 return StrCat((https_mode_ ? "https://example.com/" : kTestDomain),
97 "index.html?a&b");
98 }
99
100 GoogleString CreateInitString(StringPiece beacon_url,
101 StringPiece event,
102 StringPiece extra_params) {
103 GoogleString url;
104 EscapeToJsStringLiteral(rewrite_driver()->google_url().Spec(), false, &url);
105 GoogleString str = "pagespeed.addInstrumentationInit(";
106 StrAppend(&str, "'", beacon_url, "', ");
107 StrAppend(&str, "'", event, "', ");
108 StrAppend(&str, "'", extra_params, "', ");
109 StrAppend(&str, "'", url, "');");
110 return str;
111 }
112
113 bool report_unload_time_;
114 bool xhtml_mode_;
115 bool cdata_mode_;
116 bool https_mode_;
117 ResponseHeaders response_headers_;
118 };
119
120 TEST_F(AddInstrumentationFilterTest, ScriptInjection) {
121 RunInjection();
122 EXPECT_TRUE(output_buffer_.find(
123 CreateInitString(
124 options()->beacon_url().http, "load", "")) !=
125 GoogleString::npos);
126 }
127
128 TEST_F(AddInstrumentationFilterTest, ScriptInjectionWithNavigation) {
129 report_unload_time_ = true;
130 RunInjection();
131 EXPECT_TRUE(output_buffer_.find(
132 CreateInitString(
133 options()->beacon_url().http, "beforeunload", "")) !=
134 GoogleString::npos);
135 }
136
137 // Test an https fetch.
138 TEST_F(AddInstrumentationFilterTest, TestScriptInjectionWithHttps) {
139 AssumeHttps();
140 RunInjection();
141 EXPECT_TRUE(output_buffer_.find(
142 CreateInitString(
143 options()->beacon_url().https, "load", "")) !=
144 GoogleString::npos);
145 }
146
147 // Test an https fetch, reporting unload and using Xhtml
148 TEST_F(AddInstrumentationFilterTest,
149 TestScriptInjectionWithHttpsUnloadAndXhtml) {
150 SetMimetypeToXhtml();
151 AssumeHttps();
152 report_unload_time_ = true;
153 RunInjection();
154 EXPECT_TRUE(output_buffer_.find(
155 CreateInitString(
156 options()->beacon_url().https, "beforeunload", "")) !=
157 GoogleString::npos);
158 }
159
160 // Test that experiment id reporting is done correctly.
161 TEST_F(AddInstrumentationFilterTest, TestExperimentIdReporting) {
162 NullMessageHandler handler;
163 options()->set_running_experiment(true);
164 options()->AddExperimentSpec("id=2;percent=10;slot=4;", &handler);
165 options()->AddExperimentSpec("id=7;percent=10;level=CoreFilters;slot=4;",
166 &handler);
167 options()->SetExperimentState(2);
168 RunInjection();
169 EXPECT_TRUE(output_buffer_.find(
170 CreateInitString(
171 options()->beacon_url().http, "load", "&exptid=2")) !=
172 GoogleString::npos);
173 }
174
175 // Test that extended instrumentation is injected properly.
176 TEST_F(AddInstrumentationFilterTest, TestExtendedInstrumentation) {
177 options()->set_enable_extended_instrumentation(true);
178 RunInjection();
179 EXPECT_TRUE(output_buffer_.find(
180 CreateInitString(
181 options()->beacon_url().http, "load", "")) !=
182 GoogleString::npos);
183 EXPECT_TRUE(output_buffer_.find("getResourceTimingData=function()") !=
184 GoogleString::npos);
185 }
186
187 // Test that headers fetch timing reporting is done correctly.
188 TEST_F(AddInstrumentationFilterTest, TestHeadersFetchTimingReporting) {
189 RequestTimingInfo* timing_info = mutable_timing_info();
190 timing_info->FetchStarted();
191 AdvanceTimeMs(200);
192 timing_info->FetchHeaderReceived();
193 AdvanceTimeMs(100);
194 timing_info->FirstByteReturned();
195 AdvanceTimeMs(200);
196 timing_info->FetchFinished();
197 RunInjection();
198 EXPECT_TRUE(output_buffer_.find(
199 CreateInitString(
200 options()->beacon_url().http, "load", "&hft=200&ft=500&s_ttfb=300"))
201 != GoogleString::npos) << output_buffer_;
202 }
203
204 TEST_F(AddInstrumentationFilterTest, Quoting) {
205 AddFilters();
206 GoogleString url = "http://example.com/?');alert('foo)";
207 ParseUrl(url, "<head></head><body></body>");
208 EXPECT_EQ(GoogleString::npos,
209 output_buffer_.find("?');alert('foo)"));
210 }
211
212 // Test that head script is inserted after title and meta tags.
213 TEST_F(AddInstrumentationFilterTest, TestScriptAfterTitleAndMeta) {
214 AddFilters();
215 ParseUrl(GetTestUrl(),
216 "<head><meta name='abc' /><title></title></head><body></body>");
217 EXPECT_TRUE(output_buffer_.find(
218 "<head><meta name='abc' /><title></title><script"));
219 }
220
221 TEST_F(AddInstrumentationFilterTest, TestNon200Response) {
222 AddFilters();
223 response_headers_.set_status_code(HttpStatus::kForbidden);
224 rewrite_driver()->set_response_headers_ptr(&response_headers_);
225 ParseUrl(GetTestUrl(),
226 "<head></head><head></head><body></body><body></body>");
227 EXPECT_EQ(1, statistics()->GetVariable(
228 AddInstrumentationFilter::kInstrumentationScriptAddedCount)->Get());
229 EXPECT_TRUE(output_buffer_.find(
230 CreateInitString(
231 options()->beacon_url().http, "load", "&rc=403")) !=
232 GoogleString::npos);
233 }
234
235 TEST_F(AddInstrumentationFilterTest, TestRequestId) {
236 rewrite_driver()->request_context()->set_request_id(1234567890L);
237 RunInjection();
238 EXPECT_TRUE(output_buffer_.find(
239 CreateInitString(options()->beacon_url().http, "load",
240 "&id=1234567890")) != GoogleString::npos);
241 }
242
243 TEST_F(AddInstrumentationFilterTest, TestNoDeferInstrumentationScript) {
244 RunInjection();
245 EXPECT_TRUE(output_buffer_.find(
246 CreateInitString(
247 options()->beacon_url().http, "load", "")) !=
248 GoogleString::npos);
249 const StringPiece* nodefer =
250 HtmlKeywords::KeywordToString(HtmlName::kDataPagespeedNoDefer);
251 EXPECT_TRUE(output_buffer_.find(nodefer->as_string()) != GoogleString::npos);
252 }
253
254 TEST_F(AddInstrumentationFilterTest, TestDeferInstrumentationScript) {
255 rewrite_driver()->set_defer_instrumentation_script(true);
256 RunInjection();
257 EXPECT_TRUE(output_buffer_.find(
258 CreateInitString(
259 options()->beacon_url().http, "load", "")) !=
260 GoogleString::npos);
261 const StringPiece* nodefer =
262 HtmlKeywords::KeywordToString(HtmlName::kDataPagespeedNoDefer);
263 EXPECT_TRUE(output_buffer_.find(nodefer->as_string()) == GoogleString::npos);
264 }
265
266 TEST_F(AddInstrumentationFilterTest, TestDisableForBots) {
267 AddFiltersWithUserAgent(UserAgentMatcherTestBase::kGooglebotUserAgent);
268 ValidateNoChanges(GetTestUrl(),
269 "<head></head><head></head><body></body><body></body>");
270 }
271
272 // Test script tag and type attribute without pedantic filter
273 TEST_F(AddInstrumentationFilterTest, TestScriptTagTypeAttribute) {
274 options()->EnableFilter(RewriteOptions::kAddInstrumentation);
275 AddFilters();
276
277 SetupWriter();
278 rewrite_driver()->StartParse(kTestDomain);
279 rewrite_driver()->ParseText("<!DOCTYPE html><html><head></head><body>"
280 "<img src='Puzzle.jpg'/></body></html>");
281 rewrite_driver()->FinishParse();
282
283 // check html without type attribute in head
284 EXPECT_TRUE(output_buffer_.find(
285 "<script>window.mod_pagespeed_start") !=
286 StringPiece::npos);
287
288 // check html without type attribute in data-pagespeed-no-defer tag
289 EXPECT_TRUE(output_buffer_.find(
290 "<script data-pagespeed-no-defer>") !=
291 StringPiece::npos);
292 }
293
294 // Test script tag and type attribute with pedantic filter
295 TEST_F(AddInstrumentationFilterTest, TestScriptTagTypeAttributePedantic) {
296 options()->EnableFilter(RewriteOptions::kAddInstrumentation);
297 options()->EnableFilter(RewriteOptions::kPedantic);
298 AddFilters();
299
300 SetupWriter();
301 rewrite_driver()->StartParse(kTestDomain);
302 rewrite_driver()->ParseText("<!DOCTYPE html><html><head></head><body>"
303 "<img src='Puzzle.jpg'/></body></html>");
304 rewrite_driver()->FinishParse();
305
306 // check html with type attribute in head
307 EXPECT_TRUE(output_buffer_.find(
308 "<script type='text/javascript'>window.mod_pagespeed_start") !=
309 StringPiece::npos);
310
311 // check html with type attribute in data-pagespeed-no-defer tag
312 EXPECT_TRUE(output_buffer_.find(
313 "<script data-pagespeed-no-defer type=\"text/javascript\">")!=
314 StringPiece::npos);
315 }
316
317 const char kBeaconUrl[] = "http://example.com/beacon?org=xxx";
318
319 class AddInstrumentationAmpTest : public AddInstrumentationFilterTest {
320 protected:
321 void SetUp() override {
322 AddInstrumentationFilterTest::SetUp();
323 SetCurrentUserAgent(UserAgentMatcherTestBase::kIPhone4Safari);
324 options()->EnableFilter(RewriteOptions::kAddInstrumentation);
325 options()->set_beacon_url(kBeaconUrl);
326 options()->set_report_unload_time(true);
327 AddFilters();
328 }
329
330 void CheckInstrumentation(StringPiece html, bool expect_has_beacon) {
331 for (int i = 0, n = html.size(); i < n; ++i) {
332 if (rewrite_driver_->request_headers() == nullptr) {
333 SetDriverRequestHeaders();
334 }
335 SetupWriter();
336 rewrite_driver_->StartParse(
337 StringPrintf("http://example.com/amp_doc_%d.html", i));
338 rewrite_driver_->ParseText(html.substr(0, i));
339 rewrite_driver_->Flush();
340 rewrite_driver_->ParseText(html.substr(i));
341 rewrite_driver_->FinishParse();
342 EXPECT_EQ(expect_has_beacon,
343 output_buffer_.find(kBeaconUrl) != GoogleString::npos);
344 }
345 }
346
347 bool AddBody() const override { return false; }
348 bool AddHtmlTags() const override { return false; }
349 };
350
351 TEST_F(AddInstrumentationAmpTest, IsAmpHtml) {
352 CheckInstrumentation("<!doctype foo> <html amp><head/><body></body></html>",
353 false);
354 EXPECT_TRUE(rewrite_driver_->is_amp_document());
355 }
356
357 TEST_F(AddInstrumentationAmpTest, IsAmpLightningBolt) {
358 CheckInstrumentation(StrCat("<!doctype foo> <html ",
359 AmpDocumentFilter::kUtf8LightningBolt,
360 "><head/><body></body></html>"),
361 false);
362 EXPECT_TRUE(rewrite_driver_->is_amp_document());
363 }
364
365 TEST_F(AddInstrumentationAmpTest, IsNotAmp) {
366 CheckInstrumentation("<!doctype foo> <html><head/><body></body></html>",
367 true);
368 EXPECT_FALSE(rewrite_driver_->is_amp_document());
369 }
370
371 } // namespace net_instaweb