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: updated patch with feedback Created March 6, 2017, 5:50 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
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 #include <sstream> 18 #include <sstream>
19 #include "BaseJsTest.h" 19 #include "BaseJsTest.h"
20 #include "../src/Thread.h" 20 #include "../src/Thread.h"
21 21
22 namespace 22 namespace
23 { 23 {
24 class MockWebRequest : public AdblockPlus::WebRequest 24 class MockWebRequest : public AdblockPlus::WebRequest
25 { 25 {
26 public: 26 public:
27 AdblockPlus::ServerResponse GET(const std::string& url, const AdblockPlus::H eaderList& requestHeaders) const 27 AdblockPlus::ServerResponse GET(const std::string& url, const AdblockPlus::H eaderList& requestHeaders) const
28 { 28 {
29 lastRequestHeaders.clear();
30 for (auto header : requestHeaders)
31 {
32 lastRequestHeaders.insert(header.first);
33 }
34
29 AdblockPlus::Sleep(50); 35 AdblockPlus::Sleep(50);
30 36
31 AdblockPlus::ServerResponse result; 37 AdblockPlus::ServerResponse result;
32 result.status = NS_OK; 38 result.status = NS_OK;
33 result.responseStatus = 123; 39 result.responseStatus = 123;
34 result.responseHeaders.push_back(std::pair<std::string, std::string>("Foo" , "Bar")); 40 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; 41 result.responseText = url + "\n";
42 if (!requestHeaders.empty())
43 {
44 result.responseText += requestHeaders[0].first + "\n" + requestHeaders[0 ].second;
45 }
36 return result; 46 return result;
37 } 47 }
48
49 // mutable. Very Ugly. But we are testing and need to change this in GET whi ch is const.
50 mutable std::set<std::string> lastRequestHeaders;
38 }; 51 };
39 52
40 template<class T> 53 template<class T>
41 class WebRequestTest : public BaseJsTest 54 class WebRequestTest : public BaseJsTest
42 { 55 {
43 protected: 56 protected:
44 void SetUp() 57 void SetUp()
45 { 58 {
46 BaseJsTest::SetUp(); 59 BaseJsTest::SetUp();
47 jsEngine->SetWebRequest(AdblockPlus::WebRequestPtr(new T)); 60 jsEngine->SetWebRequest(AdblockPlus::WebRequestPtr(new T));
48 jsEngine->SetFileSystem(AdblockPlus::FileSystemPtr(new LazyFileSystem)); 61 jsEngine->SetFileSystem(AdblockPlus::FileSystemPtr(new LazyFileSystem));
49 } 62 }
50 }; 63 };
51 64
52 typedef WebRequestTest<MockWebRequest> MockWebRequestTest; 65 typedef WebRequestTest<MockWebRequest> MockWebRequestTest;
53 typedef WebRequestTest<AdblockPlus::DefaultWebRequest> DefaultWebRequestTest; 66 typedef WebRequestTest<AdblockPlus::DefaultWebRequest> DefaultWebRequestTest;
67 typedef WebRequestTest<MockWebRequest> XMLHttpRequestTest;
54 } 68 }
55 69
56 TEST_F(MockWebRequestTest, BadCall) 70 TEST_F(MockWebRequestTest, BadCall)
57 { 71 {
58 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET()")); 72 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET()"));
59 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET('', {}, function(){})")); 73 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET('', {}, function(){})"));
60 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET({toString: false}, {}, fu nction(){})")); 74 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(){})")); 75 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)")); 76 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET('http://example.com/', {} , null)"));
63 ASSERT_ANY_THROW(jsEngine->Evaluate("_webRequest.GET('http://example.com/', {} , function(){}, 0)")); 77 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);\ 124 request.addEventListener('error', function() {result = 'error';}, false);\
111 request.send(null);"); 125 request.send(null);");
112 do 126 do
113 { 127 {
114 AdblockPlus::Sleep(200); 128 AdblockPlus::Sleep(200);
115 } while (jsEngine->Evaluate("result")->IsUndefined()); 129 } while (jsEngine->Evaluate("result")->IsUndefined());
116 ASSERT_EQ(AdblockPlus::WebRequest::NS_OK, jsEngine->Evaluate("request.channel. status")->AsInt()); 130 ASSERT_EQ(AdblockPlus::WebRequest::NS_OK, jsEngine->Evaluate("request.channel. status")->AsInt());
117 ASSERT_EQ(200, jsEngine->Evaluate("request.status")->AsInt()); 131 ASSERT_EQ(200, jsEngine->Evaluate("request.status")->AsInt());
118 ASSERT_EQ("[Adblock Plus ", jsEngine->Evaluate("result.substr(0, 14)")->AsStri ng()); 132 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()); 133 ASSERT_EQ("text/plain", jsEngine->Evaluate("request.getResponseHeader('Content -Type').substr(0, 10)")->AsString());
134 #if defined(HAVE_CURL)
135 ASSERT_EQ("gzip", jsEngine->Evaluate("request.getResponseHeader('Content-Encod ing').substr(0, 4)")->AsString());
136 #endif
120 ASSERT_TRUE(jsEngine->Evaluate("request.getResponseHeader('Location')")->IsNul l()); 137 ASSERT_TRUE(jsEngine->Evaluate("request.getResponseHeader('Location')")->IsNul l());
121 } 138 }
122 #else 139 #else
123 TEST_F(DefaultWebRequestTest, DummyWebRequest) 140 TEST_F(DefaultWebRequestTest, DummyWebRequest)
124 { 141 {
125 jsEngine->Evaluate("_webRequest.GET('https://easylist-downloads.adblockplus.or g/easylist.txt', {}, function(result) {foo = result;} )"); 142 jsEngine->Evaluate("_webRequest.GET('https://easylist-downloads.adblockplus.or g/easylist.txt', {}, function(result) {foo = result;} )");
126 do 143 do
127 { 144 {
128 AdblockPlus::Sleep(200); 145 AdblockPlus::Sleep(200);
129 } while (jsEngine->Evaluate("this.foo")->IsUndefined()); 146 } while (jsEngine->Evaluate("this.foo")->IsUndefined());
(...skipping 20 matching lines...) Expand all
150 { 167 {
151 AdblockPlus::Sleep(200); 168 AdblockPlus::Sleep(200);
152 } while (jsEngine->Evaluate("result")->IsUndefined()); 169 } while (jsEngine->Evaluate("result")->IsUndefined());
153 ASSERT_EQ(AdblockPlus::WebRequest::NS_ERROR_FAILURE, jsEngine->Evaluate("reque st.channel.status")->AsInt()); 170 ASSERT_EQ(AdblockPlus::WebRequest::NS_ERROR_FAILURE, jsEngine->Evaluate("reque st.channel.status")->AsInt());
154 ASSERT_EQ(0, jsEngine->Evaluate("request.status")->AsInt()); 171 ASSERT_EQ(0, jsEngine->Evaluate("request.status")->AsInt());
155 ASSERT_EQ("error", jsEngine->Evaluate("result")->AsString()); 172 ASSERT_EQ("error", jsEngine->Evaluate("result")->AsString());
156 ASSERT_TRUE(jsEngine->Evaluate("request.getResponseHeader('Content-Type')")->I sNull()); 173 ASSERT_TRUE(jsEngine->Evaluate("request.getResponseHeader('Content-Type')")->I sNull());
157 } 174 }
158 175
159 #endif 176 #endif
177
178 namespace
179 {
180 class CatchLogSystem : public AdblockPlus::LogSystem
181 {
182 public:
183 AdblockPlus::LogSystem::LogLevel lastLogLevel;
184 std::string lastMessage;
185
186 CatchLogSystem()
187 : AdblockPlus::LogSystem(),
188 lastLogLevel(AdblockPlus::LogSystem::LOG_LEVEL_TRACE)
189 {
190 }
191
192 void operator()(AdblockPlus::LogSystem::LogLevel logLevel,
193 const std::string& message, const std::string&)
194 {
195 lastLogLevel = logLevel;
196 lastMessage = message;
197 }
198
199 void clear()
200 {
201 lastLogLevel = AdblockPlus::LogSystem::LOG_LEVEL_TRACE;
202 lastMessage.clear();
203 }
204 };
205
206 typedef std::shared_ptr<CatchLogSystem> CatchLogSystemPtr;
207
208 void
209 ResetTestXHR(const AdblockPlus::JsEnginePtr& jsEngine, const CatchLogSystemPtr & logger)
210 {
211 jsEngine->Evaluate("\
212 var result;\
213 var request = new XMLHttpRequest();\
214 request.open('GET', 'https://easylist-downloads.adblockplus.org/easylist.t xt');\
215 request.overrideMimeType('text/plain');\
216 request.addEventListener('load', function() {result = request.responseText ;}, false);\
217 request.addEventListener('error', function() {result = 'error';}, false);\
218 ");
219 logger->clear();
220 }
221 }
222
223 TEST_F(XMLHttpRequestTest, RequestHeaderValidation)
224 {
225 #define WAIT_FOR_XHR_RESULT do\
226 {\
227 AdblockPlus::Sleep(60);\
228 } while (jsEngine->Evaluate("result")->IsUndefined())
229
230 auto catchLogSystem = CatchLogSystemPtr(new CatchLogSystem);
231 jsEngine->SetLogSystem(catchLogSystem);
232
233 AdblockPlus::FilterEngine filterEngine(jsEngine);
234 auto webRequest =
235 std::static_pointer_cast<MockWebRequest>(jsEngine->GetWebRequest());
236
237 ASSERT_TRUE(webRequest);
238
239 const std::string msg = "Attempt to set a forbidden header was denied: ";
240
241 // The test will check that console.warn has been called when the
242 // header is rejected. While this is an implementation detail, we
243 // have no other way to check this
244
245 // test 'Accept-Encoding' is rejected
246 ResetTestXHR(jsEngine, catchLogSystem);
247 jsEngine->Evaluate("\
248 request.setRequestHeader('Accept-Encoding', 'gzip');\nrequest.send();");
249 EXPECT_EQ(AdblockPlus::LogSystem::LOG_LEVEL_WARN, catchLogSystem->lastLogLevel );
250 EXPECT_EQ(msg + "Accept-Encoding", catchLogSystem->lastMessage);
251 WAIT_FOR_XHR_RESULT;
252 EXPECT_TRUE(webRequest->lastRequestHeaders.cend() ==
253 webRequest->lastRequestHeaders.find("Accept-Encoding"));
254
255 // test 'DNT' is rejected
256 ResetTestXHR(jsEngine, catchLogSystem);
257 jsEngine->Evaluate("\
258 request.setRequestHeader('DNT', '1');\nrequest.send();");
259 EXPECT_EQ(AdblockPlus::LogSystem::LOG_LEVEL_WARN, catchLogSystem->lastLogLevel );
260 EXPECT_EQ(msg + "DNT", catchLogSystem->lastMessage);
261 WAIT_FOR_XHR_RESULT;
262 EXPECT_TRUE(webRequest->lastRequestHeaders.cend() ==
263 webRequest->lastRequestHeaders.find("DNT"));
264
265 // test random 'X' header is accepted
266 ResetTestXHR(jsEngine, catchLogSystem);
267 jsEngine->Evaluate("\
268 request.setRequestHeader('X', 'y');\nrequest.send();");
269 EXPECT_EQ(AdblockPlus::LogSystem::LOG_LEVEL_TRACE, catchLogSystem->lastLogLeve l);
270 EXPECT_EQ("", catchLogSystem->lastMessage);
271 WAIT_FOR_XHR_RESULT;
272 EXPECT_FALSE(webRequest->lastRequestHeaders.cend() ==
273 webRequest->lastRequestHeaders.find("X"));
274
275 // test /^Proxy-/ is rejected.
276 ResetTestXHR(jsEngine, catchLogSystem);
277 jsEngine->Evaluate("\
278 request.setRequestHeader('Proxy-foo', 'bar');\nrequest.send();");
279 EXPECT_EQ(AdblockPlus::LogSystem::LOG_LEVEL_WARN, catchLogSystem->lastLogLevel );
280 EXPECT_EQ(msg + "Proxy-foo", catchLogSystem->lastMessage);
281 WAIT_FOR_XHR_RESULT;
282 EXPECT_TRUE(webRequest->lastRequestHeaders.cend() ==
283 webRequest->lastRequestHeaders.find("Proxy-foo"));
284
285 // test /^Sec-/ is rejected.
286 ResetTestXHR(jsEngine, catchLogSystem);
287 jsEngine->Evaluate("\
288 request.setRequestHeader('Sec-foo', 'bar');\nrequest.send();");
289 EXPECT_EQ(AdblockPlus::LogSystem::LOG_LEVEL_WARN, catchLogSystem->lastLogLevel );
290 EXPECT_EQ(msg + "Sec-foo", catchLogSystem->lastMessage);
291 WAIT_FOR_XHR_RESULT;
292 EXPECT_TRUE(webRequest->lastRequestHeaders.cend() ==
293 webRequest->lastRequestHeaders.find("Sec-foo"));
294
295 // test 'Security' is accepted.
296 ResetTestXHR(jsEngine, catchLogSystem);
297 jsEngine->Evaluate("\
298 request.setRequestHeader('Security', 'theater');\nrequest.send();");
299 EXPECT_EQ(AdblockPlus::LogSystem::LOG_LEVEL_TRACE, catchLogSystem->lastLogLeve l);
300 EXPECT_EQ("", catchLogSystem->lastMessage);
301 WAIT_FOR_XHR_RESULT;
302 EXPECT_FALSE(webRequest->lastRequestHeaders.cend() ==
303 webRequest->lastRequestHeaders.find("Security"));
304 }
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