1 // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include <algorithm>
6 #include <cmath>
7 #include <memory>
8 #include <sstream>
9 #include <string>
10
11 #include "include/base/cef_callback.h"
12 #include "include/cef_request_context_handler.h"
13 #include "include/cef_scheme.h"
14 #include "include/wrapper/cef_closure_task.h"
15 #include "include/wrapper/cef_stream_resource_handler.h"
16 #include "tests/ceftests/routing_test_handler.h"
17 #include "tests/ceftests/test_handler.h"
18 #include "tests/ceftests/test_util.h"
19 #include "tests/gtest/include/gtest/gtest.h"
20
21 namespace {
22
23 // Normal stream resource handler implementation that additionally verifies
24 // calls to Cancel.
25 // This also tests the CefStreamResourceHandler implementation.
26 class NormalResourceHandler : public CefStreamResourceHandler {
27 public:
NormalResourceHandler(int status_code,const CefString & status_text,const CefString & mime_type,CefResponse::HeaderMap header_map,CefRefPtr<CefStreamReader> stream,base::OnceClosure destroy_callback)28 NormalResourceHandler(int status_code,
29 const CefString& status_text,
30 const CefString& mime_type,
31 CefResponse::HeaderMap header_map,
32 CefRefPtr<CefStreamReader> stream,
33 base::OnceClosure destroy_callback)
34 : CefStreamResourceHandler(status_code,
35 status_text,
36 mime_type,
37 header_map,
38 stream),
39 destroy_callback_(std::move(destroy_callback)) {}
40
~NormalResourceHandler()41 ~NormalResourceHandler() override {
42 EXPECT_EQ(1, cancel_ct_);
43 std::move(destroy_callback_).Run();
44 }
45
Cancel()46 void Cancel() override {
47 EXPECT_IO_THREAD();
48 cancel_ct_++;
49 }
50
51 private:
52 base::OnceClosure destroy_callback_;
53 int cancel_ct_ = 0;
54 };
55
56 // Normal stream resource handler implementation that additionally continues
57 // using the callback object and verifies calls to Cancel.
58 class CallbackResourceHandler : public CefResourceHandler {
59 public:
60 enum Mode {
61 DELAYED_OPEN,
62 DELAYED_READ,
63 IMMEDIATE_OPEN,
64 IMMEDIATE_READ,
65 DELAYED_ALL,
66 IMMEDIATE_ALL,
67 };
68
IsDelayedOpen() const69 bool IsDelayedOpen() const {
70 return mode_ == DELAYED_OPEN || mode_ == DELAYED_ALL;
71 }
72
IsDelayedRead() const73 bool IsDelayedRead() const {
74 return mode_ == DELAYED_READ || mode_ == DELAYED_ALL;
75 }
76
IsImmediateOpen() const77 bool IsImmediateOpen() const {
78 return mode_ == IMMEDIATE_OPEN || mode_ == IMMEDIATE_ALL;
79 }
80
IsImmediateRead() const81 bool IsImmediateRead() const {
82 return mode_ == IMMEDIATE_READ || mode_ == IMMEDIATE_ALL;
83 }
84
CallbackResourceHandler(Mode mode,int status_code,const CefString & status_text,const CefString & mime_type,CefResponse::HeaderMap header_map,CefRefPtr<CefStreamReader> stream,base::OnceClosure destroy_callback)85 CallbackResourceHandler(Mode mode,
86 int status_code,
87 const CefString& status_text,
88 const CefString& mime_type,
89 CefResponse::HeaderMap header_map,
90 CefRefPtr<CefStreamReader> stream,
91 base::OnceClosure destroy_callback)
92 : mode_(mode),
93 status_code_(status_code),
94 status_text_(status_text),
95 mime_type_(mime_type),
96 header_map_(header_map),
97 stream_(stream),
98 destroy_callback_(std::move(destroy_callback)) {
99 DCHECK(!mime_type_.empty());
100 DCHECK(stream_.get());
101 }
102
~CallbackResourceHandler()103 ~CallbackResourceHandler() override {
104 EXPECT_EQ(1, cancel_ct_);
105 std::move(destroy_callback_).Run();
106 }
107
Open(CefRefPtr<CefRequest> request,bool & handle_request,CefRefPtr<CefCallback> callback)108 bool Open(CefRefPtr<CefRequest> request,
109 bool& handle_request,
110 CefRefPtr<CefCallback> callback) override {
111 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
112
113 if (IsDelayedOpen()) {
114 // Continue the request asynchronously by executing the callback.
115 CefPostTask(TID_FILE_USER_VISIBLE,
116 base::BindOnce(&CefCallback::Continue, callback));
117 handle_request = false;
118 return true;
119 } else if (IsImmediateOpen()) {
120 // Continue the request immediately be executing the callback.
121 callback->Continue();
122 handle_request = false;
123 return true;
124 }
125
126 // Continue the request immediately in the default manner.
127 handle_request = true;
128 return true;
129 }
130
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)131 void GetResponseHeaders(CefRefPtr<CefResponse> response,
132 int64& response_length,
133 CefString& redirectUrl) override {
134 response->SetStatus(status_code_);
135 response->SetStatusText(status_text_);
136 response->SetMimeType(mime_type_);
137
138 if (!header_map_.empty())
139 response->SetHeaderMap(header_map_);
140
141 response_length = -1;
142 }
143
Read(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefResourceReadCallback> callback)144 bool Read(void* data_out,
145 int bytes_to_read,
146 int& bytes_read,
147 CefRefPtr<CefResourceReadCallback> callback) override {
148 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
149 EXPECT_GT(bytes_to_read, 0);
150
151 bytes_read = 0;
152
153 if (IsDelayedRead()) {
154 // Continue the request asynchronously by executing the callback.
155 CefPostTask(TID_FILE_USER_VISIBLE,
156 base::BindOnce(&CallbackResourceHandler::ContinueRead, this,
157 data_out, bytes_to_read, callback));
158 return true;
159 } else if (IsImmediateRead()) {
160 // Continue the request immediately be executing the callback.
161 ContinueRead(data_out, bytes_to_read, callback);
162 return true;
163 }
164
165 // Continue the request immediately in the default manner.
166 return DoRead(data_out, bytes_to_read, bytes_read);
167 }
168
Cancel()169 void Cancel() override {
170 EXPECT_IO_THREAD();
171 cancel_ct_++;
172 }
173
174 private:
ContinueRead(void * data_out,int bytes_to_read,CefRefPtr<CefResourceReadCallback> callback)175 void ContinueRead(void* data_out,
176 int bytes_to_read,
177 CefRefPtr<CefResourceReadCallback> callback) {
178 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
179
180 int bytes_read = 0;
181 DoRead(data_out, bytes_to_read, bytes_read);
182 callback->Continue(bytes_read);
183 }
184
DoRead(void * data_out,int bytes_to_read,int & bytes_read)185 bool DoRead(void* data_out, int bytes_to_read, int& bytes_read) {
186 DCHECK_GT(bytes_to_read, 0);
187
188 // Read until the buffer is full or until Read() returns 0 to indicate no
189 // more data.
190 bytes_read = 0;
191 int read = 0;
192 do {
193 read = static_cast<int>(
194 stream_->Read(static_cast<char*>(data_out) + bytes_read, 1,
195 bytes_to_read - bytes_read));
196 bytes_read += read;
197 } while (read != 0 && bytes_read < bytes_to_read);
198
199 return (bytes_read > 0);
200 }
201
202 const Mode mode_;
203
204 const int status_code_;
205 const CefString status_text_;
206 const CefString mime_type_;
207 const CefResponse::HeaderMap header_map_;
208 const CefRefPtr<CefStreamReader> stream_;
209
210 base::OnceClosure destroy_callback_;
211 int cancel_ct_ = 0;
212
213 IMPLEMENT_REFCOUNTING(CallbackResourceHandler);
214 DISALLOW_COPY_AND_ASSIGN(CallbackResourceHandler);
215 };
216
217 // Resource handler implementation that never completes. Used to test
218 // destruction handling behavior for in-progress requests.
219 class IncompleteResourceHandlerOld : public CefResourceHandler {
220 public:
221 enum TestMode {
222 BLOCK_PROCESS_REQUEST,
223 BLOCK_READ_RESPONSE,
224 };
225
IncompleteResourceHandlerOld(TestMode test_mode,const std::string & mime_type,base::OnceClosure destroy_callback)226 IncompleteResourceHandlerOld(TestMode test_mode,
227 const std::string& mime_type,
228 base::OnceClosure destroy_callback)
229 : test_mode_(test_mode),
230 mime_type_(mime_type),
231 destroy_callback_(std::move(destroy_callback)) {}
232
~IncompleteResourceHandlerOld()233 ~IncompleteResourceHandlerOld() override {
234 EXPECT_EQ(1, process_request_ct_);
235
236 EXPECT_EQ(1, cancel_ct_);
237
238 if (test_mode_ == BLOCK_READ_RESPONSE) {
239 EXPECT_EQ(1, get_response_headers_ct_);
240 EXPECT_EQ(1, read_response_ct_);
241 } else {
242 EXPECT_EQ(0, get_response_headers_ct_);
243 EXPECT_EQ(0, read_response_ct_);
244 }
245
246 std::move(destroy_callback_).Run();
247 }
248
ProcessRequest(CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)249 bool ProcessRequest(CefRefPtr<CefRequest> request,
250 CefRefPtr<CefCallback> callback) override {
251 EXPECT_IO_THREAD();
252
253 process_request_ct_++;
254
255 if (test_mode_ == BLOCK_PROCESS_REQUEST) {
256 // Never release or execute this callback.
257 incomplete_callback_ = callback;
258 } else {
259 callback->Continue();
260 }
261 return true;
262 }
263
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)264 void GetResponseHeaders(CefRefPtr<CefResponse> response,
265 int64& response_length,
266 CefString& redirectUrl) override {
267 EXPECT_IO_THREAD();
268 EXPECT_EQ(test_mode_, BLOCK_READ_RESPONSE);
269
270 get_response_headers_ct_++;
271
272 response->SetStatus(200);
273 response->SetStatusText("OK");
274 response->SetMimeType(mime_type_);
275 response_length = 100;
276 }
277
ReadResponse(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefCallback> callback)278 bool ReadResponse(void* data_out,
279 int bytes_to_read,
280 int& bytes_read,
281 CefRefPtr<CefCallback> callback) override {
282 EXPECT_IO_THREAD();
283 EXPECT_EQ(test_mode_, BLOCK_READ_RESPONSE);
284
285 read_response_ct_++;
286
287 // Never release or execute this callback.
288 incomplete_callback_ = callback;
289 bytes_read = 0;
290 return true;
291 }
292
Cancel()293 void Cancel() override {
294 EXPECT_IO_THREAD();
295 cancel_ct_++;
296 }
297
298 private:
299 const TestMode test_mode_;
300 const std::string mime_type_;
301 base::OnceClosure destroy_callback_;
302
303 int process_request_ct_ = 0;
304 int get_response_headers_ct_ = 0;
305 int read_response_ct_ = 0;
306 int cancel_ct_ = 0;
307
308 CefRefPtr<CefCallback> incomplete_callback_;
309
310 IMPLEMENT_REFCOUNTING(IncompleteResourceHandlerOld);
311 DISALLOW_COPY_AND_ASSIGN(IncompleteResourceHandlerOld);
312 };
313
314 class IncompleteResourceHandler : public CefResourceHandler {
315 public:
316 enum TestMode {
317 BLOCK_OPEN,
318 BLOCK_READ,
319 };
320
IncompleteResourceHandler(TestMode test_mode,const std::string & mime_type,base::OnceClosure destroy_callback)321 IncompleteResourceHandler(TestMode test_mode,
322 const std::string& mime_type,
323 base::OnceClosure destroy_callback)
324 : test_mode_(test_mode),
325 mime_type_(mime_type),
326 destroy_callback_(std::move(destroy_callback)) {}
327
~IncompleteResourceHandler()328 ~IncompleteResourceHandler() override {
329 EXPECT_EQ(1, open_ct_);
330
331 EXPECT_EQ(1, cancel_ct_);
332
333 if (test_mode_ == BLOCK_READ) {
334 EXPECT_EQ(1, get_response_headers_ct_);
335 EXPECT_EQ(1, read_ct_);
336 } else {
337 EXPECT_EQ(0, get_response_headers_ct_);
338 EXPECT_EQ(0, read_ct_);
339 }
340
341 std::move(destroy_callback_).Run();
342 }
343
Open(CefRefPtr<CefRequest> request,bool & handle_request,CefRefPtr<CefCallback> callback)344 bool Open(CefRefPtr<CefRequest> request,
345 bool& handle_request,
346 CefRefPtr<CefCallback> callback) override {
347 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
348
349 open_ct_++;
350
351 if (test_mode_ == BLOCK_OPEN) {
352 // Never release or execute this callback.
353 incomplete_open_callback_ = callback;
354 } else {
355 // Continue immediately.
356 handle_request = true;
357 }
358 return true;
359 }
360
ProcessRequest(CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)361 bool ProcessRequest(CefRefPtr<CefRequest> request,
362 CefRefPtr<CefCallback> callback) override {
363 EXPECT_TRUE(false); // Not reached.
364 return false;
365 }
366
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)367 void GetResponseHeaders(CefRefPtr<CefResponse> response,
368 int64& response_length,
369 CefString& redirectUrl) override {
370 EXPECT_IO_THREAD();
371 EXPECT_EQ(test_mode_, BLOCK_READ);
372
373 get_response_headers_ct_++;
374
375 response->SetStatus(200);
376 response->SetStatusText("OK");
377 response->SetMimeType(mime_type_);
378 response_length = 100;
379 }
380
Read(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefResourceReadCallback> callback)381 bool Read(void* data_out,
382 int bytes_to_read,
383 int& bytes_read,
384 CefRefPtr<CefResourceReadCallback> callback) override {
385 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
386 EXPECT_EQ(test_mode_, BLOCK_READ);
387
388 read_ct_++;
389
390 // Never release or execute this callback.
391 incomplete_read_callback_ = callback;
392 bytes_read = 0;
393 return true;
394 }
395
ReadResponse(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefCallback> callback)396 bool ReadResponse(void* data_out,
397 int bytes_to_read,
398 int& bytes_read,
399 CefRefPtr<CefCallback> callback) override {
400 EXPECT_TRUE(false); // Not reached.
401 bytes_read = -2;
402 return false;
403 }
404
Cancel()405 void Cancel() override {
406 EXPECT_IO_THREAD();
407 cancel_ct_++;
408 }
409
410 private:
411 const TestMode test_mode_;
412 const std::string mime_type_;
413 base::OnceClosure destroy_callback_;
414
415 int open_ct_ = 0;
416 int get_response_headers_ct_ = 0;
417 int read_ct_ = 0;
418 int cancel_ct_ = 0;
419
420 CefRefPtr<CefCallback> incomplete_open_callback_;
421 CefRefPtr<CefResourceReadCallback> incomplete_read_callback_;
422
423 IMPLEMENT_REFCOUNTING(IncompleteResourceHandler);
424 DISALLOW_COPY_AND_ASSIGN(IncompleteResourceHandler);
425 };
426
427 class BasicResponseTest : public TestHandler {
428 public:
429 enum TestMode {
430 // Normal load, nothing fancy.
431 LOAD,
432
433 // Close the browser in OnAfterCreated to verify destruction handling of
434 // uninitialized requests.
435 ABORT_AFTER_CREATED,
436
437 // Close the browser in OnBeforeBrowse to verify destruction handling of
438 // uninitialized requests.
439 ABORT_BEFORE_BROWSE,
440
441 // Don't continue from OnBeforeResourceLoad, then close the browser to
442 // verify destruction handling of in-progress requests.
443 INCOMPLETE_BEFORE_RESOURCE_LOAD,
444
445 // Modify the request (add headers) in OnBeforeResourceLoad.
446 MODIFY_BEFORE_RESOURCE_LOAD,
447
448 // Redirect the request (change the URL) in OnBeforeResourceLoad.
449 REDIRECT_BEFORE_RESOURCE_LOAD,
450
451 // Return a CefResourceHandler from GetResourceHandler that continues
452 // immediately by using the callback object instead of the return value.
453 IMMEDIATE_REQUEST_HANDLER_OPEN,
454 IMMEDIATE_REQUEST_HANDLER_READ,
455 IMMEDIATE_REQUEST_HANDLER_ALL,
456
457 // Return a CefResourceHandler from GetResourceHandler that continues with
458 // a delay by using the callback object.
459 DELAYED_REQUEST_HANDLER_OPEN,
460 DELAYED_REQUEST_HANDLER_READ,
461 DELAYED_REQUEST_HANDLER_ALL,
462
463 // Return a CefResourceHandler from GetResourceHandler that never completes,
464 // then close the browser to verify destruction handling of in-progress
465 // requests.
466 INCOMPLETE_REQUEST_HANDLER_OPEN,
467 INCOMPLETE_REQUEST_HANDLER_READ,
468
469 // Redirect the request using a CefResourceHandler returned from
470 // GetResourceHandler.
471 REDIRECT_REQUEST_HANDLER,
472
473 // Redirect the request (change the URL) an additional time in
474 // OnResourceRedirect after using a CefResourceHandler returned from
475 // GetResourceHandler for the first redirect.
476 REDIRECT_RESOURCE_REDIRECT,
477
478 // Redirect the request (change the URL) in OnResourceResponse.
479 REDIRECT_RESOURCE_RESPONSE,
480
481 // Restart the request (add headers) in OnResourceResponse.
482 RESTART_RESOURCE_RESPONSE,
483 };
484
485 // If |custom_scheme| is true all requests will use a custom scheme.
486 // If |unhandled| is true the final request (after any redirects) will be
487 // unhandled, meaning that default handling is disabled and GetResourceHandler
488 // returns null.
BasicResponseTest(TestMode mode,bool custom_scheme,bool unhandled)489 BasicResponseTest(TestMode mode, bool custom_scheme, bool unhandled)
490 : mode_(mode), custom_scheme_(custom_scheme), unhandled_(unhandled) {}
491
RunTest()492 void RunTest() override {
493 CreateBrowser(GetStartupURL());
494 SetTestTimeout();
495 }
496
OnAfterCreated(CefRefPtr<CefBrowser> browser)497 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
498 EXPECT_UI_THREAD();
499 TestHandler::OnAfterCreated(browser);
500
501 if (mode_ == ABORT_AFTER_CREATED) {
502 SetSignalCompletionWhenAllBrowsersClose(false);
503 CloseBrowser(browser, false);
504 }
505 }
506
OnBeforeClose(CefRefPtr<CefBrowser> browser)507 void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
508 EXPECT_UI_THREAD();
509 TestHandler::OnBeforeClose(browser);
510
511 if (IsAborted()) {
512 DestroyTest();
513 }
514 }
515
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)516 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
517 CefRefPtr<CefFrame> frame,
518 CefRefPtr<CefRequest> request,
519 bool user_gesture,
520 bool is_redirect) override {
521 EXPECT_UI_THREAD();
522 if (browser_id_ == 0) {
523 // This is the first callback that provides a browser ID.
524 browser_id_ = browser->GetIdentifier();
525 EXPECT_GT(browser_id_, 0);
526 } else {
527 EXPECT_EQ(browser_id_, browser->GetIdentifier());
528 }
529 EXPECT_TRUE(frame->IsMain());
530
531 if (IsChromeRuntimeEnabled()) {
532 // With the Chrome runtime this is true on initial navigation via
533 // chrome::AddTabAt() and also true for clicked links.
534 EXPECT_TRUE(user_gesture);
535 } else {
536 EXPECT_FALSE(user_gesture);
537 }
538 if (on_before_browse_ct_ == 0 || mode_ == RESTART_RESOURCE_RESPONSE) {
539 EXPECT_FALSE(is_redirect) << on_before_browse_ct_;
540 } else {
541 EXPECT_TRUE(is_redirect) << on_before_browse_ct_;
542 }
543
544 on_before_browse_ct_++;
545
546 VerifyState(kOnBeforeBrowse, request, nullptr);
547
548 if (mode_ == ABORT_BEFORE_BROWSE) {
549 SetSignalCompletionWhenAllBrowsersClose(false);
550 CloseBrowser(browser, false);
551 }
552
553 return false;
554 }
555
GetResourceRequestHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool is_navigation,bool is_download,const CefString & request_initiator,bool & disable_default_handling)556 CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
557 CefRefPtr<CefBrowser> browser,
558 CefRefPtr<CefFrame> frame,
559 CefRefPtr<CefRequest> request,
560 bool is_navigation,
561 bool is_download,
562 const CefString& request_initiator,
563 bool& disable_default_handling) override {
564 EXPECT_IO_THREAD();
565 EXPECT_EQ(browser_id_, browser->GetIdentifier());
566 EXPECT_TRUE(frame->IsMain());
567
568 if (request_id_ == 0U) {
569 // This is the first callback that provides a request ID.
570 request_id_ = request->GetIdentifier();
571 EXPECT_GT(request_id_, 0U);
572 }
573
574 VerifyState(kGetResourceRequestHandler, request, nullptr);
575
576 EXPECT_TRUE(is_navigation);
577 EXPECT_FALSE(is_download);
578 EXPECT_STREQ("null", request_initiator.ToString().c_str());
579
580 // Check expected default value.
581 if (custom_scheme_) {
582 // There is no default handling for custom schemes.
583 EXPECT_TRUE(disable_default_handling);
584 } else {
585 EXPECT_FALSE(disable_default_handling);
586 // If |unhandled_| is true then we don't want default handling of requests
587 // (e.g. attempts to resolve over the network).
588 disable_default_handling = unhandled_;
589 }
590
591 get_resource_request_handler_ct_++;
592
593 return this;
594 }
595
GetCookieAccessFilter(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)596 CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter(
597 CefRefPtr<CefBrowser> browser,
598 CefRefPtr<CefFrame> frame,
599 CefRefPtr<CefRequest> request) override {
600 EXPECT_IO_THREAD();
601 EXPECT_EQ(browser_id_, browser->GetIdentifier());
602 EXPECT_TRUE(frame->IsMain());
603
604 VerifyState(kGetCookieAccessFilter, request, nullptr);
605
606 get_cookie_access_filter_ct_++;
607
608 return nullptr;
609 }
610
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)611 cef_return_value_t OnBeforeResourceLoad(
612 CefRefPtr<CefBrowser> browser,
613 CefRefPtr<CefFrame> frame,
614 CefRefPtr<CefRequest> request,
615 CefRefPtr<CefCallback> callback) override {
616 EXPECT_IO_THREAD();
617 if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
618 // Ignore favicon requests.
619 return RV_CANCEL;
620 }
621
622 EXPECT_EQ(browser_id_, browser->GetIdentifier());
623 EXPECT_TRUE(frame->IsMain());
624
625 VerifyState(kOnBeforeResourceLoad, request, nullptr);
626
627 on_before_resource_load_ct_++;
628
629 if (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD) {
630 incomplete_callback_ = callback;
631
632 // Close the browser asynchronously to complete the test.
633 CloseBrowserAsync();
634 return RV_CONTINUE_ASYNC;
635 }
636
637 if (mode_ == MODIFY_BEFORE_RESOURCE_LOAD) {
638 // Expect this data in the request for future callbacks.
639 SetCustomHeader(request);
640 } else if (mode_ == REDIRECT_BEFORE_RESOURCE_LOAD) {
641 // Redirect to this URL.
642 request->SetURL(GetURL(RESULT_HTML));
643 }
644
645 // Other continuation modes are tested by
646 // ResourceRequestHandlerTest.BeforeResourceLoad*.
647 return RV_CONTINUE;
648 }
649
GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)650 CefRefPtr<CefResourceHandler> GetResourceHandler(
651 CefRefPtr<CefBrowser> browser,
652 CefRefPtr<CefFrame> frame,
653 CefRefPtr<CefRequest> request) override {
654 EXPECT_IO_THREAD();
655 EXPECT_EQ(browser_id_, browser->GetIdentifier());
656 EXPECT_TRUE(frame->IsMain());
657
658 VerifyState(kGetResourceHandler, request, nullptr);
659
660 get_resource_handler_ct_++;
661
662 if (IsIncompleteRequestHandler()) {
663 // Close the browser asynchronously to complete the test.
664 CloseBrowserAsync();
665 return GetIncompleteResource();
666 }
667
668 const std::string& url = request->GetURL();
669 if (url == GetURL(RESULT_HTML) && mode_ == RESTART_RESOURCE_RESPONSE) {
670 if (get_resource_handler_ct_ == 1) {
671 // First request that will be restarted after response.
672 return GetOKResource();
673 } else {
674 // Restarted request.
675 if (unhandled_)
676 return nullptr;
677 return GetOKResource();
678 }
679 } else if (url == GetURL(RESULT_HTML)) {
680 if (unhandled_)
681 return nullptr;
682 return GetOKResource();
683 } else if (url == GetURL(REDIRECT_HTML) &&
684 mode_ == REDIRECT_RESOURCE_RESPONSE) {
685 if (get_resource_handler_ct_ == 1) {
686 // First request that will be redirected after response.
687 return GetOKResource();
688 } else {
689 // Redirected request.
690 if (unhandled_)
691 return nullptr;
692 return GetOKResource();
693 }
694 } else if (url == GetURL(REDIRECT_HTML) || url == GetURL(REDIRECT2_HTML)) {
695 std::string redirect_url;
696 if (mode_ == REDIRECT_REQUEST_HANDLER ||
697 mode_ == REDIRECT_RESOURCE_RESPONSE) {
698 EXPECT_STREQ(GetURL(REDIRECT_HTML), url.c_str());
699 redirect_url = GetURL(RESULT_HTML);
700 } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
701 EXPECT_STREQ(GetURL(REDIRECT2_HTML), url.c_str());
702 redirect_url = GetURL(REDIRECT_HTML);
703 } else {
704 NOTREACHED();
705 }
706
707 return GetRedirectResource(redirect_url);
708 } else {
709 NOTREACHED();
710 return nullptr;
711 }
712 }
713
OnResourceRedirect(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response,CefString & new_url)714 void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
715 CefRefPtr<CefFrame> frame,
716 CefRefPtr<CefRequest> request,
717 CefRefPtr<CefResponse> response,
718 CefString& new_url) override {
719 EXPECT_IO_THREAD();
720 EXPECT_EQ(browser_id_, browser->GetIdentifier());
721 EXPECT_TRUE(frame->IsMain());
722
723 VerifyState(kOnResourceRedirect, request, response);
724
725 if (mode_ == REDIRECT_REQUEST_HANDLER ||
726 mode_ == REDIRECT_RESOURCE_RESPONSE) {
727 // The URL redirected to from GetResourceHandler or OnResourceResponse.
728 EXPECT_STREQ(GetURL(RESULT_HTML), new_url.ToString().c_str());
729 } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
730 if (on_resource_redirect_ct_ == 0) {
731 // The URL redirected to from GetResourceHandler.
732 EXPECT_STREQ(GetURL(REDIRECT_HTML), new_url.ToString().c_str());
733 // Redirect again.
734 new_url = GetURL(RESULT_HTML);
735 } else {
736 NOTREACHED();
737 }
738 }
739
740 on_resource_redirect_ct_++;
741 }
742
OnResourceResponse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)743 bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
744 CefRefPtr<CefFrame> frame,
745 CefRefPtr<CefRequest> request,
746 CefRefPtr<CefResponse> response) override {
747 EXPECT_IO_THREAD();
748 EXPECT_EQ(browser_id_, browser->GetIdentifier());
749 EXPECT_TRUE(frame->IsMain());
750
751 VerifyState(kOnResourceResponse, request, response);
752
753 on_resource_response_ct_++;
754
755 if (on_resource_response_ct_ == 1) {
756 if (mode_ == REDIRECT_RESOURCE_RESPONSE) {
757 // Redirect the request to this URL.
758 request->SetURL(GetURL(RESULT_HTML));
759 return true;
760 } else if (mode_ == RESTART_RESOURCE_RESPONSE) {
761 // Restart the request loading this data.
762 SetCustomHeader(request);
763 return true;
764 }
765 }
766
767 return false;
768 }
769
GetResourceResponseFilter(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)770 CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
771 CefRefPtr<CefBrowser> browser,
772 CefRefPtr<CefFrame> frame,
773 CefRefPtr<CefRequest> request,
774 CefRefPtr<CefResponse> response) override {
775 EXPECT_IO_THREAD();
776 EXPECT_EQ(browser_id_, browser->GetIdentifier());
777 EXPECT_TRUE(frame->IsMain());
778
779 VerifyState(kGetResourceResponseFilter, request, response);
780
781 get_resource_response_filter_ct_++;
782
783 return nullptr;
784 }
785
OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response,URLRequestStatus status,int64 received_content_length)786 void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
787 CefRefPtr<CefFrame> frame,
788 CefRefPtr<CefRequest> request,
789 CefRefPtr<CefResponse> response,
790 URLRequestStatus status,
791 int64 received_content_length) override {
792 EXPECT_IO_THREAD();
793
794 if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
795 // Ignore favicon requests.
796 return;
797 }
798
799 EXPECT_EQ(browser_id_, browser->GetIdentifier());
800 EXPECT_TRUE(frame->IsMain());
801
802 VerifyState(kOnResourceLoadComplete, request, response);
803
804 if (unhandled_ || IsIncomplete() || (IsAborted() && status == UR_FAILED)) {
805 EXPECT_EQ(UR_FAILED, status);
806 EXPECT_EQ(0, received_content_length);
807 } else {
808 EXPECT_EQ(UR_SUCCESS, status);
809 EXPECT_EQ(static_cast<int64>(GetResponseBody().length()),
810 received_content_length);
811 }
812
813 on_resource_load_complete_ct_++;
814
815 if (IsIncomplete()) {
816 MaybeDestroyTest(false);
817 }
818 }
819
OnProtocolExecution(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool & allow_os_execution)820 void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
821 CefRefPtr<CefFrame> frame,
822 CefRefPtr<CefRequest> request,
823 bool& allow_os_execution) override {
824 EXPECT_IO_THREAD();
825 EXPECT_EQ(browser_id_, browser->GetIdentifier());
826 EXPECT_TRUE(frame->IsMain());
827
828 EXPECT_TRUE(custom_scheme_);
829 EXPECT_TRUE(unhandled_);
830
831 // Check expected default value.
832 EXPECT_FALSE(allow_os_execution);
833
834 VerifyState(kOnProtocolExecution, request, nullptr);
835 on_protocol_execution_ct_++;
836 }
837
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)838 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
839 CefRefPtr<CefFrame> frame,
840 int httpStatusCode) override {
841 EXPECT_UI_THREAD();
842 EXPECT_EQ(browser_id_, browser->GetIdentifier());
843 EXPECT_TRUE(frame->IsMain());
844
845 if (unhandled_)
846 EXPECT_EQ(httpStatusCode, 0);
847 else
848 EXPECT_EQ(httpStatusCode, 200);
849
850 on_load_end_ct_++;
851
852 TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
853 DestroyTest();
854 }
855
DestroyTest()856 void DestroyTest() override {
857 if (mode_ == RESTART_RESOURCE_RESPONSE) {
858 EXPECT_EQ(1, on_before_browse_ct_);
859 EXPECT_EQ(2, get_resource_request_handler_ct_);
860 EXPECT_EQ(2, get_cookie_access_filter_ct_);
861 EXPECT_EQ(2, on_before_resource_load_ct_);
862 EXPECT_EQ(2, get_resource_handler_ct_);
863 EXPECT_EQ(0, on_resource_redirect_ct_);
864 // Unhandled requests won't see a call to GetResourceResponseFilter or
865 // OnResourceResponse. In this case we're restarting from inside
866 // OnResourceResponse.
867 if (unhandled_) {
868 EXPECT_EQ(0, get_resource_response_filter_ct_);
869 EXPECT_EQ(1, on_resource_response_ct_);
870 } else {
871 EXPECT_EQ(1, get_resource_response_filter_ct_);
872 EXPECT_EQ(2, on_resource_response_ct_);
873 }
874 } else if (IsLoad()) {
875 EXPECT_EQ(1, on_before_browse_ct_);
876 EXPECT_EQ(1, get_resource_request_handler_ct_);
877 EXPECT_EQ(1, get_cookie_access_filter_ct_);
878 EXPECT_EQ(1, on_before_resource_load_ct_);
879 EXPECT_EQ(1, get_resource_handler_ct_);
880 EXPECT_EQ(0, on_resource_redirect_ct_);
881
882 // Unhandled requests won't see a call to GetResourceResponseFilter
883 // or OnResourceResponse.
884 if (unhandled_) {
885 EXPECT_EQ(0, get_resource_response_filter_ct_);
886 EXPECT_EQ(0, on_resource_response_ct_);
887 } else {
888 EXPECT_EQ(1, get_resource_response_filter_ct_);
889 EXPECT_EQ(1, on_resource_response_ct_);
890 }
891 } else if (IsRedirect()) {
892 EXPECT_EQ(2, on_before_browse_ct_);
893 EXPECT_EQ(2, get_resource_request_handler_ct_);
894 EXPECT_EQ(2, get_cookie_access_filter_ct_);
895 EXPECT_EQ(2, on_before_resource_load_ct_);
896 if (mode_ == REDIRECT_BEFORE_RESOURCE_LOAD) {
897 EXPECT_EQ(1, get_resource_handler_ct_);
898 } else {
899 EXPECT_EQ(2, get_resource_handler_ct_);
900 }
901 EXPECT_EQ(1, on_resource_redirect_ct_);
902
903 // Unhandled requests won't see a call to GetResourceResponseFilter.
904 if (unhandled_) {
905 EXPECT_EQ(0, get_resource_response_filter_ct_);
906 } else {
907 EXPECT_EQ(1, get_resource_response_filter_ct_);
908 }
909
910 // Unhandled requests won't see a call to OnResourceResponse.
911 if (mode_ == REDIRECT_RESOURCE_RESPONSE) {
912 // In this case we're redirecting from inside OnResourceResponse.
913 if (unhandled_) {
914 EXPECT_EQ(1, on_resource_response_ct_);
915 } else {
916 EXPECT_EQ(2, on_resource_response_ct_);
917 }
918 } else {
919 if (unhandled_) {
920 EXPECT_EQ(0, on_resource_response_ct_);
921 } else {
922 EXPECT_EQ(1, on_resource_response_ct_);
923 }
924 }
925 } else if (IsIncomplete()) {
926 EXPECT_EQ(1, on_before_browse_ct_);
927 EXPECT_EQ(1, get_resource_request_handler_ct_);
928 EXPECT_EQ(1, get_cookie_access_filter_ct_);
929 EXPECT_EQ(1, on_before_resource_load_ct_);
930
931 if (IsIncompleteRequestHandler()) {
932 EXPECT_EQ(1, get_resource_handler_ct_);
933 } else {
934 EXPECT_EQ(0, get_resource_handler_ct_);
935 }
936
937 EXPECT_EQ(0, on_resource_redirect_ct_);
938
939 if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ) {
940 EXPECT_EQ(1, get_resource_response_filter_ct_);
941 EXPECT_EQ(1, on_resource_response_ct_);
942 } else {
943 EXPECT_EQ(0, get_resource_response_filter_ct_);
944 EXPECT_EQ(0, on_resource_response_ct_);
945 }
946 } else if (IsAborted()) {
947 EXPECT_EQ(1, on_before_browse_ct_);
948 // The callbacks executed may vary based on timing.
949 EXPECT_NEAR(0, get_resource_request_handler_ct_, 1);
950 EXPECT_NEAR(0, get_cookie_access_filter_ct_, 1);
951 EXPECT_NEAR(0, on_before_resource_load_ct_, 1);
952 EXPECT_NEAR(0, get_resource_handler_ct_, 1);
953 EXPECT_NEAR(0, get_resource_response_filter_ct_, 1);
954 EXPECT_NEAR(0, on_resource_response_ct_, 1);
955 EXPECT_EQ(0, on_resource_redirect_ct_);
956 } else {
957 NOTREACHED();
958 }
959
960 if (IsAborted()) {
961 // The callbacks executed may vary based on timing.
962 EXPECT_NEAR(0, on_load_end_ct_, 1);
963 EXPECT_NEAR(resource_handler_created_ct_, resource_handler_destroyed_ct_,
964 1);
965 EXPECT_NEAR(0, on_resource_load_complete_ct_, 1);
966 } else {
967 EXPECT_EQ(resource_handler_created_ct_, resource_handler_destroyed_ct_);
968 EXPECT_EQ(1, on_resource_load_complete_ct_);
969 }
970
971 if (IsIncomplete()) {
972 EXPECT_EQ(0, on_load_end_ct_);
973 } else if (!IsAborted()) {
974 EXPECT_EQ(1, on_load_end_ct_);
975 }
976
977 if (custom_scheme_ && unhandled_ && !(IsIncomplete() || IsAborted())) {
978 EXPECT_EQ(1, on_protocol_execution_ct_);
979 } else if (IsAborted()) {
980 // The callbacks executed may vary based on timing.
981 EXPECT_NEAR(0, on_protocol_execution_ct_, 1);
982 } else {
983 EXPECT_EQ(0, on_protocol_execution_ct_);
984 }
985
986 TestHandler::DestroyTest();
987
988 if (!SignalCompletionWhenAllBrowsersClose()) {
989 // Complete asynchronously so the call stack has a chance to unwind.
990 CefPostTask(TID_UI,
991 base::BindOnce(&BasicResponseTest::TestComplete, this));
992 }
993 }
994
995 private:
996 enum TestUrl {
997 RESULT_HTML,
998 REDIRECT_HTML,
999 REDIRECT2_HTML,
1000 };
1001
GetURL(TestUrl url) const1002 const char* GetURL(TestUrl url) const {
1003 if (custom_scheme_) {
1004 if (url == RESULT_HTML)
1005 return "rrhcustom://test.com/result.html";
1006 if (url == REDIRECT_HTML)
1007 return "rrhcustom://test.com/redirect.html";
1008 if (url == REDIRECT2_HTML)
1009 return "rrhcustom://test.com/redirect2.html";
1010 } else {
1011 if (url == RESULT_HTML)
1012 return "http://test.com/result.html";
1013 if (url == REDIRECT_HTML)
1014 return "http://test.com/redirect.html";
1015 if (url == REDIRECT2_HTML)
1016 return "http://test.com/redirect2.html";
1017 }
1018
1019 NOTREACHED();
1020 return "";
1021 }
1022
GetStartupURL() const1023 const char* GetStartupURL() const {
1024 if (IsLoad() || IsIncomplete() || IsAborted()) {
1025 return GetURL(RESULT_HTML);
1026 } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
1027 return GetURL(REDIRECT2_HTML);
1028 } else if (IsRedirect()) {
1029 return GetURL(REDIRECT_HTML);
1030 }
1031
1032 NOTREACHED();
1033 return "";
1034 }
1035
GetResponseBody() const1036 std::string GetResponseBody() const {
1037 return "<html><body>Response</body></html>";
1038 }
GetRedirectBody() const1039 std::string GetRedirectBody() const {
1040 return "<html><body>Redirect</body></html>";
1041 }
1042
GetResourceDestroyCallback()1043 base::OnceClosure GetResourceDestroyCallback() {
1044 resource_handler_created_ct_++;
1045 return base::BindOnce(&BasicResponseTest::MaybeDestroyTest, this, true);
1046 }
1047
GetCallbackResourceHandlerMode(CallbackResourceHandler::Mode & mode)1048 bool GetCallbackResourceHandlerMode(CallbackResourceHandler::Mode& mode) {
1049 switch (mode_) {
1050 case IMMEDIATE_REQUEST_HANDLER_OPEN:
1051 mode = CallbackResourceHandler::IMMEDIATE_OPEN;
1052 return true;
1053 case IMMEDIATE_REQUEST_HANDLER_READ:
1054 mode = CallbackResourceHandler::IMMEDIATE_READ;
1055 return true;
1056 case IMMEDIATE_REQUEST_HANDLER_ALL:
1057 mode = CallbackResourceHandler::IMMEDIATE_ALL;
1058 return true;
1059 case DELAYED_REQUEST_HANDLER_OPEN:
1060 mode = CallbackResourceHandler::DELAYED_OPEN;
1061 return true;
1062 case DELAYED_REQUEST_HANDLER_READ:
1063 mode = CallbackResourceHandler::DELAYED_READ;
1064 return true;
1065 case DELAYED_REQUEST_HANDLER_ALL:
1066 mode = CallbackResourceHandler::DELAYED_ALL;
1067 return true;
1068 default:
1069 break;
1070 }
1071 return false;
1072 }
1073
GetResource(int status_code,const CefString & status_text,const CefString & mime_type,CefResponse::HeaderMap header_map,const std::string & body)1074 CefRefPtr<CefResourceHandler> GetResource(int status_code,
1075 const CefString& status_text,
1076 const CefString& mime_type,
1077 CefResponse::HeaderMap header_map,
1078 const std::string& body) {
1079 CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
1080 const_cast<char*>(body.c_str()), body.size());
1081
1082 CallbackResourceHandler::Mode handler_mode;
1083 if (GetCallbackResourceHandlerMode(handler_mode)) {
1084 return new CallbackResourceHandler(handler_mode, status_code, status_text,
1085 mime_type, header_map, stream,
1086 GetResourceDestroyCallback());
1087 }
1088
1089 return new NormalResourceHandler(status_code, status_text, mime_type,
1090 header_map, stream,
1091 GetResourceDestroyCallback());
1092 }
1093
GetOKResource()1094 CefRefPtr<CefResourceHandler> GetOKResource() {
1095 return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(),
1096 GetResponseBody());
1097 }
1098
GetRedirectResource(const std::string & redirect_url)1099 CefRefPtr<CefResourceHandler> GetRedirectResource(
1100 const std::string& redirect_url) {
1101 CefResponse::HeaderMap headerMap;
1102 headerMap.insert(std::make_pair("Location", redirect_url));
1103
1104 return GetResource(307, "Temporary Redirect", "text/html", headerMap,
1105 GetRedirectBody());
1106 }
1107
GetIncompleteResource()1108 CefRefPtr<CefResourceHandler> GetIncompleteResource() {
1109 if (TestOldResourceAPI()) {
1110 return new IncompleteResourceHandlerOld(
1111 mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN
1112 ? IncompleteResourceHandlerOld::BLOCK_PROCESS_REQUEST
1113 : IncompleteResourceHandlerOld::BLOCK_READ_RESPONSE,
1114 "text/html", GetResourceDestroyCallback());
1115 }
1116
1117 return new IncompleteResourceHandler(
1118 mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN
1119 ? IncompleteResourceHandler::BLOCK_OPEN
1120 : IncompleteResourceHandler::BLOCK_READ,
1121 "text/html", GetResourceDestroyCallback());
1122 }
1123
IsLoad() const1124 bool IsLoad() const {
1125 return mode_ == LOAD || mode_ == MODIFY_BEFORE_RESOURCE_LOAD ||
1126 mode_ == RESTART_RESOURCE_RESPONSE ||
1127 mode_ == IMMEDIATE_REQUEST_HANDLER_OPEN ||
1128 mode_ == IMMEDIATE_REQUEST_HANDLER_READ ||
1129 mode_ == IMMEDIATE_REQUEST_HANDLER_ALL ||
1130 mode_ == DELAYED_REQUEST_HANDLER_OPEN ||
1131 mode_ == DELAYED_REQUEST_HANDLER_READ ||
1132 mode_ == DELAYED_REQUEST_HANDLER_ALL;
1133 }
1134
IsIncompleteRequestHandler() const1135 bool IsIncompleteRequestHandler() const {
1136 return mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN ||
1137 mode_ == INCOMPLETE_REQUEST_HANDLER_READ;
1138 }
1139
IsIncomplete() const1140 bool IsIncomplete() const {
1141 return mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD ||
1142 IsIncompleteRequestHandler();
1143 }
1144
IsAborted() const1145 bool IsAborted() const {
1146 return mode_ == ABORT_AFTER_CREATED || mode_ == ABORT_BEFORE_BROWSE;
1147 }
1148
IsRedirect() const1149 bool IsRedirect() const {
1150 return mode_ == REDIRECT_BEFORE_RESOURCE_LOAD ||
1151 mode_ == REDIRECT_REQUEST_HANDLER ||
1152 mode_ == REDIRECT_RESOURCE_REDIRECT ||
1153 mode_ == REDIRECT_RESOURCE_RESPONSE;
1154 }
1155
SetCustomHeader(CefRefPtr<CefRequest> request)1156 static void SetCustomHeader(CefRefPtr<CefRequest> request) {
1157 EXPECT_FALSE(request->IsReadOnly());
1158 request->SetHeaderByName("X-Custom-Header", "value", false);
1159 }
1160
GetCustomHeader(CefRefPtr<CefRequest> request)1161 static std::string GetCustomHeader(CefRefPtr<CefRequest> request) {
1162 return request->GetHeaderByName("X-Custom-Header");
1163 }
1164
1165 // Resource-related callbacks.
1166 enum Callback {
1167 kOnBeforeBrowse,
1168 kGetResourceRequestHandler,
1169 kGetCookieAccessFilter,
1170 kOnBeforeResourceLoad,
1171 kGetResourceHandler,
1172 kOnResourceRedirect,
1173 kOnResourceResponse,
1174 kGetResourceResponseFilter,
1175 kOnResourceLoadComplete,
1176 kOnProtocolExecution,
1177 };
1178
ShouldHaveResponse(Callback callback) const1179 bool ShouldHaveResponse(Callback callback) const {
1180 return callback >= kOnResourceRedirect &&
1181 callback <= kOnResourceLoadComplete;
1182 }
1183
ShouldHaveWritableRequest(Callback callback) const1184 bool ShouldHaveWritableRequest(Callback callback) const {
1185 return callback == kOnBeforeResourceLoad || callback == kOnResourceResponse;
1186 }
1187
VerifyState(Callback callback,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response) const1188 void VerifyState(Callback callback,
1189 CefRefPtr<CefRequest> request,
1190 CefRefPtr<CefResponse> response) const {
1191 EXPECT_TRUE(request) << callback;
1192
1193 if (ShouldHaveResponse(callback)) {
1194 EXPECT_TRUE(response) << callback;
1195 EXPECT_TRUE(response->IsReadOnly()) << callback;
1196 } else {
1197 EXPECT_FALSE(response) << callback;
1198 }
1199
1200 if (ShouldHaveWritableRequest(callback)) {
1201 EXPECT_FALSE(request->IsReadOnly()) << callback;
1202 } else {
1203 EXPECT_TRUE(request->IsReadOnly()) << callback;
1204 }
1205
1206 if (callback == kOnBeforeBrowse) {
1207 // Browser-side navigation no longer exposes the actual request
1208 // information.
1209 EXPECT_EQ(0U, request->GetIdentifier()) << callback;
1210 } else {
1211 // All resource-related callbacks share the same request ID.
1212 EXPECT_EQ(request_id_, request->GetIdentifier()) << callback;
1213 }
1214
1215 if (IsLoad() || IsIncomplete() || IsAborted()) {
1216 EXPECT_STREQ("GET", request->GetMethod().ToString().c_str()) << callback;
1217 EXPECT_STREQ(GetURL(RESULT_HTML), request->GetURL().ToString().c_str())
1218 << callback;
1219
1220 // Expect the header for all callbacks following the callback that
1221 // initially sets it.
1222 const std::string& custom_header = GetCustomHeader(request);
1223 if ((mode_ == RESTART_RESOURCE_RESPONSE &&
1224 on_resource_response_ct_ > 0) ||
1225 (mode_ == MODIFY_BEFORE_RESOURCE_LOAD &&
1226 on_before_resource_load_ct_ > 0)) {
1227 EXPECT_STREQ("value", custom_header.c_str()) << callback;
1228 } else {
1229 EXPECT_STREQ("", custom_header.c_str()) << callback;
1230 }
1231
1232 if (response)
1233 VerifyOKResponse(callback, response);
1234 } else if (IsRedirect()) {
1235 EXPECT_STREQ("GET", request->GetMethod().ToString().c_str()) << callback;
1236 if (on_before_browse_ct_ == 1) {
1237 // Before the redirect.
1238 EXPECT_STREQ(GetStartupURL(), request->GetURL().ToString().c_str())
1239 << callback;
1240 } else if (on_before_browse_ct_ == 2) {
1241 // After the redirect.
1242 EXPECT_STREQ(GetURL(RESULT_HTML), request->GetURL().ToString().c_str())
1243 << callback;
1244 } else {
1245 NOTREACHED() << callback;
1246 }
1247
1248 if (response) {
1249 if (callback == kOnResourceRedirect) {
1250 // Before the redirect.
1251 VerifyRedirectResponse(callback, response);
1252 } else {
1253 // After the redirect.
1254 VerifyOKResponse(callback, response);
1255 }
1256 }
1257 } else {
1258 NOTREACHED() << callback;
1259 }
1260 }
1261
VerifyOKResponse(Callback callback,CefRefPtr<CefResponse> response) const1262 void VerifyOKResponse(Callback callback,
1263 CefRefPtr<CefResponse> response) const {
1264 const auto error_code = response->GetError();
1265
1266 // True for the first response in cases where we're redirecting/restarting
1267 // from inside OnResourceResponse (e.g. the first response always succeeds).
1268 const bool override_unhandled = unhandled_ &&
1269 (mode_ == REDIRECT_RESOURCE_RESPONSE ||
1270 mode_ == RESTART_RESOURCE_RESPONSE) &&
1271 get_resource_handler_ct_ == 1;
1272
1273 // True for tests where the request will be incomplete and never receive a
1274 // response.
1275 const bool incomplete_unhandled =
1276 (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD ||
1277 mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN ||
1278 (IsAborted() && !custom_scheme_ && error_code != ERR_NONE));
1279
1280 if ((unhandled_ && !override_unhandled) || incomplete_unhandled) {
1281 EXPECT_TRUE(ERR_ABORTED == error_code ||
1282 ERR_UNKNOWN_URL_SCHEME == error_code)
1283 << callback << error_code;
1284 EXPECT_EQ(0, response->GetStatus()) << callback;
1285 EXPECT_STREQ("", response->GetStatusText().ToString().c_str())
1286 << callback;
1287 EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
1288 EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback;
1289 EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
1290 } else {
1291 if ((mode_ == INCOMPLETE_REQUEST_HANDLER_READ || IsAborted()) &&
1292 callback == kOnResourceLoadComplete &&
1293 response->GetError() != ERR_NONE) {
1294 // We got a response, but we also got aborted.
1295 EXPECT_EQ(ERR_ABORTED, response->GetError()) << callback;
1296 } else {
1297 EXPECT_EQ(ERR_NONE, response->GetError()) << callback;
1298 }
1299 EXPECT_EQ(200, response->GetStatus()) << callback;
1300 EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str())
1301 << callback;
1302 EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
1303 EXPECT_STREQ("text/html", response->GetMimeType().ToString().c_str())
1304 << callback;
1305 EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
1306 }
1307 }
1308
VerifyRedirectResponse(Callback callback,CefRefPtr<CefResponse> response) const1309 void VerifyRedirectResponse(Callback callback,
1310 CefRefPtr<CefResponse> response) const {
1311 EXPECT_EQ(ERR_NONE, response->GetError()) << callback;
1312 EXPECT_EQ(307, response->GetStatus()) << callback;
1313 const std::string& status_text = response->GetStatusText();
1314 EXPECT_TRUE(status_text == "Internal Redirect" ||
1315 status_text == "Temporary Redirect")
1316 << status_text << callback;
1317 EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
1318 EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback;
1319 EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
1320 }
1321
CloseBrowserAsync()1322 void CloseBrowserAsync() {
1323 EXPECT_TRUE(IsIncomplete());
1324 SetSignalCompletionWhenAllBrowsersClose(false);
1325 CefPostDelayedTask(
1326 TID_UI, base::BindOnce(&TestHandler::CloseBrowser, GetBrowser(), false),
1327 100);
1328 }
1329
MaybeDestroyTest(bool from_handler)1330 void MaybeDestroyTest(bool from_handler) {
1331 if (!CefCurrentlyOn(TID_UI)) {
1332 CefPostTask(TID_UI, base::BindOnce(&BasicResponseTest::MaybeDestroyTest,
1333 this, from_handler));
1334 return;
1335 }
1336
1337 if (from_handler) {
1338 resource_handler_destroyed_ct_++;
1339 }
1340
1341 bool destroy_test = false;
1342 if (IsIncomplete()) {
1343 // Destroy the test if we got OnResourceLoadComplete and either the
1344 // resource handler will never complete or it was destroyed.
1345 destroy_test =
1346 on_resource_load_complete_ct_ > 0 &&
1347 (!IsIncompleteRequestHandler() ||
1348 resource_handler_destroyed_ct_ == resource_handler_created_ct_);
1349 } else {
1350 // Destroy the test if we got OnLoadEnd and the expected number of
1351 // resource handlers were destroyed.
1352 destroy_test = on_load_end_ct_ > 0 && resource_handler_destroyed_ct_ ==
1353 resource_handler_created_ct_;
1354 }
1355
1356 if (destroy_test) {
1357 DestroyTest();
1358 }
1359 }
1360
1361 const TestMode mode_;
1362 const bool custom_scheme_;
1363 const bool unhandled_;
1364
1365 int browser_id_ = 0;
1366 uint64 request_id_ = 0U;
1367
1368 int resource_handler_created_ct_ = 0;
1369
1370 int on_before_browse_ct_ = 0;
1371 int on_load_end_ct_ = 0;
1372
1373 int get_resource_request_handler_ct_ = 0;
1374 int on_before_resource_load_ct_ = 0;
1375 int get_cookie_access_filter_ct_ = 0;
1376 int get_resource_handler_ct_ = 0;
1377 int on_resource_redirect_ct_ = 0;
1378 int on_resource_response_ct_ = 0;
1379 int get_resource_response_filter_ct_ = 0;
1380 int on_resource_load_complete_ct_ = 0;
1381 int on_protocol_execution_ct_ = 0;
1382 int resource_handler_destroyed_ct_ = 0;
1383
1384 // Used with INCOMPLETE_BEFORE_RESOURCE_LOAD.
1385 CefRefPtr<CefCallback> incomplete_callback_;
1386
1387 DISALLOW_COPY_AND_ASSIGN(BasicResponseTest);
1388 IMPLEMENT_REFCOUNTING(BasicResponseTest);
1389 };
1390
1391 } // namespace
1392
1393 #define BASIC_TEST(name, test_mode, custom, unhandled) \
1394 TEST(ResourceRequestHandlerTest, Basic##name) { \
1395 CefRefPtr<BasicResponseTest> handler = new BasicResponseTest( \
1396 BasicResponseTest::test_mode, custom, unhandled); \
1397 handler->ExecuteTest(); \
1398 ReleaseAndWaitForDestructor(handler); \
1399 }
1400
1401 #define BASIC_TEST_ALL_MODES(name, custom, unhandled) \
1402 BASIC_TEST(name##Load, LOAD, custom, unhandled) \
1403 BASIC_TEST(name##AbortAfterCreated, ABORT_AFTER_CREATED, custom, unhandled) \
1404 BASIC_TEST(name##AbortBeforeBrowse, ABORT_BEFORE_BROWSE, custom, unhandled) \
1405 BASIC_TEST(name##ModifyBeforeResourceLoad, MODIFY_BEFORE_RESOURCE_LOAD, \
1406 custom, unhandled) \
1407 BASIC_TEST(name##RedirectBeforeResourceLoad, REDIRECT_BEFORE_RESOURCE_LOAD, \
1408 custom, unhandled) \
1409 BASIC_TEST(name##RedirectRequestHandler, REDIRECT_REQUEST_HANDLER, custom, \
1410 unhandled) \
1411 BASIC_TEST(name##RedirectResourceRedirect, REDIRECT_RESOURCE_REDIRECT, \
1412 custom, unhandled) \
1413 BASIC_TEST(name##RedirectResourceResponse, REDIRECT_RESOURCE_RESPONSE, \
1414 custom, unhandled) \
1415 BASIC_TEST(name##RestartResourceResponse, RESTART_RESOURCE_RESPONSE, custom, \
1416 unhandled)
1417
1418 // Tests only supported in handled mode.
1419 #define BASIC_TEST_HANDLED_MODES(name, custom) \
1420 BASIC_TEST(name##ImmediateRequestHandlerOpen, \
1421 IMMEDIATE_REQUEST_HANDLER_OPEN, custom, false) \
1422 BASIC_TEST(name##ImmediateRequestHandlerRead, \
1423 IMMEDIATE_REQUEST_HANDLER_READ, custom, false) \
1424 BASIC_TEST(name##ImmediateRequestHandlerAll, IMMEDIATE_REQUEST_HANDLER_ALL, \
1425 custom, false) \
1426 BASIC_TEST(name##DelayedRequestHandlerOpen, DELAYED_REQUEST_HANDLER_OPEN, \
1427 custom, false) \
1428 BASIC_TEST(name##DelayedRequestHandlerRead, DELAYED_REQUEST_HANDLER_READ, \
1429 custom, false) \
1430 BASIC_TEST(name##DelayedRequestHandlerAll, DELAYED_REQUEST_HANDLER_ALL, \
1431 custom, false) \
1432 BASIC_TEST(name##IncompleteBeforeResourceLoad, \
1433 INCOMPLETE_BEFORE_RESOURCE_LOAD, custom, false) \
1434 BASIC_TEST(name##IncompleteRequestHandlerOpen, \
1435 INCOMPLETE_REQUEST_HANDLER_OPEN, custom, false) \
1436 BASIC_TEST(name##IncompleteRequestHandlerRead, \
1437 INCOMPLETE_REQUEST_HANDLER_READ, custom, false)
1438
1439 BASIC_TEST_ALL_MODES(StandardHandled, false, false)
1440 BASIC_TEST_ALL_MODES(StandardUnhandled, false, true)
1441 BASIC_TEST_ALL_MODES(CustomHandled, true, false)
1442 BASIC_TEST_ALL_MODES(CustomUnhandled, true, true)
1443
1444 BASIC_TEST_HANDLED_MODES(StandardHandled, false)
1445 BASIC_TEST_HANDLED_MODES(CustomHandled, true)
1446
1447 namespace {
1448
1449 const char kSubresourceProcessMsg[] = "SubresourceMsg";
1450
1451 class SubresourceResponseTest : public RoutingTestHandler {
1452 public:
1453 enum TestMode {
1454 // Normal load, nothing fancy.
1455 LOAD,
1456
1457 // Don't continue from OnBeforeResourceLoad, then close the browser to
1458 // verify destruction handling of in-progress requests.
1459 INCOMPLETE_BEFORE_RESOURCE_LOAD,
1460
1461 // Modify the request (add headers) in OnBeforeResourceLoad.
1462 MODIFY_BEFORE_RESOURCE_LOAD,
1463
1464 // Redirect the request (change the URL) in OnBeforeResourceLoad.
1465 REDIRECT_BEFORE_RESOURCE_LOAD,
1466
1467 // Return a CefResourceHandler from GetResourceHandler that continues
1468 // immediately by using the callback object instead of the return value.
1469 IMMEDIATE_REQUEST_HANDLER_OPEN,
1470 IMMEDIATE_REQUEST_HANDLER_READ,
1471 IMMEDIATE_REQUEST_HANDLER_ALL,
1472
1473 // Return a CefResourceHandler from GetResourceHandler that continues with
1474 // a delay by using the callback object.
1475 DELAYED_REQUEST_HANDLER_OPEN,
1476 DELAYED_REQUEST_HANDLER_READ,
1477 DELAYED_REQUEST_HANDLER_ALL,
1478
1479 // Return a CefResourceHandler from GetResourceHandler that never completes,
1480 // then close the browser to verify destruction handling of in-progress
1481 // requests.
1482 INCOMPLETE_REQUEST_HANDLER_OPEN,
1483 INCOMPLETE_REQUEST_HANDLER_READ,
1484
1485 // Redirect the request using a CefResourceHandler returned from
1486 // GetResourceHandler.
1487 REDIRECT_REQUEST_HANDLER,
1488
1489 // Redirect the request (change the URL) an additional time in
1490 // OnResourceRedirect after using a CefResourceHandler returned from
1491 // GetResourceHandler for the first redirect.
1492 REDIRECT_RESOURCE_REDIRECT,
1493
1494 // Redirect the request (change the URL) in OnResourceResponse.
1495 REDIRECT_RESOURCE_RESPONSE,
1496
1497 // Restart the request (add headers) in OnResourceResponse.
1498 RESTART_RESOURCE_RESPONSE,
1499 };
1500
1501 // If |custom_scheme| is true all requests will use a custom scheme.
1502 // If |unhandled| is true the final request (after any redirects) will be
1503 // unhandled, meaning that default handling is disabled and GetResourceHandler
1504 // returns null.
1505 // If |subframe| is true the resource will be loaded in an iframe.
SubresourceResponseTest(TestMode mode,bool custom_scheme,bool unhandled,bool subframe)1506 SubresourceResponseTest(TestMode mode,
1507 bool custom_scheme,
1508 bool unhandled,
1509 bool subframe)
1510 : mode_(mode),
1511 custom_scheme_(custom_scheme),
1512 unhandled_(unhandled),
1513 subframe_(subframe) {}
1514
RunTest()1515 void RunTest() override {
1516 CreateBrowser(GetMainURL());
1517 SetTestTimeout();
1518 }
1519
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)1520 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
1521 CefRefPtr<CefFrame> frame,
1522 CefRefPtr<CefRequest> request,
1523 bool user_gesture,
1524 bool is_redirect) override {
1525 EXPECT_UI_THREAD();
1526 if (browser_id_ == 0) {
1527 // This is the first callback that provides a browser ID.
1528 browser_id_ = browser->GetIdentifier();
1529 EXPECT_GT(browser_id_, 0);
1530 } else {
1531 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1532 }
1533
1534 const std::string& url = request->GetURL();
1535 if (IsMainURL(url)) {
1536 EXPECT_TRUE(frame->IsMain());
1537 } else if (IsSubURL(url)) {
1538 EXPECT_FALSE(frame->IsMain());
1539 EXPECT_TRUE(subframe_);
1540 } else {
1541 EXPECT_FALSE(true); // Not reached.
1542 }
1543
1544 if (IsChromeRuntimeEnabled() && IsMainURL(url)) {
1545 // With the Chrome runtime this is true on initial navigation via
1546 // chrome::AddTabAt() and also true for clicked links.
1547 EXPECT_TRUE(user_gesture);
1548 } else {
1549 EXPECT_FALSE(user_gesture);
1550 }
1551
1552 EXPECT_FALSE(is_redirect);
1553
1554 on_before_browse_ct_++;
1555 return false;
1556 }
1557
GetResourceRequestHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool is_navigation,bool is_download,const CefString & request_initiator,bool & disable_default_handling)1558 CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
1559 CefRefPtr<CefBrowser> browser,
1560 CefRefPtr<CefFrame> frame,
1561 CefRefPtr<CefRequest> request,
1562 bool is_navigation,
1563 bool is_download,
1564 const CefString& request_initiator,
1565 bool& disable_default_handling) override {
1566 EXPECT_IO_THREAD();
1567 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1568
1569 const std::string& url = request->GetURL();
1570 if (IgnoreURL(url))
1571 return nullptr;
1572
1573 const bool is_main_url = IsMainURL(url);
1574 const bool is_sub_url = IsSubURL(url);
1575
1576 if (is_main_url) {
1577 EXPECT_TRUE(frame->IsMain());
1578 } else if (is_sub_url) {
1579 EXPECT_FALSE(frame->IsMain());
1580 EXPECT_TRUE(subframe_);
1581 }
1582
1583 if (is_main_url || is_sub_url) {
1584 // Track the frame ID that we'll expect for resource callbacks.
1585 // Do this here instead of OnBeforeBrowse because OnBeforeBrowse may
1586 // return -4 (kInvalidFrameId) for the initial navigation.
1587 if (frame_id_ == 0) {
1588 if (subframe_) {
1589 if (is_sub_url)
1590 frame_id_ = frame->GetIdentifier();
1591 } else {
1592 frame_id_ = frame->GetIdentifier();
1593 }
1594 }
1595 return this;
1596 }
1597
1598 VerifyFrame(kGetResourceRequestHandler, frame);
1599
1600 if (request_id_ == 0U) {
1601 // This is the first callback that provides a request ID.
1602 request_id_ = request->GetIdentifier();
1603 EXPECT_GT(request_id_, 0U);
1604 }
1605
1606 VerifyState(kGetResourceRequestHandler, request, nullptr);
1607
1608 EXPECT_FALSE(is_navigation);
1609 EXPECT_FALSE(is_download);
1610 EXPECT_STREQ(GetOrigin(), request_initiator.ToString().c_str());
1611
1612 // Check expected default value.
1613 if (custom_scheme_) {
1614 // There is no default handling for custom schemes.
1615 EXPECT_TRUE(disable_default_handling);
1616 } else {
1617 EXPECT_FALSE(disable_default_handling);
1618 // If |unhandled_| is true then we don't want default handling of requests
1619 // (e.g. attempts to resolve over the network).
1620 disable_default_handling = unhandled_;
1621 }
1622
1623 get_resource_request_handler_ct_++;
1624
1625 return this;
1626 }
1627
GetCookieAccessFilter(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)1628 CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter(
1629 CefRefPtr<CefBrowser> browser,
1630 CefRefPtr<CefFrame> frame,
1631 CefRefPtr<CefRequest> request) override {
1632 EXPECT_IO_THREAD();
1633 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1634
1635 const std::string& url = request->GetURL();
1636 if (IgnoreURL(url))
1637 return nullptr;
1638
1639 if (IsMainURL(url)) {
1640 EXPECT_TRUE(frame->IsMain());
1641 return nullptr;
1642 } else if (IsSubURL(url)) {
1643 EXPECT_FALSE(frame->IsMain());
1644 EXPECT_TRUE(subframe_);
1645 return nullptr;
1646 }
1647
1648 VerifyFrame(kGetCookieAccessFilter, frame);
1649
1650 VerifyState(kGetCookieAccessFilter, request, nullptr);
1651
1652 get_cookie_access_filter_ct_++;
1653
1654 return nullptr;
1655 }
1656
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)1657 cef_return_value_t OnBeforeResourceLoad(
1658 CefRefPtr<CefBrowser> browser,
1659 CefRefPtr<CefFrame> frame,
1660 CefRefPtr<CefRequest> request,
1661 CefRefPtr<CefCallback> callback) override {
1662 EXPECT_IO_THREAD();
1663
1664 if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
1665 // Ignore favicon requests.
1666 return RV_CANCEL;
1667 }
1668
1669 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1670
1671 if (IsMainURL(request->GetURL())) {
1672 EXPECT_TRUE(frame->IsMain());
1673 return RV_CONTINUE;
1674 } else if (IsSubURL(request->GetURL())) {
1675 EXPECT_FALSE(frame->IsMain());
1676 EXPECT_TRUE(subframe_);
1677 return RV_CONTINUE;
1678 }
1679
1680 VerifyFrame(kOnBeforeResourceLoad, frame);
1681
1682 VerifyState(kOnBeforeResourceLoad, request, nullptr);
1683
1684 on_before_resource_load_ct_++;
1685
1686 if (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD) {
1687 incomplete_callback_ = callback;
1688
1689 // Close the browser asynchronously to complete the test.
1690 CloseBrowserAsync();
1691 return RV_CONTINUE_ASYNC;
1692 }
1693
1694 if (mode_ == MODIFY_BEFORE_RESOURCE_LOAD) {
1695 // Expect this data in the request for future callbacks.
1696 SetCustomHeader(request);
1697 } else if (mode_ == REDIRECT_BEFORE_RESOURCE_LOAD) {
1698 // Redirect to this URL.
1699 request->SetURL(GetURL(RESULT_JS));
1700 }
1701
1702 // Other continuation modes are tested by
1703 // ResourceRequestHandlerTest.BeforeResourceLoad*.
1704 return RV_CONTINUE;
1705 }
1706
GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)1707 CefRefPtr<CefResourceHandler> GetResourceHandler(
1708 CefRefPtr<CefBrowser> browser,
1709 CefRefPtr<CefFrame> frame,
1710 CefRefPtr<CefRequest> request) override {
1711 EXPECT_IO_THREAD();
1712 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1713
1714 if (IsMainURL(request->GetURL())) {
1715 EXPECT_TRUE(frame->IsMain());
1716 return GetMainResource();
1717 } else if (IsSubURL(request->GetURL())) {
1718 EXPECT_FALSE(frame->IsMain());
1719 EXPECT_TRUE(subframe_);
1720 return GetSubResource();
1721 }
1722
1723 VerifyFrame(kGetResourceHandler, frame);
1724
1725 VerifyState(kGetResourceHandler, request, nullptr);
1726
1727 get_resource_handler_ct_++;
1728
1729 if (IsIncompleteRequestHandler()) {
1730 // Close the browser asynchronously to complete the test.
1731 CloseBrowserAsync();
1732 return GetIncompleteResource();
1733 }
1734
1735 const std::string& url = request->GetURL();
1736 if (url == GetURL(RESULT_JS) && mode_ == RESTART_RESOURCE_RESPONSE) {
1737 if (get_resource_handler_ct_ == 1) {
1738 // First request that will be restarted after response.
1739 return GetOKResource();
1740 } else {
1741 // Restarted request.
1742 if (unhandled_)
1743 return nullptr;
1744 return GetOKResource();
1745 }
1746 } else if (url == GetURL(RESULT_JS)) {
1747 if (unhandled_)
1748 return nullptr;
1749 return GetOKResource();
1750 } else if (url == GetURL(REDIRECT_JS) &&
1751 mode_ == REDIRECT_RESOURCE_RESPONSE) {
1752 if (get_resource_handler_ct_ == 1) {
1753 // First request that will be redirected after response.
1754 return GetOKResource();
1755 } else {
1756 // Redirected request.
1757 if (unhandled_)
1758 return nullptr;
1759 return GetOKResource();
1760 }
1761 } else if (url == GetURL(REDIRECT_JS) || url == GetURL(REDIRECT2_JS)) {
1762 std::string redirect_url;
1763 if (mode_ == REDIRECT_REQUEST_HANDLER ||
1764 mode_ == REDIRECT_RESOURCE_RESPONSE) {
1765 EXPECT_STREQ(GetURL(REDIRECT_JS), url.c_str());
1766 redirect_url = GetURL(RESULT_JS);
1767 } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
1768 EXPECT_STREQ(GetURL(REDIRECT2_JS), url.c_str());
1769 redirect_url = GetURL(REDIRECT_JS);
1770 } else {
1771 NOTREACHED();
1772 }
1773
1774 return GetRedirectResource(redirect_url);
1775 } else {
1776 NOTREACHED();
1777 return nullptr;
1778 }
1779 }
1780
OnResourceRedirect(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response,CefString & new_url)1781 void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
1782 CefRefPtr<CefFrame> frame,
1783 CefRefPtr<CefRequest> request,
1784 CefRefPtr<CefResponse> response,
1785 CefString& new_url) override {
1786 EXPECT_IO_THREAD();
1787 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1788
1789 if (IsMainURL(request->GetURL()) || IsSubURL(request->GetURL())) {
1790 EXPECT_FALSE(true); // Not reached.
1791 return;
1792 }
1793
1794 VerifyFrame(kOnResourceRedirect, frame);
1795
1796 VerifyState(kOnResourceRedirect, request, response);
1797
1798 if (mode_ == REDIRECT_REQUEST_HANDLER ||
1799 mode_ == REDIRECT_RESOURCE_RESPONSE) {
1800 // The URL redirected to from GetResourceHandler or OnResourceResponse.
1801 EXPECT_STREQ(GetURL(RESULT_JS), new_url.ToString().c_str());
1802 } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
1803 if (on_resource_redirect_ct_ == 0) {
1804 // The URL redirected to from GetResourceHandler.
1805 EXPECT_STREQ(GetURL(REDIRECT_JS), new_url.ToString().c_str());
1806 // Redirect again.
1807 new_url = GetURL(RESULT_JS);
1808 } else {
1809 NOTREACHED();
1810 }
1811 }
1812
1813 on_resource_redirect_ct_++;
1814 }
1815
OnResourceResponse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)1816 bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
1817 CefRefPtr<CefFrame> frame,
1818 CefRefPtr<CefRequest> request,
1819 CefRefPtr<CefResponse> response) override {
1820 EXPECT_IO_THREAD();
1821 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1822
1823 if (IsMainURL(request->GetURL())) {
1824 EXPECT_TRUE(frame->IsMain());
1825 return false;
1826 } else if (IsSubURL(request->GetURL())) {
1827 EXPECT_FALSE(frame->IsMain());
1828 EXPECT_TRUE(subframe_);
1829 return false;
1830 }
1831
1832 VerifyFrame(kOnResourceResponse, frame);
1833
1834 VerifyState(kOnResourceResponse, request, response);
1835
1836 on_resource_response_ct_++;
1837
1838 if (on_resource_response_ct_ == 1) {
1839 if (mode_ == REDIRECT_RESOURCE_RESPONSE) {
1840 // Redirect the request to this URL.
1841 request->SetURL(GetURL(RESULT_JS));
1842 return true;
1843 } else if (mode_ == RESTART_RESOURCE_RESPONSE) {
1844 // Restart the request loading this data.
1845 SetCustomHeader(request);
1846 return true;
1847 }
1848 }
1849
1850 return false;
1851 }
1852
GetResourceResponseFilter(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)1853 CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
1854 CefRefPtr<CefBrowser> browser,
1855 CefRefPtr<CefFrame> frame,
1856 CefRefPtr<CefRequest> request,
1857 CefRefPtr<CefResponse> response) override {
1858 EXPECT_IO_THREAD();
1859 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1860
1861 if (IsMainURL(request->GetURL())) {
1862 EXPECT_TRUE(frame->IsMain());
1863 return nullptr;
1864 } else if (IsSubURL(request->GetURL())) {
1865 EXPECT_FALSE(frame->IsMain());
1866 EXPECT_TRUE(subframe_);
1867 return nullptr;
1868 }
1869
1870 VerifyFrame(kGetResourceResponseFilter, frame);
1871
1872 VerifyState(kGetResourceResponseFilter, request, response);
1873
1874 get_resource_response_filter_ct_++;
1875
1876 return nullptr;
1877 }
1878
OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response,URLRequestStatus status,int64 received_content_length)1879 void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
1880 CefRefPtr<CefFrame> frame,
1881 CefRefPtr<CefRequest> request,
1882 CefRefPtr<CefResponse> response,
1883 URLRequestStatus status,
1884 int64 received_content_length) override {
1885 EXPECT_IO_THREAD();
1886
1887 if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
1888 // Ignore favicon requests.
1889 return;
1890 }
1891
1892 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1893
1894 if (IsMainURL(request->GetURL())) {
1895 EXPECT_TRUE(frame->IsMain());
1896 EXPECT_EQ(UR_SUCCESS, status);
1897 EXPECT_EQ(static_cast<int64>(GetMainResponseBody().length()),
1898 received_content_length);
1899 return;
1900 } else if (IsSubURL(request->GetURL())) {
1901 EXPECT_FALSE(frame->IsMain());
1902 EXPECT_EQ(UR_SUCCESS, status);
1903 EXPECT_EQ(static_cast<int64>(GetSubResponseBody().length()),
1904 received_content_length);
1905 EXPECT_TRUE(subframe_);
1906 return;
1907 }
1908
1909 VerifyFrame(kOnResourceLoadComplete, frame);
1910
1911 VerifyState(kOnResourceLoadComplete, request, response);
1912
1913 if (unhandled_ || IsIncomplete()) {
1914 EXPECT_EQ(UR_FAILED, status);
1915 EXPECT_EQ(0, received_content_length);
1916 } else {
1917 EXPECT_EQ(UR_SUCCESS, status);
1918 EXPECT_EQ(static_cast<int64>(GetResponseBody().length()),
1919 received_content_length);
1920 }
1921
1922 on_resource_load_complete_ct_++;
1923
1924 if (IsIncomplete()) {
1925 MaybeDestroyTest(false);
1926 }
1927 }
1928
OnProtocolExecution(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool & allow_os_execution)1929 void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
1930 CefRefPtr<CefFrame> frame,
1931 CefRefPtr<CefRequest> request,
1932 bool& allow_os_execution) override {
1933 EXPECT_IO_THREAD();
1934 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1935
1936 if (IsMainURL(request->GetURL()) || IsSubURL(request->GetURL())) {
1937 EXPECT_FALSE(true); // Not reached.
1938 return;
1939 }
1940
1941 VerifyFrame(kOnProtocolExecution, frame);
1942
1943 EXPECT_TRUE(custom_scheme_);
1944 EXPECT_TRUE(unhandled_);
1945
1946 // Check expected default value.
1947 EXPECT_FALSE(allow_os_execution);
1948
1949 VerifyState(kOnProtocolExecution, request, nullptr);
1950 on_protocol_execution_ct_++;
1951 }
1952
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)1953 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
1954 CefRefPtr<CefFrame> frame,
1955 int httpStatusCode) override {
1956 EXPECT_UI_THREAD();
1957 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1958
1959 EXPECT_EQ(httpStatusCode, 200);
1960
1961 on_load_end_ct_++;
1962
1963 TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
1964 MaybeDestroyTest(false);
1965 }
1966
OnQuery(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int64 query_id,const CefString & request,bool persistent,CefRefPtr<Callback> callback)1967 bool OnQuery(CefRefPtr<CefBrowser> browser,
1968 CefRefPtr<CefFrame> frame,
1969 int64 query_id,
1970 const CefString& request,
1971 bool persistent,
1972 CefRefPtr<Callback> callback) override {
1973 EXPECT_UI_THREAD();
1974 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1975
1976 EXPECT_STREQ(kSubresourceProcessMsg, request.ToString().c_str());
1977
1978 VerifyFrame(kOnQuery, frame);
1979
1980 callback->Success("");
1981
1982 on_query_ct_++;
1983 MaybeDestroyTest(false);
1984
1985 return true;
1986 }
1987
DestroyTest()1988 void DestroyTest() override {
1989 // Only called for the main and/or sub frame load.
1990 if (subframe_) {
1991 EXPECT_EQ(2, on_before_browse_ct_);
1992 } else {
1993 EXPECT_EQ(1, on_before_browse_ct_);
1994 }
1995
1996 if (mode_ == RESTART_RESOURCE_RESPONSE) {
1997 EXPECT_EQ(2, get_resource_request_handler_ct_);
1998 EXPECT_EQ(2, get_cookie_access_filter_ct_);
1999 EXPECT_EQ(2, on_before_resource_load_ct_);
2000 EXPECT_EQ(2, get_resource_handler_ct_);
2001 EXPECT_EQ(0, on_resource_redirect_ct_);
2002 // Unhandled requests won't see a call to GetResourceResponseFilter or
2003 // OnResourceResponse. In this case we're restarting from inside
2004 // OnResourceResponse.
2005 if (unhandled_) {
2006 EXPECT_EQ(0, get_resource_response_filter_ct_);
2007 EXPECT_EQ(1, on_resource_response_ct_);
2008 } else {
2009 EXPECT_EQ(1, get_resource_response_filter_ct_);
2010 EXPECT_EQ(2, on_resource_response_ct_);
2011 }
2012 } else if (IsLoad()) {
2013 EXPECT_EQ(1, get_resource_request_handler_ct_);
2014 EXPECT_EQ(1, get_cookie_access_filter_ct_);
2015 EXPECT_EQ(1, on_before_resource_load_ct_);
2016 EXPECT_EQ(1, get_resource_handler_ct_);
2017 EXPECT_EQ(0, on_resource_redirect_ct_);
2018 // Unhandled requests won't see a call to GetResourceResponseFilter or
2019 // OnResourceResponse.
2020 if (unhandled_) {
2021 EXPECT_EQ(0, get_resource_response_filter_ct_);
2022 EXPECT_EQ(0, on_resource_response_ct_);
2023 } else {
2024 EXPECT_EQ(1, get_resource_response_filter_ct_);
2025 EXPECT_EQ(1, on_resource_response_ct_);
2026 }
2027 } else if (IsRedirect()) {
2028 EXPECT_EQ(2, get_resource_request_handler_ct_);
2029 EXPECT_EQ(2, get_cookie_access_filter_ct_);
2030 EXPECT_EQ(2, on_before_resource_load_ct_);
2031 if (mode_ == REDIRECT_BEFORE_RESOURCE_LOAD) {
2032 EXPECT_EQ(1, get_resource_handler_ct_);
2033 } else {
2034 EXPECT_EQ(2, get_resource_handler_ct_);
2035 }
2036 EXPECT_EQ(1, on_resource_redirect_ct_);
2037
2038 // Unhandled requests won't see a call to GetResourceResponseFilter.
2039 if (unhandled_)
2040 EXPECT_EQ(0, get_resource_response_filter_ct_);
2041 else
2042 EXPECT_EQ(1, get_resource_response_filter_ct_);
2043
2044 // Unhandled requests won't see a call to OnResourceResponse.
2045 if (mode_ == REDIRECT_RESOURCE_RESPONSE) {
2046 // In this case we're redirecting from inside OnResourceResponse.
2047 if (unhandled_)
2048 EXPECT_EQ(1, on_resource_response_ct_);
2049 else
2050 EXPECT_EQ(2, on_resource_response_ct_);
2051 } else {
2052 if (unhandled_)
2053 EXPECT_EQ(0, on_resource_response_ct_);
2054 else
2055 EXPECT_EQ(1, on_resource_response_ct_);
2056 }
2057 } else if (IsIncomplete()) {
2058 EXPECT_EQ(1, get_resource_request_handler_ct_);
2059 EXPECT_EQ(1, get_cookie_access_filter_ct_);
2060 EXPECT_EQ(1, on_before_resource_load_ct_);
2061
2062 if (IsIncompleteRequestHandler()) {
2063 EXPECT_EQ(1, get_resource_handler_ct_);
2064 } else {
2065 EXPECT_EQ(0, get_resource_handler_ct_);
2066 }
2067
2068 EXPECT_EQ(0, on_resource_redirect_ct_);
2069
2070 if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ) {
2071 EXPECT_EQ(1, get_resource_response_filter_ct_);
2072 EXPECT_EQ(1, on_resource_response_ct_);
2073 } else {
2074 EXPECT_EQ(0, get_resource_response_filter_ct_);
2075 EXPECT_EQ(0, on_resource_response_ct_);
2076 }
2077 } else {
2078 NOTREACHED();
2079 }
2080
2081 EXPECT_EQ(resource_handler_created_ct_, resource_handler_destroyed_ct_);
2082 EXPECT_EQ(1, on_resource_load_complete_ct_);
2083
2084 // Only called for the main and/or sub frame load.
2085 if (IsIncomplete()) {
2086 EXPECT_EQ(0, on_load_end_ct_);
2087 } else {
2088 if (subframe_) {
2089 EXPECT_EQ(2, on_load_end_ct_);
2090 } else {
2091 EXPECT_EQ(1, on_load_end_ct_);
2092 }
2093 }
2094
2095 if (unhandled_ || IsIncomplete()) {
2096 EXPECT_EQ(0, on_query_ct_);
2097 } else {
2098 EXPECT_EQ(1, on_query_ct_);
2099 }
2100
2101 if (custom_scheme_ && unhandled_ && !IsIncomplete()) {
2102 EXPECT_EQ(1, on_protocol_execution_ct_);
2103 } else {
2104 EXPECT_EQ(0, on_protocol_execution_ct_);
2105 }
2106
2107 TestHandler::DestroyTest();
2108
2109 if (!SignalCompletionWhenAllBrowsersClose()) {
2110 // Complete asynchronously so the call stack has a chance to unwind.
2111 CefPostTask(TID_UI,
2112 base::BindOnce(&SubresourceResponseTest::TestComplete, this));
2113 }
2114 }
2115
2116 private:
GetMainURL() const2117 const char* GetMainURL() const {
2118 if (custom_scheme_) {
2119 return "rrhcustom://test.com/main.html";
2120 } else {
2121 return "http://test.com/main.html";
2122 }
2123 }
2124
GetSubURL() const2125 const char* GetSubURL() const {
2126 if (custom_scheme_) {
2127 return "rrhcustom://test.com/subframe.html";
2128 } else {
2129 return "http://test.com/subframe.html";
2130 }
2131 }
2132
GetOrigin() const2133 const char* GetOrigin() const {
2134 if (custom_scheme_) {
2135 return "rrhcustom://test.com";
2136 } else {
2137 return "http://test.com";
2138 }
2139 }
2140
IsMainURL(const std::string & url) const2141 bool IsMainURL(const std::string& url) const { return url == GetMainURL(); }
IsSubURL(const std::string & url) const2142 bool IsSubURL(const std::string& url) const { return url == GetSubURL(); }
2143
2144 enum TestUrl {
2145 RESULT_JS,
2146 REDIRECT_JS,
2147 REDIRECT2_JS,
2148 };
2149
GetURL(TestUrl url) const2150 const char* GetURL(TestUrl url) const {
2151 if (custom_scheme_) {
2152 if (url == RESULT_JS)
2153 return "rrhcustom://test.com/result.js";
2154 if (url == REDIRECT_JS)
2155 return "rrhcustom://test.com/redirect.js";
2156 if (url == REDIRECT2_JS)
2157 return "rrhcustom://test.com/redirect2.js";
2158 } else {
2159 if (url == RESULT_JS)
2160 return "http://test.com/result.js";
2161 if (url == REDIRECT_JS)
2162 return "http://test.com/redirect.js";
2163 if (url == REDIRECT2_JS)
2164 return "http://test.com/redirect2.js";
2165 }
2166
2167 NOTREACHED();
2168 return "";
2169 }
2170
GetStartupURL() const2171 const char* GetStartupURL() const {
2172 if (IsLoad() || IsIncomplete()) {
2173 return GetURL(RESULT_JS);
2174 } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
2175 return GetURL(REDIRECT2_JS);
2176 } else if (IsRedirect()) {
2177 return GetURL(REDIRECT_JS);
2178 }
2179
2180 NOTREACHED();
2181 return "";
2182 }
2183
GetMainResponseBody() const2184 std::string GetMainResponseBody() const {
2185 std::stringstream html;
2186 html << "<html><head>";
2187
2188 if (subframe_) {
2189 const std::string& url = GetSubURL();
2190 html << "<iframe src=\"" << url << "\"></iframe>";
2191 } else {
2192 const std::string& url = GetStartupURL();
2193 html << "<script type=\"text/javascript\" src=\"" << url
2194 << "\"></script>";
2195 }
2196
2197 html << "</head><body><p>Main</p></body></html>";
2198 return html.str();
2199 }
2200
GetSubResponseBody() const2201 std::string GetSubResponseBody() const {
2202 DCHECK(subframe_);
2203
2204 std::stringstream html;
2205 html << "<html><head>";
2206
2207 const std::string& url = GetStartupURL();
2208 html << "<script type=\"text/javascript\" src=\"" << url << "\"></script>";
2209
2210 html << "</head><body><p>Sub</p></body></html>";
2211 return html.str();
2212 }
2213
GetResponseBody() const2214 std::string GetResponseBody() const {
2215 return "window.testQuery({request:'" + std::string(kSubresourceProcessMsg) +
2216 "'});";
2217 }
GetRedirectBody() const2218 std::string GetRedirectBody() const {
2219 return "<html><body>Redirect</body></html>";
2220 }
2221
GetResourceDestroyCallback()2222 base::OnceClosure GetResourceDestroyCallback() {
2223 resource_handler_created_ct_++;
2224 return base::BindOnce(&SubresourceResponseTest::MaybeDestroyTest, this,
2225 true);
2226 }
2227
GetCallbackResourceHandlerMode(CallbackResourceHandler::Mode & mode)2228 bool GetCallbackResourceHandlerMode(CallbackResourceHandler::Mode& mode) {
2229 switch (mode_) {
2230 case IMMEDIATE_REQUEST_HANDLER_OPEN:
2231 mode = CallbackResourceHandler::IMMEDIATE_OPEN;
2232 return true;
2233 case IMMEDIATE_REQUEST_HANDLER_READ:
2234 mode = CallbackResourceHandler::IMMEDIATE_READ;
2235 return true;
2236 case IMMEDIATE_REQUEST_HANDLER_ALL:
2237 mode = CallbackResourceHandler::IMMEDIATE_ALL;
2238 return true;
2239 case DELAYED_REQUEST_HANDLER_OPEN:
2240 mode = CallbackResourceHandler::DELAYED_OPEN;
2241 return true;
2242 case DELAYED_REQUEST_HANDLER_READ:
2243 mode = CallbackResourceHandler::DELAYED_READ;
2244 return true;
2245 case DELAYED_REQUEST_HANDLER_ALL:
2246 mode = CallbackResourceHandler::DELAYED_ALL;
2247 return true;
2248 default:
2249 break;
2250 }
2251 return false;
2252 }
2253
GetResource(int status_code,const CefString & status_text,const CefString & mime_type,CefResponse::HeaderMap header_map,const std::string & body)2254 CefRefPtr<CefResourceHandler> GetResource(int status_code,
2255 const CefString& status_text,
2256 const CefString& mime_type,
2257 CefResponse::HeaderMap header_map,
2258 const std::string& body) {
2259 CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
2260 const_cast<char*>(body.c_str()), body.size());
2261
2262 CallbackResourceHandler::Mode handler_mode;
2263 if (GetCallbackResourceHandlerMode(handler_mode)) {
2264 return new CallbackResourceHandler(handler_mode, status_code, status_text,
2265 mime_type, header_map, stream,
2266 GetResourceDestroyCallback());
2267 }
2268
2269 return new NormalResourceHandler(status_code, status_text, mime_type,
2270 header_map, stream,
2271 GetResourceDestroyCallback());
2272 }
2273
GetMainResource()2274 CefRefPtr<CefResourceHandler> GetMainResource() {
2275 return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(),
2276 GetMainResponseBody());
2277 }
2278
GetSubResource()2279 CefRefPtr<CefResourceHandler> GetSubResource() {
2280 return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(),
2281 GetSubResponseBody());
2282 }
2283
GetOKResource()2284 CefRefPtr<CefResourceHandler> GetOKResource() {
2285 return GetResource(200, "OK", "text/javascript", CefResponse::HeaderMap(),
2286 GetResponseBody());
2287 }
2288
GetRedirectResource(const std::string & redirect_url)2289 CefRefPtr<CefResourceHandler> GetRedirectResource(
2290 const std::string& redirect_url) {
2291 CefResponse::HeaderMap headerMap;
2292 headerMap.insert(std::make_pair("Location", redirect_url));
2293
2294 return GetResource(307, "Temporary Redirect", "text/javascript", headerMap,
2295 GetRedirectBody());
2296 }
2297
GetIncompleteResource()2298 CefRefPtr<CefResourceHandler> GetIncompleteResource() {
2299 if (TestOldResourceAPI()) {
2300 return new IncompleteResourceHandlerOld(
2301 mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN
2302 ? IncompleteResourceHandlerOld::BLOCK_PROCESS_REQUEST
2303 : IncompleteResourceHandlerOld::BLOCK_READ_RESPONSE,
2304 "text/javascript", GetResourceDestroyCallback());
2305 }
2306
2307 return new IncompleteResourceHandler(
2308 mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN
2309 ? IncompleteResourceHandler::BLOCK_OPEN
2310 : IncompleteResourceHandler::BLOCK_READ,
2311 "text/javascript", GetResourceDestroyCallback());
2312 }
2313
IsLoad() const2314 bool IsLoad() const {
2315 return mode_ == LOAD || mode_ == MODIFY_BEFORE_RESOURCE_LOAD ||
2316 mode_ == RESTART_RESOURCE_RESPONSE ||
2317 mode_ == IMMEDIATE_REQUEST_HANDLER_OPEN ||
2318 mode_ == IMMEDIATE_REQUEST_HANDLER_READ ||
2319 mode_ == IMMEDIATE_REQUEST_HANDLER_ALL ||
2320 mode_ == DELAYED_REQUEST_HANDLER_OPEN ||
2321 mode_ == DELAYED_REQUEST_HANDLER_READ ||
2322 mode_ == DELAYED_REQUEST_HANDLER_ALL;
2323 }
2324
IsIncompleteRequestHandler() const2325 bool IsIncompleteRequestHandler() const {
2326 return mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN ||
2327 mode_ == INCOMPLETE_REQUEST_HANDLER_READ;
2328 }
2329
IsIncomplete() const2330 bool IsIncomplete() const {
2331 return mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD ||
2332 IsIncompleteRequestHandler();
2333 }
2334
IsRedirect() const2335 bool IsRedirect() const {
2336 return mode_ == REDIRECT_BEFORE_RESOURCE_LOAD ||
2337 mode_ == REDIRECT_REQUEST_HANDLER ||
2338 mode_ == REDIRECT_RESOURCE_REDIRECT ||
2339 mode_ == REDIRECT_RESOURCE_RESPONSE;
2340 }
2341
SetCustomHeader(CefRefPtr<CefRequest> request)2342 static void SetCustomHeader(CefRefPtr<CefRequest> request) {
2343 EXPECT_FALSE(request->IsReadOnly());
2344 request->SetHeaderByName("X-Custom-Header", "value", false);
2345 }
2346
GetCustomHeader(CefRefPtr<CefRequest> request)2347 static std::string GetCustomHeader(CefRefPtr<CefRequest> request) {
2348 return request->GetHeaderByName("X-Custom-Header");
2349 }
2350
2351 // Resource-related callbacks.
2352 enum Callback {
2353 kGetResourceRequestHandler,
2354 kGetCookieAccessFilter,
2355 kOnBeforeResourceLoad,
2356 kGetResourceHandler,
2357 kOnResourceRedirect,
2358 kOnResourceResponse,
2359 kGetResourceResponseFilter,
2360 kOnResourceLoadComplete,
2361 kOnProtocolExecution,
2362 kOnQuery,
2363 };
2364
ShouldHaveResponse(Callback callback) const2365 bool ShouldHaveResponse(Callback callback) const {
2366 return callback >= kOnResourceRedirect &&
2367 callback <= kOnResourceLoadComplete;
2368 }
2369
ShouldHaveWritableRequest(Callback callback) const2370 bool ShouldHaveWritableRequest(Callback callback) const {
2371 return callback == kOnBeforeResourceLoad || callback == kOnResourceResponse;
2372 }
2373
VerifyFrame(Callback callback,CefRefPtr<CefFrame> frame) const2374 void VerifyFrame(Callback callback, CefRefPtr<CefFrame> frame) const {
2375 EXPECT_TRUE(frame);
2376
2377 if (subframe_)
2378 EXPECT_FALSE(frame->IsMain()) << callback;
2379 else
2380 EXPECT_TRUE(frame->IsMain()) << callback;
2381
2382 EXPECT_EQ(frame_id_, frame->GetIdentifier()) << callback;
2383 }
2384
VerifyState(Callback callback,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response) const2385 void VerifyState(Callback callback,
2386 CefRefPtr<CefRequest> request,
2387 CefRefPtr<CefResponse> response) const {
2388 EXPECT_TRUE(request) << callback;
2389
2390 if (ShouldHaveResponse(callback)) {
2391 EXPECT_TRUE(response) << callback;
2392 EXPECT_TRUE(response->IsReadOnly()) << callback;
2393 } else {
2394 EXPECT_FALSE(response) << callback;
2395 }
2396
2397 if (ShouldHaveWritableRequest(callback)) {
2398 EXPECT_FALSE(request->IsReadOnly()) << callback;
2399 } else {
2400 EXPECT_TRUE(request->IsReadOnly()) << callback;
2401 }
2402
2403 // All resource-related callbacks share the same request ID.
2404 EXPECT_EQ(request_id_, request->GetIdentifier()) << callback;
2405
2406 if (IsLoad() || IsIncomplete()) {
2407 EXPECT_STREQ("GET", request->GetMethod().ToString().c_str()) << callback;
2408 EXPECT_STREQ(GetURL(RESULT_JS), request->GetURL().ToString().c_str())
2409 << callback;
2410
2411 // Expect the header for all callbacks following the callback that
2412 // initially sets it.
2413 const std::string& custom_header = GetCustomHeader(request);
2414 if ((mode_ == RESTART_RESOURCE_RESPONSE &&
2415 on_resource_response_ct_ > 0) ||
2416 (mode_ == MODIFY_BEFORE_RESOURCE_LOAD &&
2417 on_before_resource_load_ct_ > 0)) {
2418 EXPECT_STREQ("value", custom_header.c_str()) << callback;
2419 } else {
2420 EXPECT_STREQ("", custom_header.c_str()) << callback;
2421 }
2422
2423 if (response)
2424 VerifyOKResponse(callback, response);
2425 } else if (IsRedirect()) {
2426 EXPECT_STREQ("GET", request->GetMethod().ToString().c_str()) << callback;
2427 // Subresource loads don't get OnBeforeBrowse calls, so this check is a
2428 // bit less exact then with main resource loads.
2429 if (on_resource_redirect_ct_ == 0) {
2430 // Before the redirect.
2431 EXPECT_STREQ(GetStartupURL(), request->GetURL().ToString().c_str())
2432 << callback;
2433 } else {
2434 // After the redirect.
2435 EXPECT_STREQ(GetURL(RESULT_JS), request->GetURL().ToString().c_str())
2436 << callback;
2437 }
2438
2439 if (response) {
2440 if (callback == kOnResourceRedirect) {
2441 // Before the redirect.
2442 VerifyRedirectResponse(callback, response);
2443 } else {
2444 // After the redirect.
2445 VerifyOKResponse(callback, response);
2446 }
2447 }
2448 } else {
2449 NOTREACHED() << callback;
2450 }
2451 }
2452
VerifyOKResponse(Callback callback,CefRefPtr<CefResponse> response) const2453 void VerifyOKResponse(Callback callback,
2454 CefRefPtr<CefResponse> response) const {
2455 // True for the first response in cases where we're redirecting/restarting
2456 // from inside OnResourceResponse (e.g. the first response always succeeds).
2457 const bool override_unhandled = unhandled_ &&
2458 (mode_ == REDIRECT_RESOURCE_RESPONSE ||
2459 mode_ == RESTART_RESOURCE_RESPONSE) &&
2460 get_resource_handler_ct_ == 1;
2461
2462 // True for tests where the request will be incomplete and never receive a
2463 // response.
2464 const bool incomplete_unhandled =
2465 (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD ||
2466 mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN);
2467
2468 if ((unhandled_ && !override_unhandled) || incomplete_unhandled) {
2469 if (incomplete_unhandled) {
2470 EXPECT_EQ(ERR_ABORTED, response->GetError()) << callback;
2471 } else {
2472 EXPECT_EQ(ERR_UNKNOWN_URL_SCHEME, response->GetError()) << callback;
2473 }
2474 EXPECT_EQ(0, response->GetStatus()) << callback;
2475 EXPECT_STREQ("", response->GetStatusText().ToString().c_str())
2476 << callback;
2477 EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
2478 EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback;
2479 EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
2480 } else {
2481 if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ &&
2482 callback == kOnResourceLoadComplete) {
2483 // We got a response, but we also got aborted.
2484 EXPECT_EQ(ERR_ABORTED, response->GetError()) << callback;
2485 } else {
2486 EXPECT_EQ(ERR_NONE, response->GetError()) << callback;
2487 }
2488 EXPECT_EQ(200, response->GetStatus()) << callback;
2489 EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str())
2490 << callback;
2491 EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
2492 EXPECT_STREQ("text/javascript",
2493 response->GetMimeType().ToString().c_str())
2494 << callback;
2495 EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
2496 }
2497 }
2498
VerifyRedirectResponse(Callback callback,CefRefPtr<CefResponse> response) const2499 void VerifyRedirectResponse(Callback callback,
2500 CefRefPtr<CefResponse> response) const {
2501 EXPECT_EQ(ERR_NONE, response->GetError()) << callback;
2502 EXPECT_EQ(307, response->GetStatus()) << callback;
2503 const std::string& status_text = response->GetStatusText();
2504 EXPECT_TRUE(status_text == "Internal Redirect" ||
2505 status_text == "Temporary Redirect")
2506 << status_text << callback;
2507 EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
2508 EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback;
2509 EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
2510 }
2511
CloseBrowserAsync()2512 void CloseBrowserAsync() {
2513 EXPECT_TRUE(IsIncomplete());
2514 SetSignalCompletionWhenAllBrowsersClose(false);
2515 CefPostDelayedTask(
2516 TID_UI, base::BindOnce(&TestHandler::CloseBrowser, GetBrowser(), false),
2517 100);
2518 }
2519
MaybeDestroyTest(bool from_handler)2520 void MaybeDestroyTest(bool from_handler) {
2521 if (!CefCurrentlyOn(TID_UI)) {
2522 CefPostTask(TID_UI,
2523 base::BindOnce(&SubresourceResponseTest::MaybeDestroyTest,
2524 this, from_handler));
2525 return;
2526 }
2527
2528 if (from_handler) {
2529 resource_handler_destroyed_ct_++;
2530 }
2531
2532 bool destroy_test = false;
2533 if (IsIncomplete()) {
2534 // Destroy the test if we got OnResourceLoadComplete and either the
2535 // resource handler will never complete or it was destroyed.
2536 destroy_test =
2537 on_resource_load_complete_ct_ > 0 &&
2538 (!IsIncompleteRequestHandler() ||
2539 resource_handler_destroyed_ct_ == resource_handler_created_ct_);
2540 } else {
2541 // Destroy the test if we got the expected number of OnLoadEnd and
2542 // OnQuery, and the expected number of resource handlers were destroyed.
2543 destroy_test =
2544 on_load_end_ct_ > (subframe_ ? 1 : 0) &&
2545 (on_query_ct_ > 0 || unhandled_) &&
2546 resource_handler_destroyed_ct_ == resource_handler_created_ct_;
2547 }
2548
2549 if (destroy_test) {
2550 DestroyTest();
2551 }
2552 }
2553
2554 const TestMode mode_;
2555 const bool custom_scheme_;
2556 const bool unhandled_;
2557 const bool subframe_;
2558
2559 int browser_id_ = 0;
2560 int64 frame_id_ = 0;
2561 uint64 request_id_ = 0U;
2562
2563 int resource_handler_created_ct_ = 0;
2564
2565 int on_before_browse_ct_ = 0;
2566 int on_load_end_ct_ = 0;
2567 int on_query_ct_ = 0;
2568
2569 int get_resource_request_handler_ct_ = 0;
2570 int get_cookie_access_filter_ct_ = 0;
2571 int on_before_resource_load_ct_ = 0;
2572 int get_resource_handler_ct_ = 0;
2573 int on_resource_redirect_ct_ = 0;
2574 int on_resource_response_ct_ = 0;
2575 int get_resource_response_filter_ct_ = 0;
2576 int on_resource_load_complete_ct_ = 0;
2577 int on_protocol_execution_ct_ = 0;
2578 int resource_handler_destroyed_ct_ = 0;
2579
2580 // Used with INCOMPLETE_BEFORE_RESOURCE_LOAD.
2581 CefRefPtr<CefCallback> incomplete_callback_;
2582
2583 DISALLOW_COPY_AND_ASSIGN(SubresourceResponseTest);
2584 IMPLEMENT_REFCOUNTING(SubresourceResponseTest);
2585 };
2586
2587 } // namespace
2588
2589 #define SUBRESOURCE_TEST(name, test_mode, custom, unhandled, subframe) \
2590 TEST(ResourceRequestHandlerTest, Subresource##name) { \
2591 CefRefPtr<SubresourceResponseTest> handler = new SubresourceResponseTest( \
2592 SubresourceResponseTest::test_mode, custom, unhandled, subframe); \
2593 handler->ExecuteTest(); \
2594 ReleaseAndWaitForDestructor(handler); \
2595 }
2596
2597 #define SUBRESOURCE_TEST_ALL_MODES(name, custom, unhandled, subframe) \
2598 SUBRESOURCE_TEST(name##Load, LOAD, custom, unhandled, subframe) \
2599 SUBRESOURCE_TEST(name##ModifyBeforeResourceLoad, \
2600 MODIFY_BEFORE_RESOURCE_LOAD, custom, unhandled, subframe) \
2601 SUBRESOURCE_TEST(name##RedirectBeforeResourceLoad, \
2602 REDIRECT_BEFORE_RESOURCE_LOAD, custom, unhandled, subframe) \
2603 SUBRESOURCE_TEST(name##RedirectRequestHandler, REDIRECT_REQUEST_HANDLER, \
2604 custom, unhandled, subframe) \
2605 SUBRESOURCE_TEST(name##RedirectResourceRedirect, REDIRECT_RESOURCE_REDIRECT, \
2606 custom, unhandled, subframe) \
2607 SUBRESOURCE_TEST(name##RedirectResourceResponse, REDIRECT_RESOURCE_RESPONSE, \
2608 custom, unhandled, subframe) \
2609 SUBRESOURCE_TEST(name##RestartResourceResponse, RESTART_RESOURCE_RESPONSE, \
2610 custom, unhandled, subframe)
2611
2612 // Tests only supported in handled mode.
2613 #define SUBRESOURCE_TEST_HANDLED_MODES(name, custom, subframe) \
2614 SUBRESOURCE_TEST(name##ImmediateRequestHandlerOpen, \
2615 IMMEDIATE_REQUEST_HANDLER_OPEN, custom, false, subframe) \
2616 SUBRESOURCE_TEST(name##ImmediateRequestHandlerRead, \
2617 IMMEDIATE_REQUEST_HANDLER_READ, custom, false, subframe) \
2618 SUBRESOURCE_TEST(name##ImmediateRequestHandlerAll, \
2619 IMMEDIATE_REQUEST_HANDLER_ALL, custom, false, subframe) \
2620 SUBRESOURCE_TEST(name##DelayedRequestHandlerOpen, \
2621 DELAYED_REQUEST_HANDLER_OPEN, custom, false, subframe) \
2622 SUBRESOURCE_TEST(name##DelayedRequestHandlerRead, \
2623 DELAYED_REQUEST_HANDLER_READ, custom, false, subframe) \
2624 SUBRESOURCE_TEST(name##DelayedRequestHandlerAll, \
2625 DELAYED_REQUEST_HANDLER_ALL, custom, false, subframe) \
2626 SUBRESOURCE_TEST(name##IncompleteBeforeResourceLoad, \
2627 INCOMPLETE_BEFORE_RESOURCE_LOAD, custom, false, subframe) \
2628 SUBRESOURCE_TEST(name##IncompleteRequestHandlerOpen, \
2629 INCOMPLETE_REQUEST_HANDLER_OPEN, custom, false, subframe) \
2630 SUBRESOURCE_TEST(name##IncompleteRequestHandlerRead, \
2631 INCOMPLETE_REQUEST_HANDLER_READ, custom, false, subframe)
2632
2633 SUBRESOURCE_TEST_ALL_MODES(StandardHandledMainFrame, false, false, false)
2634 SUBRESOURCE_TEST_ALL_MODES(StandardUnhandledMainFrame, false, true, false)
2635 SUBRESOURCE_TEST_ALL_MODES(CustomHandledMainFrame, true, false, false)
2636 SUBRESOURCE_TEST_ALL_MODES(CustomUnhandledMainFrame, true, true, false)
2637
2638 SUBRESOURCE_TEST_ALL_MODES(StandardHandledSubFrame, false, false, true)
2639 SUBRESOURCE_TEST_ALL_MODES(StandardUnhandledSubFrame, false, true, true)
2640 SUBRESOURCE_TEST_ALL_MODES(CustomHandledSubFrame, true, false, true)
2641 SUBRESOURCE_TEST_ALL_MODES(CustomUnhandledSubFrame, true, true, true)
2642
2643 SUBRESOURCE_TEST_HANDLED_MODES(StandardHandledMainFrame, false, false)
2644 SUBRESOURCE_TEST_HANDLED_MODES(CustomHandledMainFrame, true, false)
2645
2646 SUBRESOURCE_TEST_HANDLED_MODES(StandardHandledSubFrame, false, true)
2647 SUBRESOURCE_TEST_HANDLED_MODES(CustomHandledSubFrame, true, true)
2648
2649 namespace {
2650
2651 const char kResourceTestHtml[] = "http://test.com/resource.html";
2652
2653 class RedirectResponseTest : public TestHandler {
2654 public:
2655 enum TestMode {
2656 URL,
2657 HEADER,
2658 POST,
2659 };
2660
RedirectResponseTest(TestMode mode,bool via_request_context_handler)2661 RedirectResponseTest(TestMode mode, bool via_request_context_handler)
2662 : via_request_context_handler_(via_request_context_handler) {
2663 if (mode == URL)
2664 resource_test_.reset(new UrlResourceTest);
2665 else if (mode == HEADER)
2666 resource_test_.reset(new HeaderResourceTest);
2667 else
2668 resource_test_.reset(new PostResourceTest);
2669 }
2670
RunTest()2671 void RunTest() override {
2672 AddResource(kResourceTestHtml, GetHtml(), "text/html");
2673
2674 resource_request_handler_ = new ResourceRequestHandler(this);
2675
2676 CefRefPtr<CefRequestContext> request_context =
2677 CefRequestContext::GetGlobalContext();
2678 if (via_request_context_handler_) {
2679 CefRefPtr<CefRequestContextHandler> request_context_handler =
2680 new RequestContextHandler(resource_request_handler_.get());
2681 CefRequestContextSettings settings;
2682 request_context = CefRequestContext::CreateContext(
2683 request_context, request_context_handler);
2684 }
2685
2686 CreateBrowser(kResourceTestHtml, request_context);
2687 SetTestTimeout();
2688 }
2689
GetResourceRequestHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool is_navigation,bool is_download,const CefString & request_initiator,bool & disable_default_handling)2690 CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
2691 CefRefPtr<CefBrowser> browser,
2692 CefRefPtr<CefFrame> frame,
2693 CefRefPtr<CefRequest> request,
2694 bool is_navigation,
2695 bool is_download,
2696 const CefString& request_initiator,
2697 bool& disable_default_handling) override {
2698 if (via_request_context_handler_) {
2699 // Use the handler returned by RequestContextHandler.
2700 return nullptr;
2701 }
2702 return resource_request_handler_.get();
2703 }
2704
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)2705 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
2706 CefRefPtr<CefFrame> frame,
2707 CefRefPtr<CefRequest> request,
2708 bool user_gesture,
2709 bool is_redirect) override {
2710 EXPECT_UI_THREAD();
2711 EXPECT_EQ(0, browser_id_);
2712 browser_id_ = browser->GetIdentifier();
2713 EXPECT_GT(browser_id_, 0);
2714
2715 // This method is only called for the main resource.
2716 EXPECT_STREQ(kResourceTestHtml, request->GetURL().ToString().c_str());
2717
2718 // Browser-side navigation no longer exposes the actual request information.
2719 EXPECT_EQ(0U, request->GetIdentifier());
2720
2721 return false;
2722 }
2723
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)2724 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
2725 CefRefPtr<CefFrame> frame,
2726 int httpStatusCode) override {
2727 EXPECT_UI_THREAD();
2728 EXPECT_EQ(browser_id_, browser->GetIdentifier());
2729
2730 TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
2731 DestroyTest();
2732 }
2733
DestroyTest()2734 void DestroyTest() override {
2735 resource_test_->CheckExpected();
2736 resource_test_.reset(nullptr);
2737
2738 TestHandler::DestroyTest();
2739 }
2740
2741 private:
GetHtml() const2742 std::string GetHtml() const {
2743 std::stringstream html;
2744 html << "<html><head>";
2745
2746 const std::string& url = resource_test_->start_url();
2747 html << "<script type=\"text/javascript\" src=\"" << url << "\"></script>";
2748
2749 html << "</head><body><p>Main</p></body></html>";
2750 return html.str();
2751 }
2752
2753 class ResourceTest {
2754 public:
ResourceTest(const std::string & start_url,size_t expected_resource_response_ct=2U,size_t expected_before_resource_load_ct=1U,size_t expected_resource_redirect_ct=0U,size_t expected_resource_load_complete_ct=1U)2755 ResourceTest(const std::string& start_url,
2756 size_t expected_resource_response_ct = 2U,
2757 size_t expected_before_resource_load_ct = 1U,
2758 size_t expected_resource_redirect_ct = 0U,
2759 size_t expected_resource_load_complete_ct = 1U)
2760 : start_url_(start_url),
2761 expected_resource_response_ct_(expected_resource_response_ct),
2762 expected_before_resource_load_ct_(expected_before_resource_load_ct),
2763 expected_resource_redirect_ct_(expected_resource_redirect_ct),
2764 expected_resource_load_complete_ct_(
2765 expected_resource_load_complete_ct) {}
~ResourceTest()2766 virtual ~ResourceTest() {}
2767
start_url() const2768 const std::string& start_url() const { return start_url_; }
2769
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)2770 virtual bool OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
2771 CefRefPtr<CefFrame> frame,
2772 CefRefPtr<CefRequest> request) {
2773 before_resource_load_ct_++;
2774 return false;
2775 }
2776
GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)2777 virtual CefRefPtr<CefResourceHandler> GetResourceHandler(
2778 CefRefPtr<CefBrowser> browser,
2779 CefRefPtr<CefFrame> frame,
2780 CefRefPtr<CefRequest> request) {
2781 get_resource_handler_ct_++;
2782
2783 const std::string& js_content = "<!-- -->";
2784
2785 CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
2786 const_cast<char*>(js_content.c_str()), js_content.size());
2787
2788 return new CefStreamResourceHandler(200, "OK", "text/javascript",
2789 CefResponse::HeaderMap(), stream);
2790 }
2791
OnResourceRedirect(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefString & new_url)2792 virtual void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
2793 CefRefPtr<CefFrame> frame,
2794 CefRefPtr<CefRequest> request,
2795 CefString& new_url) {
2796 resource_redirect_ct_++;
2797 }
2798
OnResourceResponse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)2799 bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
2800 CefRefPtr<CefFrame> frame,
2801 CefRefPtr<CefRequest> request,
2802 CefRefPtr<CefResponse> response) {
2803 EXPECT_TRUE(CheckUrl(request->GetURL()));
2804
2805 // Verify the response returned by GetResourceHandler.
2806 EXPECT_EQ(200, response->GetStatus());
2807 EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str());
2808 EXPECT_STREQ("text/javascript",
2809 response->GetMimeType().ToString().c_str());
2810
2811 if (resource_response_ct_++ == 0U) {
2812 // Always redirect at least one time.
2813 OnResourceReceived(browser, frame, request, response);
2814 return true;
2815 }
2816
2817 OnRetryReceived(browser, frame, request, response);
2818 return (resource_response_ct_ < expected_resource_response_ct_);
2819 }
2820
GetResourceResponseFilter(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)2821 CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
2822 CefRefPtr<CefBrowser> browser,
2823 CefRefPtr<CefFrame> frame,
2824 CefRefPtr<CefRequest> request,
2825 CefRefPtr<CefResponse> response) {
2826 get_resource_response_filter_ct_++;
2827 return nullptr;
2828 }
2829
OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response,URLRequestStatus status,int64 received_content_length)2830 void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
2831 CefRefPtr<CefFrame> frame,
2832 CefRefPtr<CefRequest> request,
2833 CefRefPtr<CefResponse> response,
2834 URLRequestStatus status,
2835 int64 received_content_length) {
2836 EXPECT_TRUE(CheckUrl(request->GetURL()));
2837
2838 // Verify the response returned by GetResourceHandler.
2839 EXPECT_EQ(200, response->GetStatus());
2840 EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str());
2841 EXPECT_STREQ("text/javascript",
2842 response->GetMimeType().ToString().c_str());
2843
2844 resource_load_complete_ct_++;
2845 }
2846
CheckUrl(const std::string & url) const2847 virtual bool CheckUrl(const std::string& url) const {
2848 return (url == start_url_);
2849 }
2850
CheckExpected()2851 virtual void CheckExpected() {
2852 EXPECT_TRUE(got_resource_);
2853 EXPECT_TRUE(got_resource_retry_);
2854
2855 EXPECT_EQ(expected_resource_response_ct_, resource_response_ct_);
2856 EXPECT_EQ(expected_resource_response_ct_, get_resource_handler_ct_);
2857 EXPECT_EQ(expected_resource_load_complete_ct_,
2858 get_resource_response_filter_ct_);
2859 EXPECT_EQ(expected_before_resource_load_ct_, before_resource_load_ct_);
2860 EXPECT_EQ(expected_resource_redirect_ct_, resource_redirect_ct_);
2861 EXPECT_EQ(expected_resource_load_complete_ct_,
2862 resource_load_complete_ct_);
2863 }
2864
2865 protected:
OnResourceReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)2866 virtual void OnResourceReceived(CefRefPtr<CefBrowser> browser,
2867 CefRefPtr<CefFrame> frame,
2868 CefRefPtr<CefRequest> request,
2869 CefRefPtr<CefResponse> response) {
2870 got_resource_.yes();
2871 }
2872
OnRetryReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)2873 virtual void OnRetryReceived(CefRefPtr<CefBrowser> browser,
2874 CefRefPtr<CefFrame> frame,
2875 CefRefPtr<CefRequest> request,
2876 CefRefPtr<CefResponse> response) {
2877 got_resource_retry_.yes();
2878 }
2879
2880 private:
2881 std::string start_url_;
2882
2883 size_t resource_response_ct_ = 0U;
2884 size_t expected_resource_response_ct_;
2885 size_t before_resource_load_ct_ = 0U;
2886 size_t expected_before_resource_load_ct_;
2887 size_t get_resource_handler_ct_ = 0U;
2888 size_t resource_redirect_ct_ = 0U;
2889 size_t expected_resource_redirect_ct_;
2890 size_t get_resource_response_filter_ct_ = 0U;
2891 size_t resource_load_complete_ct_ = 0U;
2892 size_t expected_resource_load_complete_ct_;
2893
2894 TrackCallback got_resource_;
2895 TrackCallback got_resource_retry_;
2896 };
2897
2898 class UrlResourceTest : public ResourceTest {
2899 public:
2900 // With NetworkService we don't get an additional (unnecessary) redirect
2901 // callback.
UrlResourceTest()2902 UrlResourceTest()
2903 : ResourceTest("http://test.com/start_url.js", 2U, 2U, 1U) {
2904 redirect_url_ = "http://test.com/redirect_url.js";
2905 }
2906
CheckUrl(const std::string & url) const2907 bool CheckUrl(const std::string& url) const override {
2908 if (url == redirect_url_)
2909 return true;
2910
2911 return ResourceTest::CheckUrl(url);
2912 }
2913
OnResourceRedirect(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefString & new_url)2914 void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
2915 CefRefPtr<CefFrame> frame,
2916 CefRefPtr<CefRequest> request,
2917 CefString& new_url) override {
2918 ResourceTest::OnResourceRedirect(browser, frame, request, new_url);
2919 const std::string& old_url = request->GetURL();
2920 EXPECT_STREQ(start_url().c_str(), old_url.c_str());
2921 EXPECT_STREQ(redirect_url_.c_str(), new_url.ToString().c_str());
2922 }
2923
2924 private:
OnResourceReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)2925 void OnResourceReceived(CefRefPtr<CefBrowser> browser,
2926 CefRefPtr<CefFrame> frame,
2927 CefRefPtr<CefRequest> request,
2928 CefRefPtr<CefResponse> response) override {
2929 ResourceTest::OnResourceReceived(browser, frame, request, response);
2930 request->SetURL(redirect_url_);
2931 }
2932
OnRetryReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)2933 void OnRetryReceived(CefRefPtr<CefBrowser> browser,
2934 CefRefPtr<CefFrame> frame,
2935 CefRefPtr<CefRequest> request,
2936 CefRefPtr<CefResponse> response) override {
2937 ResourceTest::OnRetryReceived(browser, frame, request, response);
2938 const std::string& new_url = request->GetURL();
2939 EXPECT_STREQ(redirect_url_.c_str(), new_url.c_str());
2940 }
2941
2942 std::string redirect_url_;
2943 };
2944
2945 class HeaderResourceTest : public ResourceTest {
2946 public:
2947 // With NetworkService we restart the request, so we get another call to
2948 // OnBeforeResourceLoad.
HeaderResourceTest()2949 HeaderResourceTest()
2950 : ResourceTest("http://test.com/start_header.js", 2U, 2U) {
2951 expected_headers_.insert(std::make_pair("Test-Key1", "Value1"));
2952 expected_headers_.insert(std::make_pair("Test-Key2", "Value2"));
2953 }
2954
2955 private:
OnResourceReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)2956 void OnResourceReceived(CefRefPtr<CefBrowser> browser,
2957 CefRefPtr<CefFrame> frame,
2958 CefRefPtr<CefRequest> request,
2959 CefRefPtr<CefResponse> response) override {
2960 ResourceTest::OnResourceReceived(browser, frame, request, response);
2961 request->SetHeaderMap(expected_headers_);
2962 }
2963
OnRetryReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)2964 void OnRetryReceived(CefRefPtr<CefBrowser> browser,
2965 CefRefPtr<CefFrame> frame,
2966 CefRefPtr<CefRequest> request,
2967 CefRefPtr<CefResponse> response) override {
2968 ResourceTest::OnRetryReceived(browser, frame, request, response);
2969 CefRequest::HeaderMap actual_headers;
2970 request->GetHeaderMap(actual_headers);
2971 TestMapEqual(expected_headers_, actual_headers, true);
2972 }
2973
2974 CefRequest::HeaderMap expected_headers_;
2975 };
2976
2977 class PostResourceTest : public ResourceTest {
2978 public:
2979 // With NetworkService we restart the request, so we get another call to
2980 // OnBeforeResourceLoad.
PostResourceTest()2981 PostResourceTest() : ResourceTest("http://test.com/start_post.js", 2U, 2U) {
2982 CefRefPtr<CefPostDataElement> elem = CefPostDataElement::Create();
2983 const std::string data("Test Post Data");
2984 elem->SetToBytes(data.size(), data.c_str());
2985
2986 expected_post_ = CefPostData::Create();
2987 expected_post_->AddElement(elem);
2988 }
2989
2990 private:
OnResourceReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)2991 void OnResourceReceived(CefRefPtr<CefBrowser> browser,
2992 CefRefPtr<CefFrame> frame,
2993 CefRefPtr<CefRequest> request,
2994 CefRefPtr<CefResponse> response) override {
2995 ResourceTest::OnResourceReceived(browser, frame, request, response);
2996 request->SetPostData(expected_post_);
2997 }
2998
OnRetryReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)2999 void OnRetryReceived(CefRefPtr<CefBrowser> browser,
3000 CefRefPtr<CefFrame> frame,
3001 CefRefPtr<CefRequest> request,
3002 CefRefPtr<CefResponse> response) override {
3003 ResourceTest::OnRetryReceived(browser, frame, request, response);
3004 CefRefPtr<CefPostData> actual_post = request->GetPostData();
3005 TestPostDataEqual(expected_post_, actual_post);
3006 }
3007
3008 CefRefPtr<CefPostData> expected_post_;
3009 };
3010
3011 class RequestContextHandler : public CefRequestContextHandler {
3012 public:
RequestContextHandler(CefRefPtr<CefResourceRequestHandler> resource_request_handler)3013 explicit RequestContextHandler(
3014 CefRefPtr<CefResourceRequestHandler> resource_request_handler)
3015 : resource_request_handler_(resource_request_handler) {}
3016
GetResourceRequestHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool is_navigation,bool is_download,const CefString & request_initiator,bool & disable_default_handling)3017 CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
3018 CefRefPtr<CefBrowser> browser,
3019 CefRefPtr<CefFrame> frame,
3020 CefRefPtr<CefRequest> request,
3021 bool is_navigation,
3022 bool is_download,
3023 const CefString& request_initiator,
3024 bool& disable_default_handling) override {
3025 return resource_request_handler_;
3026 }
3027
3028 private:
3029 CefRefPtr<CefResourceRequestHandler> resource_request_handler_;
3030
3031 IMPLEMENT_REFCOUNTING(RequestContextHandler);
3032 DISALLOW_COPY_AND_ASSIGN(RequestContextHandler);
3033 };
3034
3035 class ResourceRequestHandler : public CefResourceRequestHandler {
3036 public:
ResourceRequestHandler(RedirectResponseTest * test)3037 explicit ResourceRequestHandler(RedirectResponseTest* test) : test_(test) {}
3038
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)3039 cef_return_value_t OnBeforeResourceLoad(
3040 CefRefPtr<CefBrowser> browser,
3041 CefRefPtr<CefFrame> frame,
3042 CefRefPtr<CefRequest> request,
3043 CefRefPtr<CefCallback> callback) override {
3044 EXPECT_IO_THREAD();
3045
3046 if (IsChromeRuntimeEnabled() &&
3047 request->GetResourceType() == RT_FAVICON) {
3048 // Ignore favicon requests.
3049 return RV_CANCEL;
3050 }
3051
3052 EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
3053
3054 if (request->GetURL() == kResourceTestHtml) {
3055 // All loads of the main resource should keep the same request id.
3056 EXPECT_EQ(0U, main_request_id_);
3057 main_request_id_ = request->GetIdentifier();
3058 EXPECT_GT(main_request_id_, 0U);
3059 return RV_CONTINUE;
3060 }
3061
3062 // All redirects of the sub-resource should keep the same request id.
3063 if (sub_request_id_ == 0U) {
3064 sub_request_id_ = request->GetIdentifier();
3065 EXPECT_GT(sub_request_id_, 0U);
3066 } else {
3067 EXPECT_EQ(sub_request_id_, request->GetIdentifier());
3068 }
3069
3070 return test_->resource_test_->OnBeforeResourceLoad(browser, frame,
3071 request)
3072 ? RV_CANCEL
3073 : RV_CONTINUE;
3074 }
3075
GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)3076 CefRefPtr<CefResourceHandler> GetResourceHandler(
3077 CefRefPtr<CefBrowser> browser,
3078 CefRefPtr<CefFrame> frame,
3079 CefRefPtr<CefRequest> request) override {
3080 EXPECT_IO_THREAD();
3081 EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
3082
3083 if (request->GetURL() == kResourceTestHtml) {
3084 EXPECT_EQ(main_request_id_, request->GetIdentifier());
3085 return test_->GetResourceHandler(browser, frame, request);
3086 }
3087
3088 EXPECT_EQ(sub_request_id_, request->GetIdentifier());
3089 return test_->resource_test_->GetResourceHandler(browser, frame, request);
3090 }
3091
OnResourceRedirect(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response,CefString & new_url)3092 void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
3093 CefRefPtr<CefFrame> frame,
3094 CefRefPtr<CefRequest> request,
3095 CefRefPtr<CefResponse> response,
3096 CefString& new_url) override {
3097 EXPECT_IO_THREAD();
3098 EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
3099 EXPECT_EQ(sub_request_id_, request->GetIdentifier());
3100
3101 test_->resource_test_->OnResourceRedirect(browser, frame, request,
3102 new_url);
3103 }
3104
OnResourceResponse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)3105 bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
3106 CefRefPtr<CefFrame> frame,
3107 CefRefPtr<CefRequest> request,
3108 CefRefPtr<CefResponse> response) override {
3109 EXPECT_IO_THREAD();
3110 EXPECT_TRUE(browser.get());
3111 EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
3112
3113 EXPECT_TRUE(frame.get());
3114 EXPECT_TRUE(frame->IsMain());
3115
3116 if (request->GetURL() == kResourceTestHtml) {
3117 EXPECT_EQ(main_request_id_, request->GetIdentifier());
3118 return false;
3119 }
3120
3121 EXPECT_EQ(sub_request_id_, request->GetIdentifier());
3122 return test_->resource_test_->OnResourceResponse(browser, frame, request,
3123 response);
3124 }
3125
GetResourceResponseFilter(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)3126 CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
3127 CefRefPtr<CefBrowser> browser,
3128 CefRefPtr<CefFrame> frame,
3129 CefRefPtr<CefRequest> request,
3130 CefRefPtr<CefResponse> response) override {
3131 EXPECT_IO_THREAD();
3132 EXPECT_TRUE(browser.get());
3133 EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
3134
3135 EXPECT_TRUE(frame.get());
3136 EXPECT_TRUE(frame->IsMain());
3137
3138 if (request->GetURL() == kResourceTestHtml) {
3139 EXPECT_EQ(main_request_id_, request->GetIdentifier());
3140 return nullptr;
3141 }
3142
3143 return test_->resource_test_->GetResourceResponseFilter(
3144 browser, frame, request, response);
3145 }
3146
OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response,URLRequestStatus status,int64 received_content_length)3147 void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
3148 CefRefPtr<CefFrame> frame,
3149 CefRefPtr<CefRequest> request,
3150 CefRefPtr<CefResponse> response,
3151 URLRequestStatus status,
3152 int64 received_content_length) override {
3153 EXPECT_IO_THREAD();
3154
3155 if (IsChromeRuntimeEnabled() &&
3156 request->GetResourceType() == RT_FAVICON) {
3157 // Ignore favicon requests.
3158 return;
3159 }
3160
3161 EXPECT_TRUE(browser.get());
3162 EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
3163
3164 EXPECT_TRUE(frame.get());
3165 EXPECT_TRUE(frame->IsMain());
3166
3167 if (request->GetURL() == kResourceTestHtml) {
3168 EXPECT_EQ(main_request_id_, request->GetIdentifier());
3169 return;
3170 }
3171
3172 EXPECT_EQ(sub_request_id_, request->GetIdentifier());
3173 test_->resource_test_->OnResourceLoadComplete(
3174 browser, frame, request, response, status, received_content_length);
3175 }
3176
3177 private:
3178 RedirectResponseTest* const test_;
3179
3180 uint64 main_request_id_ = 0U;
3181 uint64 sub_request_id_ = 0U;
3182
3183 IMPLEMENT_REFCOUNTING(ResourceRequestHandler);
3184 DISALLOW_COPY_AND_ASSIGN(ResourceRequestHandler);
3185 };
3186
3187 const bool via_request_context_handler_;
3188
3189 int browser_id_ = 0;
3190 std::unique_ptr<ResourceTest> resource_test_;
3191 CefRefPtr<ResourceRequestHandler> resource_request_handler_;
3192
3193 IMPLEMENT_REFCOUNTING(RedirectResponseTest);
3194 };
3195
3196 } // namespace
3197
3198 // Verify redirect with client handler.
TEST(ResourceRequestHandlerTest,RedirectURLViaClient)3199 TEST(ResourceRequestHandlerTest, RedirectURLViaClient) {
3200 CefRefPtr<RedirectResponseTest> handler =
3201 new RedirectResponseTest(RedirectResponseTest::URL, false);
3202 handler->ExecuteTest();
3203 ReleaseAndWaitForDestructor(handler);
3204 }
3205
3206 // Verify redirect + modified headers with client handler.
TEST(ResourceRequestHandlerTest,RedirectHeaderViaClient)3207 TEST(ResourceRequestHandlerTest, RedirectHeaderViaClient) {
3208 CefRefPtr<RedirectResponseTest> handler =
3209 new RedirectResponseTest(RedirectResponseTest::HEADER, false);
3210 handler->ExecuteTest();
3211 ReleaseAndWaitForDestructor(handler);
3212 }
3213
3214 // Verify redirect + modified post data with client handler.
TEST(ResourceRequestHandlerTest,RedirectPostViaClient)3215 TEST(ResourceRequestHandlerTest, RedirectPostViaClient) {
3216 CefRefPtr<RedirectResponseTest> handler =
3217 new RedirectResponseTest(RedirectResponseTest::POST, false);
3218 handler->ExecuteTest();
3219 ReleaseAndWaitForDestructor(handler);
3220 }
3221
3222 // Verify redirect with context handler.
TEST(ResourceRequestHandlerTest,RedirectURLViaContext)3223 TEST(ResourceRequestHandlerTest, RedirectURLViaContext) {
3224 CefRefPtr<RedirectResponseTest> handler =
3225 new RedirectResponseTest(RedirectResponseTest::URL, true);
3226 handler->ExecuteTest();
3227 ReleaseAndWaitForDestructor(handler);
3228 }
3229
3230 // Verify redirect + modified headers with context handler.
TEST(ResourceRequestHandlerTest,RedirectHeaderViaContext)3231 TEST(ResourceRequestHandlerTest, RedirectHeaderViaContext) {
3232 CefRefPtr<RedirectResponseTest> handler =
3233 new RedirectResponseTest(RedirectResponseTest::HEADER, true);
3234 handler->ExecuteTest();
3235 ReleaseAndWaitForDestructor(handler);
3236 }
3237
3238 // Verify redirect + modified post data with context handler.
TEST(ResourceRequestHandlerTest,RedirectPostViaContext)3239 TEST(ResourceRequestHandlerTest, RedirectPostViaContext) {
3240 CefRefPtr<RedirectResponseTest> handler =
3241 new RedirectResponseTest(RedirectResponseTest::POST, true);
3242 handler->ExecuteTest();
3243 ReleaseAndWaitForDestructor(handler);
3244 }
3245
3246 namespace {
3247
3248 const char kResourceTestHtml2[] = "http://test.com/resource2.html";
3249
3250 class BeforeResourceLoadTest : public TestHandler {
3251 public:
3252 enum TestMode {
3253 CANCEL,
3254 CANCEL_ASYNC,
3255 CANCEL_NAV,
3256 CONTINUE,
3257 CONTINUE_ASYNC,
3258 };
3259
BeforeResourceLoadTest(TestMode mode)3260 explicit BeforeResourceLoadTest(TestMode mode) : test_mode_(mode) {}
3261
RunTest()3262 void RunTest() override {
3263 AddResource(kResourceTestHtml, "<html><body>Test</body></html>",
3264 "text/html");
3265 AddResource(kResourceTestHtml2, "<html><body>Test2</body></html>",
3266 "text/html");
3267 CreateBrowser(kResourceTestHtml);
3268 SetTestTimeout();
3269 }
3270
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)3271 cef_return_value_t OnBeforeResourceLoad(
3272 CefRefPtr<CefBrowser> browser,
3273 CefRefPtr<CefFrame> frame,
3274 CefRefPtr<CefRequest> request,
3275 CefRefPtr<CefCallback> callback) override {
3276 EXPECT_IO_THREAD();
3277
3278 if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
3279 // Ignore favicon requests.
3280 return RV_CANCEL;
3281 }
3282
3283 // Allow the 2nd navigation to continue.
3284 const std::string& url = request->GetURL();
3285 if (url == kResourceTestHtml2) {
3286 got_before_resource_load2_.yes();
3287 EXPECT_EQ(CANCEL_NAV, test_mode_);
3288 return RV_CONTINUE;
3289 }
3290
3291 EXPECT_FALSE(got_before_resource_load_);
3292 got_before_resource_load_.yes();
3293
3294 if (test_mode_ == CANCEL) {
3295 // Cancel immediately.
3296 return RV_CANCEL;
3297 } else if (test_mode_ == CONTINUE) {
3298 // Continue immediately.
3299 return RV_CONTINUE;
3300 } else {
3301 if (test_mode_ == CANCEL_NAV) {
3302 // Cancel the request by navigating to a new URL.
3303 browser->GetMainFrame()->LoadURL(kResourceTestHtml2);
3304 } else if (test_mode_ == CONTINUE_ASYNC) {
3305 // Continue asynchronously.
3306 CefPostTask(TID_UI,
3307 base::BindOnce(&CefCallback::Continue, callback.get()));
3308 } else {
3309 // Cancel asynchronously.
3310 CefPostTask(TID_UI,
3311 base::BindOnce(&CefCallback::Cancel, callback.get()));
3312 }
3313 return RV_CONTINUE_ASYNC;
3314 }
3315 }
3316
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)3317 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
3318 CefRefPtr<CefFrame> frame,
3319 int httpStatusCode) override {
3320 EXPECT_UI_THREAD();
3321
3322 EXPECT_FALSE(got_load_end_);
3323 got_load_end_.yes();
3324
3325 const std::string& url = frame->GetURL();
3326 if (test_mode_ == CANCEL_NAV)
3327 EXPECT_STREQ(kResourceTestHtml2, url.data());
3328 else
3329 EXPECT_STREQ(kResourceTestHtml, url.data());
3330
3331 TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
3332 DestroyTest();
3333 }
3334
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)3335 void OnLoadError(CefRefPtr<CefBrowser> browser,
3336 CefRefPtr<CefFrame> frame,
3337 ErrorCode errorCode,
3338 const CefString& errorText,
3339 const CefString& failedUrl) override {
3340 EXPECT_UI_THREAD();
3341
3342 EXPECT_FALSE(got_load_error_);
3343 got_load_error_.yes();
3344
3345 const std::string& url = failedUrl;
3346 EXPECT_STREQ(kResourceTestHtml, url.data());
3347
3348 TestHandler::OnLoadError(browser, frame, errorCode, errorText, failedUrl);
3349 if (test_mode_ != CANCEL_NAV)
3350 DestroyTest();
3351 }
3352
DestroyTest()3353 void DestroyTest() override {
3354 EXPECT_TRUE(got_before_resource_load_);
3355
3356 if (test_mode_ == CANCEL_NAV)
3357 EXPECT_TRUE(got_before_resource_load2_);
3358 else
3359 EXPECT_FALSE(got_before_resource_load2_);
3360
3361 if (test_mode_ == CONTINUE || test_mode_ == CONTINUE_ASYNC) {
3362 EXPECT_TRUE(got_load_end_);
3363 EXPECT_FALSE(got_load_error_);
3364 } else if (test_mode_ == CANCEL || test_mode_ == CANCEL_ASYNC) {
3365 EXPECT_FALSE(got_load_end_);
3366 EXPECT_TRUE(got_load_error_);
3367 }
3368
3369 TestHandler::DestroyTest();
3370 }
3371
3372 private:
3373 const TestMode test_mode_;
3374
3375 TrackCallback got_before_resource_load_;
3376 TrackCallback got_before_resource_load2_;
3377 TrackCallback got_load_end_;
3378 TrackCallback got_load_error_;
3379
3380 IMPLEMENT_REFCOUNTING(BeforeResourceLoadTest);
3381 };
3382
3383 } // namespace
3384
TEST(ResourceRequestHandlerTest,BeforeResourceLoadCancel)3385 TEST(ResourceRequestHandlerTest, BeforeResourceLoadCancel) {
3386 CefRefPtr<BeforeResourceLoadTest> handler =
3387 new BeforeResourceLoadTest(BeforeResourceLoadTest::CANCEL);
3388 handler->ExecuteTest();
3389 ReleaseAndWaitForDestructor(handler);
3390 }
3391
TEST(ResourceRequestHandlerTest,BeforeResourceLoadCancelAsync)3392 TEST(ResourceRequestHandlerTest, BeforeResourceLoadCancelAsync) {
3393 CefRefPtr<BeforeResourceLoadTest> handler =
3394 new BeforeResourceLoadTest(BeforeResourceLoadTest::CANCEL_ASYNC);
3395 handler->ExecuteTest();
3396 ReleaseAndWaitForDestructor(handler);
3397 }
3398
TEST(ResourceRequestHandlerTest,BeforeResourceLoadCancelNav)3399 TEST(ResourceRequestHandlerTest, BeforeResourceLoadCancelNav) {
3400 CefRefPtr<BeforeResourceLoadTest> handler =
3401 new BeforeResourceLoadTest(BeforeResourceLoadTest::CANCEL_NAV);
3402 handler->ExecuteTest();
3403 ReleaseAndWaitForDestructor(handler);
3404 }
3405
TEST(ResourceRequestHandlerTest,BeforeResourceLoadContinue)3406 TEST(ResourceRequestHandlerTest, BeforeResourceLoadContinue) {
3407 CefRefPtr<BeforeResourceLoadTest> handler =
3408 new BeforeResourceLoadTest(BeforeResourceLoadTest::CONTINUE);
3409 handler->ExecuteTest();
3410 ReleaseAndWaitForDestructor(handler);
3411 }
3412
TEST(ResourceRequestHandlerTest,BeforeResourceLoadContinueAsync)3413 TEST(ResourceRequestHandlerTest, BeforeResourceLoadContinueAsync) {
3414 CefRefPtr<BeforeResourceLoadTest> handler =
3415 new BeforeResourceLoadTest(BeforeResourceLoadTest::CONTINUE_ASYNC);
3416 handler->ExecuteTest();
3417 ReleaseAndWaitForDestructor(handler);
3418 }
3419
3420 namespace {
3421
3422 // For response filtering we need to test:
3423 // - Passing through content unchanged.
3424 // - Not reading all of the input buffer.
3425 // - Needing more input and getting it.
3426 // - Needing more input and not getting it.
3427 // - Filter error.
3428
3429 const char kResponseFilterTestUrl[] = "http://tests.com/response_filter.html";
3430
GetResponseBufferSize()3431 size_t GetResponseBufferSize() {
3432 // Match the default |capacity_num_bytes| value from
3433 // mojo::Core::CreateDataPipe.
3434 return 64 * 1024; // 64kb
3435 }
3436
3437 const char kInputHeader[] = "<html><head></head><body>";
3438 const char kInputFooter[] = "</body></html>";
3439
3440 // Repeat |content| the minimum number of times necessary to satisfy
3441 // |desired_min_size|. If |calculated_repeat_ct| is non-nullptr it will be set
3442 // to the number of times that |content| was repeated.
CreateInput(const std::string & content,size_t desired_min_size,size_t * calculated_repeat_ct=nullptr)3443 std::string CreateInput(const std::string& content,
3444 size_t desired_min_size,
3445 size_t* calculated_repeat_ct = nullptr) {
3446 const size_t header_footer_size =
3447 sizeof(kInputHeader) + sizeof(kInputFooter) - 2;
3448 EXPECT_GE(desired_min_size, header_footer_size + content.size());
3449 desired_min_size -= header_footer_size;
3450
3451 size_t repeat_ct =
3452 static_cast<size_t>(std::ceil(static_cast<double>(desired_min_size) /
3453 static_cast<double>(content.size())));
3454 if (calculated_repeat_ct)
3455 *calculated_repeat_ct = repeat_ct;
3456
3457 std::string result;
3458 result.reserve(header_footer_size + (content.size() * repeat_ct));
3459
3460 result = kInputHeader;
3461 while (repeat_ct--)
3462 result += content;
3463 result += kInputFooter;
3464
3465 return result;
3466 }
3467
CreateOutput(const std::string & content,size_t repeat_ct)3468 std::string CreateOutput(const std::string& content, size_t repeat_ct) {
3469 const size_t header_footer_size =
3470 sizeof(kInputHeader) + sizeof(kInputFooter) - 2;
3471
3472 std::string result;
3473 result.reserve(header_footer_size + (content.size() * repeat_ct));
3474
3475 result = kInputHeader;
3476 while (repeat_ct--)
3477 result += content;
3478 result += kInputFooter;
3479
3480 return result;
3481 }
3482
3483 // Base class for test filters.
3484 class ResponseFilterTestBase : public CefResponseFilter {
3485 public:
ResponseFilterTestBase()3486 ResponseFilterTestBase() : filter_count_(0U) {}
3487
InitFilter()3488 bool InitFilter() override {
3489 EXPECT_FALSE(got_init_filter_);
3490 got_init_filter_.yes();
3491 return true;
3492 }
3493
Filter(void * data_in,size_t data_in_size,size_t & data_in_read,void * data_out,size_t data_out_size,size_t & data_out_written)3494 FilterStatus Filter(void* data_in,
3495 size_t data_in_size,
3496 size_t& data_in_read,
3497 void* data_out,
3498 size_t data_out_size,
3499 size_t& data_out_written) override {
3500 if (data_in_size == 0U)
3501 EXPECT_FALSE(data_in);
3502 else
3503 EXPECT_TRUE(data_in);
3504 EXPECT_EQ(data_in_read, 0U);
3505 EXPECT_TRUE(data_out);
3506 EXPECT_GT(data_out_size, 0U);
3507 EXPECT_EQ(data_out_written, 0U);
3508 filter_count_++;
3509 return RESPONSE_FILTER_ERROR;
3510 }
3511
3512 // Returns the input that will be fed into the filter.
3513 virtual std::string GetInput() = 0;
3514
3515 // Verify the output from the filter.
VerifyOutput(cef_urlrequest_status_t status,int64 received_content_length,const std::string & received_content)3516 virtual void VerifyOutput(cef_urlrequest_status_t status,
3517 int64 received_content_length,
3518 const std::string& received_content) {
3519 EXPECT_TRUE(got_init_filter_);
3520 EXPECT_GT(filter_count_, 0U);
3521 }
3522
VerifyStatusCode(int httpStatusCode) const3523 virtual void VerifyStatusCode(int httpStatusCode) const {
3524 EXPECT_TRUE(httpStatusCode == 0 || httpStatusCode == 200) << httpStatusCode;
3525 }
3526
3527 protected:
3528 TrackCallback got_init_filter_;
3529 size_t filter_count_;
3530
3531 IMPLEMENT_REFCOUNTING(ResponseFilterTestBase);
3532 };
3533
3534 // Pass through the contents unchanged.
3535 class ResponseFilterPassThru : public ResponseFilterTestBase {
3536 public:
ResponseFilterPassThru(bool limit_read)3537 explicit ResponseFilterPassThru(bool limit_read) : limit_read_(limit_read) {}
3538
Filter(void * data_in,size_t data_in_size,size_t & data_in_read,void * data_out,size_t data_out_size,size_t & data_out_written)3539 FilterStatus Filter(void* data_in,
3540 size_t data_in_size,
3541 size_t& data_in_read,
3542 void* data_out,
3543 size_t data_out_size,
3544 size_t& data_out_written) override {
3545 ResponseFilterTestBase::Filter(data_in, data_in_size, data_in_read,
3546 data_out, data_out_size, data_out_written);
3547
3548 if (limit_read_) {
3549 // Read at most 1k bytes.
3550 data_in_read = std::min(data_in_size, static_cast<size_t>(1024U));
3551 } else {
3552 // Read all available bytes.
3553 data_in_read = data_in_size;
3554 }
3555
3556 data_out_written = std::min(data_in_read, data_out_size);
3557 memcpy(data_out, data_in, data_out_written);
3558
3559 return RESPONSE_FILTER_DONE;
3560 }
3561
GetInput()3562 std::string GetInput() override {
3563 input_ = CreateInput("FOOBAR ", GetResponseBufferSize() * 2U + 1);
3564 return input_;
3565 }
3566
VerifyOutput(cef_urlrequest_status_t status,int64 received_content_length,const std::string & received_content)3567 void VerifyOutput(cef_urlrequest_status_t status,
3568 int64 received_content_length,
3569 const std::string& received_content) override {
3570 ResponseFilterTestBase::VerifyOutput(status, received_content_length,
3571 received_content);
3572
3573 if (limit_read_)
3574 // Expected to read 2 full buffers of GetResponseBufferSize() at 1kb
3575 // increments and one partial buffer.
3576 EXPECT_EQ(2U * (GetResponseBufferSize() / 1024) + 1U, filter_count_);
3577 else {
3578 // Expected to read 2 full buffers of GetResponseBufferSize() and one
3579 // partial buffer.
3580 EXPECT_EQ(3U, filter_count_);
3581 }
3582 EXPECT_STREQ(input_.c_str(), received_content.c_str());
3583
3584 // Input size and content size should match.
3585 EXPECT_EQ(input_.size(), static_cast<size_t>(received_content_length));
3586 EXPECT_EQ(input_.size(), received_content.size());
3587 }
3588
3589 private:
3590 std::string input_;
3591 bool limit_read_;
3592 };
3593
3594 const char kFindString[] = "REPLACE_THIS_STRING";
3595 const char kReplaceString[] = "This is the replaced string!";
3596
3597 // Helper for passing params to Write().
3598 #define WRITE_PARAMS data_out_ptr, data_out_size, data_out_written
3599
3600 // Replace all instances of |kFindString| with |kReplaceString|.
3601 // This implementation is similar to the example in
3602 // tests/shared/response_filter_test.cc.
3603 class ResponseFilterNeedMore : public ResponseFilterTestBase {
3604 public:
ResponseFilterNeedMore()3605 ResponseFilterNeedMore()
3606 : find_match_offset_(0U),
3607 replace_overflow_size_(0U),
3608 input_size_(0U),
3609 repeat_ct_(0U) {}
3610
Filter(void * data_in,size_t data_in_size,size_t & data_in_read,void * data_out,size_t data_out_size,size_t & data_out_written)3611 FilterStatus Filter(void* data_in,
3612 size_t data_in_size,
3613 size_t& data_in_read,
3614 void* data_out,
3615 size_t data_out_size,
3616 size_t& data_out_written) override {
3617 ResponseFilterTestBase::Filter(data_in, data_in_size, data_in_read,
3618 data_out, data_out_size, data_out_written);
3619
3620 // All data will be read.
3621 data_in_read = data_in_size;
3622
3623 const size_t find_size = sizeof(kFindString) - 1;
3624
3625 const char* data_in_ptr = static_cast<char*>(data_in);
3626 char* data_out_ptr = static_cast<char*>(data_out);
3627
3628 // Reset the overflow.
3629 std::string old_overflow;
3630 if (!overflow_.empty()) {
3631 old_overflow = overflow_;
3632 overflow_.clear();
3633 }
3634
3635 const size_t likely_out_size =
3636 data_in_size + replace_overflow_size_ + old_overflow.size();
3637 if (data_out_size < likely_out_size) {
3638 // We'll likely need to use the overflow buffer. Size it appropriately.
3639 overflow_.reserve(likely_out_size - data_out_size);
3640 }
3641
3642 if (!old_overflow.empty()) {
3643 // Write the overflow from last time.
3644 Write(old_overflow.c_str(), old_overflow.size(), WRITE_PARAMS);
3645 }
3646
3647 // Evaluate each character in the input buffer. Track how many characters in
3648 // a row match kFindString. If kFindString is completely matched then write
3649 // kReplaceString. Otherwise, write the input characters as-is.
3650 for (size_t i = 0U; i < data_in_size; ++i) {
3651 if (data_in_ptr[i] == kFindString[find_match_offset_]) {
3652 // Matched the next character in the find string.
3653 if (++find_match_offset_ == find_size) {
3654 // Complete match of the find string. Write the replace string.
3655 Write(kReplaceString, sizeof(kReplaceString) - 1, WRITE_PARAMS);
3656
3657 // Start over looking for a match.
3658 find_match_offset_ = 0;
3659 }
3660 continue;
3661 }
3662
3663 // Character did not match the find string.
3664 if (find_match_offset_ > 0) {
3665 // Write the portion of the find string that has matched so far.
3666 Write(kFindString, find_match_offset_, WRITE_PARAMS);
3667
3668 // Start over looking for a match.
3669 find_match_offset_ = 0;
3670 }
3671
3672 // Write the current character.
3673 Write(&data_in_ptr[i], 1, WRITE_PARAMS);
3674 }
3675
3676 // If a match is currently in-progress and input was provided then we need
3677 // more data. Otherwise, we're done.
3678 return find_match_offset_ > 0 && data_in_size > 0
3679 ? RESPONSE_FILTER_NEED_MORE_DATA
3680 : RESPONSE_FILTER_DONE;
3681 }
3682
GetInput()3683 std::string GetInput() override {
3684 const std::string& input =
3685 CreateInput(std::string(kFindString) + " ",
3686 GetResponseBufferSize() * 2U + 1, &repeat_ct_);
3687 input_size_ = input.size();
3688
3689 const size_t find_size = sizeof(kFindString) - 1;
3690 const size_t replace_size = sizeof(kReplaceString) - 1;
3691
3692 // Determine a reasonable amount of space for find/replace overflow.
3693 if (replace_size > find_size)
3694 replace_overflow_size_ = (replace_size - find_size) * repeat_ct_;
3695
3696 return input;
3697 }
3698
VerifyOutput(cef_urlrequest_status_t status,int64 received_content_length,const std::string & received_content)3699 void VerifyOutput(cef_urlrequest_status_t status,
3700 int64 received_content_length,
3701 const std::string& received_content) override {
3702 ResponseFilterTestBase::VerifyOutput(status, received_content_length,
3703 received_content);
3704
3705 const std::string& output =
3706 CreateOutput(std::string(kReplaceString) + " ", repeat_ct_);
3707 EXPECT_STREQ(output.c_str(), received_content.c_str());
3708
3709 // Pre-filter content length should be the original input size.
3710 EXPECT_EQ(input_size_, static_cast<size_t>(received_content_length));
3711
3712 // Filtered content length should be the output size.
3713 EXPECT_EQ(output.size(), received_content.size());
3714
3715 // Expected to read 2 full buffers of GetResponseBufferSize() and one
3716 // partial buffer, and then one additional call to drain the overflow.
3717 EXPECT_EQ(4U, filter_count_);
3718 }
3719
3720 private:
Write(const char * str,size_t str_size,char * & data_out_ptr,size_t data_out_size,size_t & data_out_written)3721 inline void Write(const char* str,
3722 size_t str_size,
3723 char*& data_out_ptr,
3724 size_t data_out_size,
3725 size_t& data_out_written) {
3726 // Number of bytes remaining in the output buffer.
3727 const size_t remaining_space = data_out_size - data_out_written;
3728 // Maximum number of bytes we can write into the output buffer.
3729 const size_t max_write = std::min(str_size, remaining_space);
3730
3731 // Write the maximum portion that fits in the output buffer.
3732 if (max_write == 1) {
3733 // Small optimization for single character writes.
3734 *data_out_ptr = str[0];
3735 data_out_ptr += 1;
3736 data_out_written += 1;
3737 } else if (max_write > 1) {
3738 memcpy(data_out_ptr, str, max_write);
3739 data_out_ptr += max_write;
3740 data_out_written += max_write;
3741 }
3742
3743 if (max_write < str_size) {
3744 // Need to write more bytes than will fit in the output buffer. Store the
3745 // remainder in the overflow buffer.
3746 overflow_ += std::string(str + max_write, str_size - max_write);
3747 }
3748 }
3749
3750 // The portion of the find string that is currently matching.
3751 size_t find_match_offset_;
3752
3753 // The likely amount of overflow.
3754 size_t replace_overflow_size_;
3755
3756 // Overflow from the output buffer.
3757 std::string overflow_;
3758
3759 // The original input size.
3760 size_t input_size_;
3761
3762 // The number of times the find string was repeated.
3763 size_t repeat_ct_;
3764 };
3765
3766 // Return a filter error.
3767 class ResponseFilterError : public ResponseFilterTestBase {
3768 public:
ResponseFilterError()3769 ResponseFilterError() {}
3770
Filter(void * data_in,size_t data_in_size,size_t & data_in_read,void * data_out,size_t data_out_size,size_t & data_out_written)3771 FilterStatus Filter(void* data_in,
3772 size_t data_in_size,
3773 size_t& data_in_read,
3774 void* data_out,
3775 size_t data_out_size,
3776 size_t& data_out_written) override {
3777 ResponseFilterTestBase::Filter(data_in, data_in_size, data_in_read,
3778 data_out, data_out_size, data_out_written);
3779
3780 return RESPONSE_FILTER_ERROR;
3781 }
3782
GetInput()3783 std::string GetInput() override {
3784 return kInputHeader + std::string("ERROR") + kInputFooter;
3785 }
3786
VerifyOutput(cef_urlrequest_status_t status,int64 received_content_length,const std::string & received_content)3787 void VerifyOutput(cef_urlrequest_status_t status,
3788 int64 received_content_length,
3789 const std::string& received_content) override {
3790 ResponseFilterTestBase::VerifyOutput(status, received_content_length,
3791 received_content);
3792
3793 EXPECT_EQ(UR_FAILED, status);
3794
3795 // Expect empty content.
3796 EXPECT_STREQ("", received_content.c_str());
3797 EXPECT_EQ(0U, received_content_length);
3798
3799 // Expect to only be called one time.
3800 EXPECT_EQ(filter_count_, 1U);
3801 }
3802
VerifyStatusCode(int httpStatusCode) const3803 void VerifyStatusCode(int httpStatusCode) const override {
3804 EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, httpStatusCode);
3805 }
3806 };
3807
3808 class ResponseFilterTestHandler : public TestHandler {
3809 public:
ResponseFilterTestHandler(CefRefPtr<ResponseFilterTestBase> response_filter)3810 explicit ResponseFilterTestHandler(
3811 CefRefPtr<ResponseFilterTestBase> response_filter)
3812 : response_filter_(response_filter) {}
3813
RunTest()3814 void RunTest() override {
3815 const std::string& resource = response_filter_->GetInput();
3816 AddResource(kResponseFilterTestUrl, resource, "text/html");
3817
3818 // Create the browser.
3819 CreateBrowser(kResponseFilterTestUrl);
3820
3821 // Time out the test after a reasonable period of time.
3822 SetTestTimeout();
3823 }
3824
GetResourceResponseFilter(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)3825 CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
3826 CefRefPtr<CefBrowser> browser,
3827 CefRefPtr<CefFrame> frame,
3828 CefRefPtr<CefRequest> request,
3829 CefRefPtr<CefResponse> response) override {
3830 EXPECT_IO_THREAD();
3831
3832 DCHECK(!got_resource_response_filter_);
3833 got_resource_response_filter_.yes();
3834 return response_filter_;
3835 }
3836
OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response,URLRequestStatus status,int64 received_content_length)3837 void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
3838 CefRefPtr<CefFrame> frame,
3839 CefRefPtr<CefRequest> request,
3840 CefRefPtr<CefResponse> response,
3841 URLRequestStatus status,
3842 int64 received_content_length) override {
3843 EXPECT_IO_THREAD();
3844
3845 if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
3846 // Ignore favicon requests.
3847 return;
3848 }
3849
3850 DCHECK(!got_resource_load_complete_);
3851 got_resource_load_complete_.yes();
3852
3853 status_ = status;
3854 received_content_length_ = received_content_length;
3855 }
3856
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)3857 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
3858 CefRefPtr<CefFrame> frame,
3859 int httpStatusCode) override {
3860 DCHECK(!got_load_end_);
3861 got_load_end_.yes();
3862
3863 response_filter_->VerifyStatusCode(httpStatusCode);
3864
3865 GetOutputContent(frame);
3866 }
3867
3868 private:
3869 // Retrieve the output content using a StringVisitor. This effectively
3870 // serializes the DOM from the renderer process so any comparison to the
3871 // filter output is somewhat error-prone.
GetOutputContent(CefRefPtr<CefFrame> frame)3872 void GetOutputContent(CefRefPtr<CefFrame> frame) {
3873 class StringVisitor : public CefStringVisitor {
3874 public:
3875 using VisitorCallback =
3876 base::OnceCallback<void(const std::string& /*received_content*/)>;
3877
3878 explicit StringVisitor(VisitorCallback callback)
3879 : callback_(std::move(callback)) {}
3880
3881 void Visit(const CefString& string) override {
3882 std::move(callback_).Run(string);
3883 }
3884
3885 private:
3886 VisitorCallback callback_;
3887
3888 IMPLEMENT_REFCOUNTING(StringVisitor);
3889 };
3890
3891 frame->GetSource(new StringVisitor(
3892 base::BindOnce(&ResponseFilterTestHandler::VerifyOutput, this)));
3893 }
3894
VerifyOutput(const std::string & received_content)3895 void VerifyOutput(const std::string& received_content) {
3896 response_filter_->VerifyOutput(status_, received_content_length_,
3897 received_content);
3898 response_filter_ = nullptr;
3899
3900 DestroyTest();
3901 }
3902
DestroyTest()3903 void DestroyTest() override {
3904 EXPECT_TRUE(got_resource_response_filter_);
3905 EXPECT_TRUE(got_resource_load_complete_);
3906 EXPECT_TRUE(got_load_end_);
3907
3908 TestHandler::DestroyTest();
3909 }
3910
3911 CefRefPtr<ResponseFilterTestBase> response_filter_;
3912
3913 TrackCallback got_resource_response_filter_;
3914 TrackCallback got_resource_load_complete_;
3915 TrackCallback got_load_end_;
3916
3917 URLRequestStatus status_;
3918 int64 received_content_length_;
3919
3920 IMPLEMENT_REFCOUNTING(ResponseFilterTestHandler);
3921 };
3922
3923 } // namespace
3924
3925 // Pass through contents unchanged. Read all available input.
TEST(ResourceRequestHandlerTest,FilterPassThruReadAll)3926 TEST(ResourceRequestHandlerTest, FilterPassThruReadAll) {
3927 CefRefPtr<ResponseFilterTestHandler> handler =
3928 new ResponseFilterTestHandler(new ResponseFilterPassThru(false));
3929 handler->ExecuteTest();
3930 ReleaseAndWaitForDestructor(handler);
3931 }
3932
3933 // Pass through contents unchanged. Read limited input.
TEST(ResourceRequestHandlerTest,FilterPassThruReadLimited)3934 TEST(ResourceRequestHandlerTest, FilterPassThruReadLimited) {
3935 CefRefPtr<ResponseFilterTestHandler> handler =
3936 new ResponseFilterTestHandler(new ResponseFilterPassThru(true));
3937 handler->ExecuteTest();
3938 ReleaseAndWaitForDestructor(handler);
3939 }
3940
3941 // Find/replace contents such that we occasionally need more data.
TEST(ResourceRequestHandlerTest,FilterNeedMore)3942 TEST(ResourceRequestHandlerTest, FilterNeedMore) {
3943 CefRefPtr<ResponseFilterTestHandler> handler =
3944 new ResponseFilterTestHandler(new ResponseFilterNeedMore());
3945 handler->ExecuteTest();
3946 ReleaseAndWaitForDestructor(handler);
3947 }
3948
3949 // Error during filtering.
TEST(ResourceRequestHandlerTest,FilterError)3950 TEST(ResourceRequestHandlerTest, FilterError) {
3951 CefRefPtr<ResponseFilterTestHandler> handler =
3952 new ResponseFilterTestHandler(new ResponseFilterError());
3953 handler->ExecuteTest();
3954 ReleaseAndWaitForDestructor(handler);
3955 }
3956
3957 // Entry point for registering custom schemes.
3958 // Called from client_app_delegates.cc.
RegisterResourceRequestHandlerCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar)3959 void RegisterResourceRequestHandlerCustomSchemes(
3960 CefRawPtr<CefSchemeRegistrar> registrar) {
3961 // Add a custom standard scheme.
3962 registrar->AddCustomScheme(
3963 "rrhcustom", CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_CORS_ENABLED);
3964 }
3965