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

Side by Side Diff: content/browser/loader/mime_sniffing_resource_handler_unittest.cc

Issue 2005273002: Move MimeTypeResourceHandler before ThrottlingResourceHandler (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed issue in ResourceDispatcherHostTests Created 4 years, 6 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
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/loader/mime_sniffing_resource_handler.h"
6
7 #include <stdint.h>
8
9 #include <memory>
10
11 #include "base/files/file_path.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "content/public/browser/resource_controller.h"
18 #include "content/public/browser/resource_request_info.h"
19 #include "content/public/common/resource_response.h"
20 #include "content/public/common/webplugininfo.h"
21 #include "content/public/test/test_browser_thread_bundle.h"
22 #include "content/public/test/test_utils.h"
23 #include "net/url_request/url_request_context.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "url/gurl.h"
26
27 namespace content {
28
29 namespace {
30
31 class TestResourceHandler : public ResourceHandler {
32 public:
33 TestResourceHandler(bool response_started,
34 bool defer_response_started,
35 bool will_read,
36 bool read_completed,
37 bool defer_read_completed)
38 : ResourceHandler(nullptr),
39 buffer_(new net::IOBuffer(2048)),
40 response_started_(response_started),
41 defer_response_started_(defer_response_started),
42 will_read_(will_read),
43 read_completed_(read_completed),
44 defer_read_completed_(defer_read_completed) {}
45
46 void SetController(ResourceController* controller) override {}
47
48 bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
49 ResourceResponse* response,
50 bool* defer) override {
51 NOTREACHED();
52 return false;
53 }
54
55 bool OnResponseStarted(ResourceResponse* response, bool* defer) override {
56 if (defer_response_started_)
57 *defer = true;
58 return response_started_;
59 }
60
61 bool OnWillStart(const GURL& url, bool* defer) override { return false; }
62
63 bool OnBeforeNetworkStart(const GURL& url, bool* defer) override {
64 NOTREACHED();
65 return false;
66 }
67
68 bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
69 int* buf_size,
70 int min_size) override {
71 *buf = buffer_;
72 *buf_size = 2048;
73 return will_read_;
74 }
75
76 bool OnReadCompleted(int bytes_read, bool* defer) override {
77 DCHECK_LT(bytes_read, 2048);
78 if (defer_read_completed_)
79 *defer = true;
80 return read_completed_;
81 }
82
83 void OnResponseCompleted(const net::URLRequestStatus& status,
84 const std::string& security_info,
85 bool* defer) override {}
86
87 void OnDataDownloaded(int bytes_downloaded) override { NOTREACHED(); }
88
89 scoped_refptr<net::IOBuffer> buffer() { return buffer_; }
90
91 private:
92 scoped_refptr<net::IOBuffer> buffer_;
93 bool response_started_;
94 bool defer_response_started_;
95 bool will_read_;
96 bool read_completed_;
97 bool defer_read_completed_;
98 DISALLOW_COPY_AND_ASSIGN(TestResourceHandler);
99 };
100
101 } // namespace
102
103 class TestResourceController : public ResourceController {
104 public:
105 TestResourceController() : cancel_called_(0), resume_called_(0) {}
106 void Cancel() override { cancel_called_++; }
107
108 void CancelAndIgnore() override { NOTREACHED(); }
109
110 void CancelWithError(int error_code) override { NOTREACHED(); }
111
112 void Resume() override { resume_called_++; }
113
114 int cancel_called() const { return cancel_called_; }
115 int resume_called() const { return resume_called_; }
116
117 private:
118 int cancel_called_;
119 int resume_called_;
120 };
121
122 class MimeSniffingResourceHandlerTest : public testing::Test {
123 public:
124 MimeSniffingResourceHandlerTest() {}
125
126 std::string TestAcceptHeaderSetting(ResourceType request_resource_type);
127 std::string TestAcceptHeaderSettingWithURLRequest(
128 ResourceType request_resource_type,
129 net::URLRequest* request);
130
131 // Tests the operation of the MimeSniffingHandler when it needs to buffer
132 // data.
133 void TestHandlerSniffing(bool response_started,
134 bool defer_response_started,
135 bool will_read,
136 bool read_completed,
137 bool defer_read_completed);
138
139 // Tests the operation of the MimeSniffingHandler when it doesn't buffer
140 // data.
141 void TestHandlerNoSniffing(bool response_started,
142 bool defer_response_started,
143 bool will_read,
144 bool read_completed,
145 bool defer_read_completed);
146
147 private:
148 TestBrowserThreadBundle thread_bundle_;
149 };
150
151 std::string MimeSniffingResourceHandlerTest::TestAcceptHeaderSetting(
152 ResourceType request_resource_type) {
153 net::URLRequestContext context;
154 std::unique_ptr<net::URLRequest> request(context.CreateRequest(
155 GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
156 return TestAcceptHeaderSettingWithURLRequest(request_resource_type,
157 request.get());
158 }
159
160 std::string
161 MimeSniffingResourceHandlerTest::TestAcceptHeaderSettingWithURLRequest(
162 ResourceType request_resource_type,
163 net::URLRequest* request) {
164 bool is_main_frame = request_resource_type == RESOURCE_TYPE_MAIN_FRAME;
165 ResourceRequestInfo::AllocateForTesting(request, request_resource_type,
166 nullptr, // context
167 0, // render_process_id
168 0, // render_view_id
169 0, // render_frame_id
170 is_main_frame, // is_main_frame
171 false, // parent_is_main_frame
172 false, // allow_download
173 true, // is_async
174 false); // is_using_lofi
175
176 std::unique_ptr<ResourceHandler> mime_sniffing_handler(
177 new MimeSniffingResourceHandler(
178 std::unique_ptr<ResourceHandler>(
179 new TestResourceHandler(false, false, false, false, false)),
180 request));
181
182 bool defer = false;
183 mime_sniffing_handler->OnWillStart(request->url(), &defer);
184 content::RunAllPendingInMessageLoop();
185
186 std::string accept_header;
187 request->extra_request_headers().GetHeader("Accept", &accept_header);
188 return accept_header;
189 }
190
191 void MimeSniffingResourceHandlerTest::TestHandlerSniffing(
192 bool response_started,
193 bool defer_response_started,
194 bool will_read,
195 bool read_completed,
196 bool defer_read_completed) {
197 net::URLRequestContext context;
198 std::unique_ptr<net::URLRequest> request(context.CreateRequest(
199 GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
200 ResourceRequestInfo::AllocateForTesting(request.get(),
201 RESOURCE_TYPE_MAIN_FRAME,
202 nullptr, // context
203 0, // render_process_id
204 0, // render_view_id
205 0, // render_frame_id
206 true, // is_main_frame
207 false, // parent_is_main_frame
208 false, // allow_download
209 true, // is_async
210 false); // is_using_lofi
211
212 std::unique_ptr<ResourceHandler> handler(new MimeSniffingResourceHandler(
213 std::unique_ptr<ResourceHandler>(new TestResourceHandler(
214 response_started, defer_response_started, will_read, read_completed,
215 defer_read_completed)),
216 request.get()));
217 MimeSniffingResourceHandler* mime_sniffing_handler =
218 static_cast<MimeSniffingResourceHandler*>(handler.get());
219
220 TestResourceController resource_controller;
221 mime_sniffing_handler->SetController(&resource_controller);
222
223 // The response should be sniffed.
224 scoped_refptr<ResourceResponse> response(new ResourceResponse);
225 response->head.mime_type.assign("text/plain");
226
227 CHECK_EQ(MimeSniffingResourceHandler::STATE_STARTING,
228 mime_sniffing_handler->state_);
229
230 // Simulate the response starting. We should start buffering, so the return
231 // value should always be true.
232 bool defer = false;
233 CHECK_EQ(true,
234 mime_sniffing_handler->OnResponseStarted(response.get(), &defer));
235 CHECK_EQ(0, resource_controller.cancel_called());
236 CHECK_EQ(0, resource_controller.resume_called());
237 CHECK_EQ(false, defer);
238 CHECK_EQ(MimeSniffingResourceHandler::STATE_BUFFERING,
239 mime_sniffing_handler->state_);
240
241 // Read some data to sniff the mime type. This will ask the next
242 // ResourceHandler for a buffer.
243 scoped_refptr<net::IOBuffer> read_buffer;
244 int buf_size = 0;
245 CHECK_EQ(will_read,
246 mime_sniffing_handler->OnWillRead(&read_buffer, &buf_size, -1));
247 CHECK_EQ(0, resource_controller.cancel_called());
248 CHECK_EQ(MimeSniffingResourceHandler::STATE_BUFFERING,
249 mime_sniffing_handler->state_);
250
251 if (!will_read)
252 return;
253
254 // Simulate an HTML page. The mime sniffer will identify the MimeType and
255 // proceed with replay.
256 char data[] = "!DOCTYPE html\n<head>\n<title>Foo</title>\n</head>";
257 memcpy(read_buffer->data(), data, sizeof(data));
258
259 defer = false;
260 bool return_value =
261 mime_sniffing_handler->OnReadCompleted(sizeof(data), &defer);
262
263 // If the next handler cancels the response start, we hsould be notified
264 // immediately.
265 if (!response_started) {
266 CHECK_EQ(response_started, return_value);
267 CHECK_EQ(0, resource_controller.cancel_called());
268 return;
269 }
270
271 // The replay can be deferred both at response started and read replay
272 // stages.
273 CHECK_EQ(defer, defer_response_started || defer_read_completed);
274 if (defer_response_started) {
275 CHECK_EQ(true, defer);
276 CHECK_EQ(true, return_value);
277 CHECK_EQ(MimeSniffingResourceHandler::STATE_REPLAYING_RESPONSE_RECEIVED,
278 mime_sniffing_handler->state_);
279 mime_sniffing_handler->Resume();
280 }
281
282 // The body that was sniffed should be transmitted to the next handler. This
283 // may cancel the request.
284 if (!read_completed) {
285 if (defer_response_started) {
286 CHECK_EQ(1, resource_controller.cancel_called());
287 } else {
288 CHECK_EQ(0, resource_controller.cancel_called());
289 CHECK_EQ(false, return_value);
290 }
291 return;
292 }
293
294 CHECK_EQ(MimeSniffingResourceHandler::STATE_STREAMING,
295 mime_sniffing_handler->state_);
296
297 // The request may be deferred by the next handler once the read is done.
298 if (defer_read_completed) {
299 CHECK_EQ(true, defer);
300 mime_sniffing_handler->Resume();
301 }
302
303 CHECK_EQ(MimeSniffingResourceHandler::STATE_STREAMING,
304 mime_sniffing_handler->state_);
305 CHECK_EQ(0, resource_controller.cancel_called());
306
307 // Even if the next handler defers the request twice, the
308 // MimeSniffingResourceHandler should only call Resume on its controller
309 // once.
310 if (defer_response_started || defer_read_completed)
311 CHECK_EQ(1, resource_controller.resume_called());
312 else
313 CHECK_EQ(0, resource_controller.resume_called());
314 }
315
316 void MimeSniffingResourceHandlerTest::TestHandlerNoSniffing(
317 bool response_started,
318 bool defer_response_started,
319 bool will_read,
320 bool read_completed,
321 bool defer_read_completed) {
322 net::URLRequestContext context;
323 std::unique_ptr<net::URLRequest> request(context.CreateRequest(
324 GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
325 ResourceRequestInfo::AllocateForTesting(request.get(),
326 RESOURCE_TYPE_MAIN_FRAME,
327 nullptr, // context
328 0, // render_process_id
329 0, // render_view_id
330 0, // render_frame_id
331 true, // is_main_frame
332 false, // parent_is_main_frame
333 false, // allow_download
334 true, // is_async
335 false); // is_using_lofi
336
337 std::unique_ptr<ResourceHandler> handler(new MimeSniffingResourceHandler(
338 std::unique_ptr<ResourceHandler>(new TestResourceHandler(
339 response_started, defer_response_started, will_read, read_completed,
340 defer_read_completed)),
341 request.get()));
342 MimeSniffingResourceHandler* mime_sniffing_handler =
343 static_cast<MimeSniffingResourceHandler*>(handler.get());
344
345 TestResourceController resource_controller;
346 mime_sniffing_handler->SetController(&resource_controller);
347 int expected_resume_calls = 0;
348
349 // The response should not be sniffed.
350 scoped_refptr<ResourceResponse> response(new ResourceResponse);
351 response->head.mime_type.assign("text/html");
352
353 CHECK_EQ(MimeSniffingResourceHandler::STATE_STARTING,
354 mime_sniffing_handler->state_);
355
356 // Simulate the response starting. There should be no need for buffering, so
357 // the return value should be that of the next handler.
358 bool defer = false;
359 CHECK_EQ(response_started,
360 mime_sniffing_handler->OnResponseStarted(response.get(), &defer));
361 CHECK_EQ(0, resource_controller.cancel_called());
362
363 if (!response_started)
364 return;
365
366 CHECK_EQ(defer_response_started, defer);
367 if (defer) {
368 CHECK_EQ(MimeSniffingResourceHandler::STATE_REPLAYING_RESPONSE_RECEIVED,
369 mime_sniffing_handler->state_);
370 expected_resume_calls++;
371 mime_sniffing_handler->Resume();
372 }
373
374 CHECK_EQ(expected_resume_calls, resource_controller.resume_called());
375 CHECK_EQ(MimeSniffingResourceHandler::STATE_STREAMING,
376 mime_sniffing_handler->state_);
377
378 // The MimeSniffingResourceHandler should be acting as a pass-through
379 // ResourceHandler.
380 scoped_refptr<net::IOBuffer> read_buffer;
381 int buf_size = 0;
382 CHECK_EQ(will_read,
383 mime_sniffing_handler->OnWillRead(&read_buffer, &buf_size, -1));
384 CHECK_EQ(0, resource_controller.cancel_called());
385 CHECK_EQ(MimeSniffingResourceHandler::STATE_STREAMING,
386 mime_sniffing_handler->state_);
387
388 if (!will_read)
389 return;
390
391 defer = false;
392 CHECK_EQ(read_completed,
393 mime_sniffing_handler->OnReadCompleted(2000, &defer));
394 CHECK_EQ(0, resource_controller.cancel_called());
395 CHECK_EQ(MimeSniffingResourceHandler::STATE_STREAMING,
396 mime_sniffing_handler->state_);
397
398 if (!read_completed)
399 return;
400
401 CHECK_EQ(defer_read_completed, defer);
402 if (defer) {
403 expected_resume_calls++;
404 mime_sniffing_handler->Resume();
405 }
406 CHECK_EQ(expected_resume_calls, resource_controller.resume_called());
407 }
408
409 // Test that the proper Accept: header is set based on the ResourceType
410 TEST_F(MimeSniffingResourceHandlerTest, AcceptHeaders) {
411 EXPECT_EQ(
412 "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,"
413 "*/*;q=0.8",
414 TestAcceptHeaderSetting(RESOURCE_TYPE_MAIN_FRAME));
415 EXPECT_EQ(
416 "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,"
417 "*/*;q=0.8",
418 TestAcceptHeaderSetting(RESOURCE_TYPE_SUB_FRAME));
419 EXPECT_EQ("text/css,*/*;q=0.1",
420 TestAcceptHeaderSetting(RESOURCE_TYPE_STYLESHEET));
421 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_SCRIPT));
422 EXPECT_EQ("image/webp,image/*,*/*;q=0.8",
423 TestAcceptHeaderSetting(RESOURCE_TYPE_IMAGE));
424 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_FONT_RESOURCE));
425 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_SUB_RESOURCE));
426 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_OBJECT));
427 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_MEDIA));
428 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_WORKER));
429 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_SHARED_WORKER));
430 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_PREFETCH));
431 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_FAVICON));
432 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_XHR));
433 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_PING));
434 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_SERVICE_WORKER));
435 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_CSP_REPORT));
436 EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_PLUGIN_RESOURCE));
437
438 // Ensure that if an Accept header is already set, it is not overwritten.
439 net::URLRequestContext context;
440 std::unique_ptr<net::URLRequest> request(context.CreateRequest(
441 GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
442 request->SetExtraRequestHeaderByName("Accept", "*", true);
443 EXPECT_EQ("*", TestAcceptHeaderSettingWithURLRequest(RESOURCE_TYPE_XHR,
444 request.get()));
445 }
446
447 // Test that the MimeSniffingHandler operates properly when it doesn't sniff
448 // resources.
449 TEST_F(MimeSniffingResourceHandlerTest, NoSniffing) {
450 // Test simple case.
451 TestHandlerNoSniffing(true, false, true, true, false);
452
453 // Test deferral in OnResponseStarted and/or in OnReadCompleted.
454 TestHandlerNoSniffing(true, true, true, true, false);
455 TestHandlerNoSniffing(true, false, true, true, true);
456 TestHandlerNoSniffing(true, true, true, true, true);
457
458 // Test cancel in OnResponseStarted, OnWillRead, OnReadCompleted.
459 TestHandlerNoSniffing(false, false, false, false, false);
460 TestHandlerNoSniffing(true, false, false, false, false);
461 TestHandlerNoSniffing(true, false, true, false, false);
462
463 // Test cancel after OnResponseStarted deferral.
464 TestHandlerNoSniffing(true, true, false, false, false);
465 TestHandlerNoSniffing(true, true, true, false, false);
466 }
467
468 // Test that the MimeSniffingHandler operates properly when it sniffs
469 // resources.
470 TEST_F(MimeSniffingResourceHandlerTest, Sniffing) {
471 // Test simple case.
472 TestHandlerSniffing(true, false, true, true, false);
473
474 // Test deferral in OnResponseStarted and/or in OnReadCompleted.
475 TestHandlerSniffing(true, true, true, true, false);
476 TestHandlerSniffing(true, false, true, true, true);
477 TestHandlerSniffing(true, true, true, true, true);
478
479 // Test cancel in OnResponseStarted, OnWillRead, OnReadCompleted.
480 TestHandlerSniffing(false, false, false, false, false);
481 TestHandlerSniffing(true, false, false, false, false);
482 TestHandlerSniffing(true, false, true, false, false);
483
484 // Test cancel after OnResponseStarted deferral.
485 TestHandlerSniffing(true, true, false, false, false);
486 TestHandlerSniffing(true, true, true, false, false);
487 }
488
489 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698