Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: test/WebRequest.cpp

Issue 29377825: Issue 4951 - Restrict request headers in XMLHttpRequest.Also test Accept-Encoding with th… (Closed) Base URL: https://hg.adblockplus.org/libadblockplus/
Patch Set: improve tests following feedback. Created March 3, 2017, 7:04 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/compat.js ('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 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2016 Eyeo GmbH 3 * Copyright (C) 2006-2016 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 19 matching lines...) Expand all
30 30
31 AdblockPlus::ServerResponse result; 31 AdblockPlus::ServerResponse result;
32 result.status = NS_OK; 32 result.status = NS_OK;
33 result.responseStatus = 123; 33 result.responseStatus = 123;
34 result.responseHeaders.push_back(std::pair<std::string, std::string>("Foo" , "Bar")); 34 result.responseHeaders.push_back(std::pair<std::string, std::string>("Foo" , "Bar"));
35 result.responseText = url + "\n" + requestHeaders[0].first + "\n" + reques tHeaders[0].second; 35 result.responseText = url + "\n" + requestHeaders[0].first + "\n" + reques tHeaders[0].second;
36 return result; 36 return result;
37 } 37 }
38 }; 38 };
39 39
40 class XHRTestWebRequest : public AdblockPlus::WebRequest
Felix Dahlke 2017/03/06 16:51:07 IMHO it'd make more sense to add lastRequestHeader
hub 2017/03/06 17:26:05 I can do that too. I was trying to avoid side effe
41 {
42 public:
43 AdblockPlus::ServerResponse GET(const std::string& url, const AdblockPlus::H eaderList& requestHeaders) const
44 {
45 lastRequestHeaders.clear();
46 for (auto header : requestHeaders)
47 {
48 lastRequestHeaders.insert(header.first);
49 }
50
51 AdblockPlus::ServerResponse result;
52 result.status = NS_OK;
53 result.responseStatus = 123;
54 result.responseHeaders.push_back(std::pair<std::string, std::string>("Foo" , "Bar"));
55 return result;
56 }
57
58 // mutable. Very Ugly. But we are testing.
59 mutable std::set<std::string> lastRequestHeaders;
60 };
61
40 template<class T> 62 template<class T>
41 class WebRequestTest : public BaseJsTest 63 class WebRequestTest : public BaseJsTest
42 { 64 {
43 protected: 65 protected:
44 void SetUp() 66 void SetUp()
45 { 67 {
46 BaseJsTest::SetUp(); 68 BaseJsTest::SetUp();
47 jsEngine->SetWebRequest(AdblockPlus::WebRequestPtr(new T)); 69 jsEngine->SetWebRequest(AdblockPlus::WebRequestPtr(new T));
48 jsEngine->SetFileSystem(AdblockPlus::FileSystemPtr(new LazyFileSystem)); 70 jsEngine->SetFileSystem(AdblockPlus::FileSystemPtr(new LazyFileSystem));
49 } 71 }
50 }; 72 };
51 73
52 typedef WebRequestTest<MockWebRequest> MockWebRequestTest; 74 typedef WebRequestTest<MockWebRequest> MockWebRequestTest;
53 typedef WebRequestTest<AdblockPlus::DefaultWebRequest> DefaultWebRequestTest; 75 typedef WebRequestTest<AdblockPlus::DefaultWebRequest> DefaultWebRequestTest;
76 typedef WebRequestTest<XHRTestWebRequest> XMLHttpRequestTest;
54 } 77 }
55 78
56 TEST_F(MockWebRequestTest, BadCall) 79 TEST_F(MockWebRequestTest, BadCall)
57 { 80 {
58 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET()")); 81 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET()"));
59 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET('', {}, function(){})")); 82 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET('', {}, function(){})"));
60 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET({toString: false}, {}, fu nction(){})")); 83 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET({toString: false}, {}, fu nction(){})"));
61 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET('http://example.com/', nu ll, function(){})")); 84 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET('http://example.com/', nu ll, function(){})"));
62 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET('http://example.com/', {} , null)")); 85 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET('http://example.com/', {} , null)"));
63 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET('http://example.com/', {} , function(){}, 0)")); 86 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET('http://example.com/', {} , function(){}, 0)"));
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 request.addEventListener('error', function() {result = 'error';}, false);\ 133 request.addEventListener('error', function() {result = 'error';}, false);\
111 request.send(null);"); 134 request.send(null);");
112 do 135 do
113 { 136 {
114 AdblockPlus::Sleep(200); 137 AdblockPlus::Sleep(200);
115 } while (jsEngine->Evaluate("result")->IsUndefined()); 138 } while (jsEngine->Evaluate("result")->IsUndefined());
116 ASSERT_EQ(AdblockPlus::WebRequest::NS_OK, jsEngine->Evaluate("request.channel. status")->AsInt()); 139 ASSERT_EQ(AdblockPlus::WebRequest::NS_OK, jsEngine->Evaluate("request.channel. status")->AsInt());
117 ASSERT_EQ(200, jsEngine->Evaluate("request.status")->AsInt()); 140 ASSERT_EQ(200, jsEngine->Evaluate("request.status")->AsInt());
118 ASSERT_EQ("[Adblock Plus ", jsEngine->Evaluate("result.substr(0, 14)")->AsStri ng()); 141 ASSERT_EQ("[Adblock Plus ", jsEngine->Evaluate("result.substr(0, 14)")->AsStri ng());
119 ASSERT_EQ("text/plain", jsEngine->Evaluate("request.getResponseHeader('Content -Type').substr(0, 10)")->AsString()); 142 ASSERT_EQ("text/plain", jsEngine->Evaluate("request.getResponseHeader('Content -Type').substr(0, 10)")->AsString());
143 #if defined(HAVE_CURL)
144 ASSERT_EQ("gzip", jsEngine->Evaluate("request.getResponseHeader('Content-Encod ing').substr(0, 4)")->AsString());
145 #endif
120 ASSERT_TRUE(jsEngine->Evaluate("request.getResponseHeader('Location')")->IsNul l()); 146 ASSERT_TRUE(jsEngine->Evaluate("request.getResponseHeader('Location')")->IsNul l());
121 } 147 }
122 #else 148 #else
123 TEST_F(DefaultWebRequestTest, DummyWebRequest) 149 TEST_F(DefaultWebRequestTest, DummyWebRequest)
124 { 150 {
125 jsEngine->Evaluate("_webRequest.GET('https://easylist-downloads.adblockplus.or g/easylist.txt', {}, function(result) {foo = result;} )"); 151 jsEngine->Evaluate("_webRequest.GET('https://easylist-downloads.adblockplus.or g/easylist.txt', {}, function(result) {foo = result;} )");
126 do 152 do
127 { 153 {
128 AdblockPlus::Sleep(200); 154 AdblockPlus::Sleep(200);
129 } while (jsEngine->Evaluate("this.foo")->IsUndefined()); 155 } while (jsEngine->Evaluate("this.foo")->IsUndefined());
(...skipping 20 matching lines...) Expand all
150 { 176 {
151 AdblockPlus::Sleep(200); 177 AdblockPlus::Sleep(200);
152 } while (jsEngine->Evaluate("result")->IsUndefined()); 178 } while (jsEngine->Evaluate("result")->IsUndefined());
153 ASSERT_EQ(AdblockPlus::WebRequest::NS_ERROR_FAILURE, jsEngine->Evaluate("reque st.channel.status")->AsInt()); 179 ASSERT_EQ(AdblockPlus::WebRequest::NS_ERROR_FAILURE, jsEngine->Evaluate("reque st.channel.status")->AsInt());
154 ASSERT_EQ(0, jsEngine->Evaluate("request.status")->AsInt()); 180 ASSERT_EQ(0, jsEngine->Evaluate("request.status")->AsInt());
155 ASSERT_EQ("error", jsEngine->Evaluate("result")->AsString()); 181 ASSERT_EQ("error", jsEngine->Evaluate("result")->AsString());
156 ASSERT_TRUE(jsEngine->Evaluate("request.getResponseHeader('Content-Type')")->I sNull()); 182 ASSERT_TRUE(jsEngine->Evaluate("request.getResponseHeader('Content-Type')")->I sNull());
157 } 183 }
158 184
159 #endif 185 #endif
186
187 namespace
188 {
189 class CatchLogSystem : public AdblockPlus::LogSystem
190 {
191 public:
192 AdblockPlus::LogSystem::LogLevel lastLogLevel;
193 std::string lastMessage;
194
195 CatchLogSystem()
196 : AdblockPlus::LogSystem(),
197 lastLogLevel(AdblockPlus::LogSystem::LOG_LEVEL_TRACE)
198 {
199 }
200
201 void operator()(AdblockPlus::LogSystem::LogLevel logLevel,
202 const std::string& message, const std::string&)
203 {
204 lastLogLevel = logLevel;
205 lastMessage = message;
206 }
207
208 void clear()
209 {
210 lastLogLevel = AdblockPlus::LogSystem::LOG_LEVEL_TRACE;
211 lastMessage.clear();
212 }
213 };
214
215 typedef std::shared_ptr<CatchLogSystem> CatchLogSystemPtr;
216
217 void
218 ResetTestXHR(const AdblockPlus::JsEnginePtr & jsEngine, const CatchLogSystemPt r & logger)
Felix Dahlke 2017/03/06 16:51:07 Nit: `AdblockPlus::JsEnginePtr &` -> `AdblockPlus:
hub 2017/03/06 17:26:05 Acknowledged.
219 {
220 jsEngine->Evaluate("\
221 var result;\
222 var request = new XMLHttpRequest();\
223 request.open('GET', 'https://easylist-downloads.adblockplus.org/easylist.t xt');\
224 request.overrideMimeType('text/plain');\
225 request.addEventListener('load', function() {result = request.responseText ;}, false);\
226 request.addEventListener('error', function() {result = 'error';}, false);\
227 ");
228 logger->clear();
229 }
230 }
231
232 TEST_F(XMLHttpRequestTest, RequestHeaderValidation)
233 {
234 #define WAIT_FOR_XHR_RESULT do\
235 {\
236 AdblockPlus::Sleep(60);\
237 } while (jsEngine->Evaluate("result")->IsUndefined())
Felix Dahlke 2017/03/06 16:51:08 This is a bit of a footgun, wouldn't it work to ju
hub 2017/03/06 17:26:05 The only difference I see is that we'll check afte
Felix Dahlke 2017/03/07 07:44:22 Oh sorry, it seems I didn't get what I meant here
hub 2017/03/07 15:52:32 The other test have a similar loop. That's where I
Felix Dahlke 2017/03/07 17:03:42 Oh indeed, for some reason I missed that. Like I s
238
239 auto catchLogSystem = CatchLogSystemPtr(new CatchLogSystem);
240 jsEngine->SetLogSystem(catchLogSystem);
241
242 AdblockPlus::FilterEngine filterEngine(jsEngine);
243 auto webRequest =
244 std::static_pointer_cast<XHRTestWebRequest>(jsEngine->GetWebRequest());
245
246 ASSERT_TRUE(webRequest);
247
248 const std::string msg = "Attempt to set a forbidden header was denied: ";
249
250 // The test will check that console.warn has been called when the
251 // header is rejected. While this is an implementation detail, we
252 // have no other way to check this
253
254 // test 'Accept-Encoding' is rejected
255 ResetTestXHR(jsEngine, catchLogSystem);
256 jsEngine->Evaluate("\
257 request.setRequestHeader('Accept-Encoding', 'gzip');\nrequest.send();");
258 EXPECT_EQ(AdblockPlus::LogSystem::LOG_LEVEL_WARN, catchLogSystem->lastLogLevel );
259 EXPECT_EQ(msg + "Accept-Encoding", catchLogSystem->lastMessage);
260 WAIT_FOR_XHR_RESULT;
261 EXPECT_TRUE(webRequest->lastRequestHeaders.cend() ==
262 webRequest->lastRequestHeaders.find("Accept-Encoding"));
263
264 // test 'DNT' is rejected
265 ResetTestXHR(jsEngine, catchLogSystem);
266 jsEngine->Evaluate("\
267 request.setRequestHeader('DNT', '1');\nrequest.send();");
268 EXPECT_EQ(AdblockPlus::LogSystem::LOG_LEVEL_WARN, catchLogSystem->lastLogLevel );
269 EXPECT_EQ(msg + "DNT", catchLogSystem->lastMessage);
270 WAIT_FOR_XHR_RESULT;
271 EXPECT_TRUE(webRequest->lastRequestHeaders.cend() ==
272 webRequest->lastRequestHeaders.find("DNT"));
273
274 // test random 'X' header is accepted
275 ResetTestXHR(jsEngine, catchLogSystem);
276 jsEngine->Evaluate("\
277 request.setRequestHeader('X', 'y');\nrequest.send();");
278 EXPECT_EQ(AdblockPlus::LogSystem::LOG_LEVEL_TRACE, catchLogSystem->lastLogLeve l);
279 EXPECT_EQ("", catchLogSystem->lastMessage);
280 WAIT_FOR_XHR_RESULT;
281 EXPECT_FALSE(webRequest->lastRequestHeaders.cend() ==
282 webRequest->lastRequestHeaders.find("X"));
283
284 // test /^Proxy-/ is rejected.
285 ResetTestXHR(jsEngine, catchLogSystem);
286 jsEngine->Evaluate("\
287 request.setRequestHeader('Proxy-foo', 'bar');\nrequest.send();");
288 EXPECT_EQ(AdblockPlus::LogSystem::LOG_LEVEL_WARN, catchLogSystem->lastLogLevel );
289 EXPECT_EQ(msg + "Proxy-foo", catchLogSystem->lastMessage);
290 WAIT_FOR_XHR_RESULT;
291 EXPECT_TRUE(webRequest->lastRequestHeaders.cend() ==
292 webRequest->lastRequestHeaders.find("Proxy-foo"));
293
294 // test /^Sec-/ is rejected.
295 ResetTestXHR(jsEngine, catchLogSystem);
296 jsEngine->Evaluate("\
297 request.setRequestHeader('Sec-foo', 'bar');\nrequest.send();");
298 EXPECT_EQ(AdblockPlus::LogSystem::LOG_LEVEL_WARN, catchLogSystem->lastLogLevel );
299 EXPECT_EQ(msg + "Sec-foo", catchLogSystem->lastMessage);
300 WAIT_FOR_XHR_RESULT;
301 EXPECT_TRUE(webRequest->lastRequestHeaders.cend() ==
302 webRequest->lastRequestHeaders.find("Sec-foo"));
303
304 // test 'Security' is accepted.
305 ResetTestXHR(jsEngine, catchLogSystem);
306 jsEngine->Evaluate("\
307 request.setRequestHeader('Security', 'theater');\nrequest.send();");
308 EXPECT_EQ(AdblockPlus::LogSystem::LOG_LEVEL_TRACE, catchLogSystem->lastLogLeve l);
309 EXPECT_EQ("", catchLogSystem->lastMessage);
310 WAIT_FOR_XHR_RESULT;
311 EXPECT_FALSE(webRequest->lastRequestHeaders.cend() ==
312 webRequest->lastRequestHeaders.find("Security"));
313 }
OLDNEW
« no previous file with comments | « lib/compat.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld