• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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