mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	Some test cases don't create browsers at all, or require additional signals such as request context destruction. To test: Run `ceftests --gtest_filter=URLRequestTest.*`
		
			
				
	
	
		
			4010 lines
		
	
	
		
			132 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			4010 lines
		
	
	
		
			132 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
 | 
						|
// reserved. Use of this source code is governed by a BSD-style license that
 | 
						|
// can be found in the LICENSE file.
 | 
						|
 | 
						|
#include <algorithm>
 | 
						|
#include <cmath>
 | 
						|
#include <memory>
 | 
						|
#include <sstream>
 | 
						|
#include <string>
 | 
						|
 | 
						|
#include "include/base/cef_callback.h"
 | 
						|
#include "include/cef_request_context_handler.h"
 | 
						|
#include "include/cef_scheme.h"
 | 
						|
#include "include/wrapper/cef_closure_task.h"
 | 
						|
#include "include/wrapper/cef_stream_resource_handler.h"
 | 
						|
#include "tests/ceftests/routing_test_handler.h"
 | 
						|
#include "tests/ceftests/test_handler.h"
 | 
						|
#include "tests/ceftests/test_util.h"
 | 
						|
#include "tests/gtest/include/gtest/gtest.h"
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
// Normal stream resource handler implementation that additionally verifies
 | 
						|
// calls to Cancel.
 | 
						|
// This also tests the CefStreamResourceHandler implementation.
 | 
						|
class NormalResourceHandler : public CefStreamResourceHandler {
 | 
						|
 public:
 | 
						|
  NormalResourceHandler(int status_code,
 | 
						|
                        const CefString& status_text,
 | 
						|
                        const CefString& mime_type,
 | 
						|
                        CefResponse::HeaderMap header_map,
 | 
						|
                        CefRefPtr<CefStreamReader> stream,
 | 
						|
                        base::OnceClosure destroy_callback)
 | 
						|
      : CefStreamResourceHandler(status_code,
 | 
						|
                                 status_text,
 | 
						|
                                 mime_type,
 | 
						|
                                 header_map,
 | 
						|
                                 stream),
 | 
						|
        destroy_callback_(std::move(destroy_callback)) {}
 | 
						|
 | 
						|
  ~NormalResourceHandler() override {
 | 
						|
    EXPECT_EQ(1, cancel_ct_);
 | 
						|
    std::move(destroy_callback_).Run();
 | 
						|
  }
 | 
						|
 | 
						|
  void Cancel() override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    cancel_ct_++;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  base::OnceClosure destroy_callback_;
 | 
						|
  int cancel_ct_ = 0;
 | 
						|
};
 | 
						|
 | 
						|
// Normal stream resource handler implementation that additionally continues
 | 
						|
// using the callback object and verifies calls to Cancel.
 | 
						|
class CallbackResourceHandler : public CefResourceHandler {
 | 
						|
 public:
 | 
						|
  enum Mode {
 | 
						|
    DELAYED_OPEN,
 | 
						|
    DELAYED_READ,
 | 
						|
    IMMEDIATE_OPEN,
 | 
						|
    IMMEDIATE_READ,
 | 
						|
    DELAYED_ALL,
 | 
						|
    IMMEDIATE_ALL,
 | 
						|
  };
 | 
						|
 | 
						|
  bool IsDelayedOpen() const {
 | 
						|
    return mode_ == DELAYED_OPEN || mode_ == DELAYED_ALL;
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsDelayedRead() const {
 | 
						|
    return mode_ == DELAYED_READ || mode_ == DELAYED_ALL;
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsImmediateOpen() const {
 | 
						|
    return mode_ == IMMEDIATE_OPEN || mode_ == IMMEDIATE_ALL;
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsImmediateRead() const {
 | 
						|
    return mode_ == IMMEDIATE_READ || mode_ == IMMEDIATE_ALL;
 | 
						|
  }
 | 
						|
 | 
						|
  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)
 | 
						|
      : mode_(mode),
 | 
						|
        status_code_(status_code),
 | 
						|
        status_text_(status_text),
 | 
						|
        mime_type_(mime_type),
 | 
						|
        header_map_(header_map),
 | 
						|
        stream_(stream),
 | 
						|
        destroy_callback_(std::move(destroy_callback)) {
 | 
						|
    DCHECK(!mime_type_.empty());
 | 
						|
    DCHECK(stream_.get());
 | 
						|
  }
 | 
						|
 | 
						|
  ~CallbackResourceHandler() override {
 | 
						|
    EXPECT_EQ(1, cancel_ct_);
 | 
						|
    std::move(destroy_callback_).Run();
 | 
						|
  }
 | 
						|
 | 
						|
  bool Open(CefRefPtr<CefRequest> request,
 | 
						|
            bool& handle_request,
 | 
						|
            CefRefPtr<CefCallback> callback) override {
 | 
						|
    EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
 | 
						|
 | 
						|
    if (IsDelayedOpen()) {
 | 
						|
      // Continue the request asynchronously by executing the callback.
 | 
						|
      CefPostTask(TID_FILE_USER_VISIBLE,
 | 
						|
                  base::BindOnce(&CefCallback::Continue, callback));
 | 
						|
      handle_request = false;
 | 
						|
      return true;
 | 
						|
    } else if (IsImmediateOpen()) {
 | 
						|
      // Continue the request immediately be executing the callback.
 | 
						|
      callback->Continue();
 | 
						|
      handle_request = false;
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // Continue the request immediately in the default manner.
 | 
						|
    handle_request = true;
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  void GetResponseHeaders(CefRefPtr<CefResponse> response,
 | 
						|
                          int64_t& response_length,
 | 
						|
                          CefString& redirectUrl) override {
 | 
						|
    response->SetStatus(status_code_);
 | 
						|
    response->SetStatusText(status_text_);
 | 
						|
    response->SetMimeType(mime_type_);
 | 
						|
 | 
						|
    if (!header_map_.empty()) {
 | 
						|
      response->SetHeaderMap(header_map_);
 | 
						|
    }
 | 
						|
 | 
						|
    response_length = -1;
 | 
						|
  }
 | 
						|
 | 
						|
  bool Read(void* data_out,
 | 
						|
            int bytes_to_read,
 | 
						|
            int& bytes_read,
 | 
						|
            CefRefPtr<CefResourceReadCallback> callback) override {
 | 
						|
    EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
 | 
						|
    EXPECT_GT(bytes_to_read, 0);
 | 
						|
 | 
						|
    bytes_read = 0;
 | 
						|
 | 
						|
    if (IsDelayedRead()) {
 | 
						|
      // Continue the request asynchronously by executing the callback.
 | 
						|
      CefPostTask(TID_FILE_USER_VISIBLE,
 | 
						|
                  base::BindOnce(&CallbackResourceHandler::ContinueRead, this,
 | 
						|
                                 data_out, bytes_to_read, callback));
 | 
						|
      return true;
 | 
						|
    } else if (IsImmediateRead()) {
 | 
						|
      // Continue the request immediately be executing the callback.
 | 
						|
      ContinueRead(data_out, bytes_to_read, callback);
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // Continue the request immediately in the default manner.
 | 
						|
    return DoRead(data_out, bytes_to_read, bytes_read);
 | 
						|
  }
 | 
						|
 | 
						|
  void Cancel() override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    cancel_ct_++;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  void ContinueRead(void* data_out,
 | 
						|
                    int bytes_to_read,
 | 
						|
                    CefRefPtr<CefResourceReadCallback> callback) {
 | 
						|
    EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
 | 
						|
 | 
						|
    int bytes_read = 0;
 | 
						|
    DoRead(data_out, bytes_to_read, bytes_read);
 | 
						|
    callback->Continue(bytes_read);
 | 
						|
  }
 | 
						|
 | 
						|
  bool DoRead(void* data_out, int bytes_to_read, int& bytes_read) {
 | 
						|
    EXPECT_GT(bytes_to_read, 0);
 | 
						|
 | 
						|
    // Read until the buffer is full or until Read() returns 0 to indicate no
 | 
						|
    // more data.
 | 
						|
    bytes_read = 0;
 | 
						|
    int read = 0;
 | 
						|
    do {
 | 
						|
      read = static_cast<int>(
 | 
						|
          stream_->Read(static_cast<char*>(data_out) + bytes_read, 1,
 | 
						|
                        bytes_to_read - bytes_read));
 | 
						|
      bytes_read += read;
 | 
						|
    } while (read != 0 && bytes_read < bytes_to_read);
 | 
						|
 | 
						|
    return (bytes_read > 0);
 | 
						|
  }
 | 
						|
 | 
						|
  const Mode mode_;
 | 
						|
 | 
						|
  const int status_code_;
 | 
						|
  const CefString status_text_;
 | 
						|
  const CefString mime_type_;
 | 
						|
  const CefResponse::HeaderMap header_map_;
 | 
						|
  const CefRefPtr<CefStreamReader> stream_;
 | 
						|
 | 
						|
  base::OnceClosure destroy_callback_;
 | 
						|
  int cancel_ct_ = 0;
 | 
						|
 | 
						|
  IMPLEMENT_REFCOUNTING(CallbackResourceHandler);
 | 
						|
  DISALLOW_COPY_AND_ASSIGN(CallbackResourceHandler);
 | 
						|
};
 | 
						|
 | 
						|
// Resource handler implementation that never completes. Used to test
 | 
						|
// destruction handling behavior for in-progress requests.
 | 
						|
class IncompleteResourceHandlerOld : public CefResourceHandler {
 | 
						|
 public:
 | 
						|
  enum TestMode {
 | 
						|
    BLOCK_PROCESS_REQUEST,
 | 
						|
    BLOCK_READ_RESPONSE,
 | 
						|
  };
 | 
						|
 | 
						|
  IncompleteResourceHandlerOld(TestMode test_mode,
 | 
						|
                               const std::string& mime_type,
 | 
						|
                               base::OnceClosure destroy_callback)
 | 
						|
      : test_mode_(test_mode),
 | 
						|
        mime_type_(mime_type),
 | 
						|
        destroy_callback_(std::move(destroy_callback)) {}
 | 
						|
 | 
						|
  ~IncompleteResourceHandlerOld() override {
 | 
						|
    EXPECT_EQ(1, process_request_ct_);
 | 
						|
 | 
						|
    EXPECT_EQ(1, cancel_ct_);
 | 
						|
 | 
						|
    if (test_mode_ == BLOCK_READ_RESPONSE) {
 | 
						|
      EXPECT_EQ(1, get_response_headers_ct_);
 | 
						|
      EXPECT_EQ(1, read_response_ct_);
 | 
						|
    } else {
 | 
						|
      EXPECT_EQ(0, get_response_headers_ct_);
 | 
						|
      EXPECT_EQ(0, read_response_ct_);
 | 
						|
    }
 | 
						|
 | 
						|
    std::move(destroy_callback_).Run();
 | 
						|
  }
 | 
						|
 | 
						|
  bool ProcessRequest(CefRefPtr<CefRequest> request,
 | 
						|
                      CefRefPtr<CefCallback> callback) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
 | 
						|
    process_request_ct_++;
 | 
						|
 | 
						|
    if (test_mode_ == BLOCK_PROCESS_REQUEST) {
 | 
						|
      // Never release or execute this callback.
 | 
						|
      incomplete_callback_ = callback;
 | 
						|
    } else {
 | 
						|
      callback->Continue();
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  void GetResponseHeaders(CefRefPtr<CefResponse> response,
 | 
						|
                          int64_t& response_length,
 | 
						|
                          CefString& redirectUrl) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(test_mode_, BLOCK_READ_RESPONSE);
 | 
						|
 | 
						|
    get_response_headers_ct_++;
 | 
						|
 | 
						|
    response->SetStatus(200);
 | 
						|
    response->SetStatusText("OK");
 | 
						|
    response->SetMimeType(mime_type_);
 | 
						|
    response_length = 100;
 | 
						|
  }
 | 
						|
 | 
						|
  bool ReadResponse(void* data_out,
 | 
						|
                    int bytes_to_read,
 | 
						|
                    int& bytes_read,
 | 
						|
                    CefRefPtr<CefCallback> callback) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(test_mode_, BLOCK_READ_RESPONSE);
 | 
						|
 | 
						|
    read_response_ct_++;
 | 
						|
 | 
						|
    // Never release or execute this callback.
 | 
						|
    incomplete_callback_ = callback;
 | 
						|
    bytes_read = 0;
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  void Cancel() override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    cancel_ct_++;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  const TestMode test_mode_;
 | 
						|
  const std::string mime_type_;
 | 
						|
  base::OnceClosure destroy_callback_;
 | 
						|
 | 
						|
  int process_request_ct_ = 0;
 | 
						|
  int get_response_headers_ct_ = 0;
 | 
						|
  int read_response_ct_ = 0;
 | 
						|
  int cancel_ct_ = 0;
 | 
						|
 | 
						|
  CefRefPtr<CefCallback> incomplete_callback_;
 | 
						|
 | 
						|
  IMPLEMENT_REFCOUNTING(IncompleteResourceHandlerOld);
 | 
						|
  DISALLOW_COPY_AND_ASSIGN(IncompleteResourceHandlerOld);
 | 
						|
};
 | 
						|
 | 
						|
class IncompleteResourceHandler : public CefResourceHandler {
 | 
						|
 public:
 | 
						|
  enum TestMode {
 | 
						|
    BLOCK_OPEN,
 | 
						|
    BLOCK_READ,
 | 
						|
  };
 | 
						|
 | 
						|
  IncompleteResourceHandler(TestMode test_mode,
 | 
						|
                            const std::string& mime_type,
 | 
						|
                            base::OnceClosure destroy_callback)
 | 
						|
      : test_mode_(test_mode),
 | 
						|
        mime_type_(mime_type),
 | 
						|
        destroy_callback_(std::move(destroy_callback)) {}
 | 
						|
 | 
						|
  ~IncompleteResourceHandler() override {
 | 
						|
    EXPECT_EQ(1, open_ct_);
 | 
						|
 | 
						|
    EXPECT_EQ(1, cancel_ct_);
 | 
						|
 | 
						|
    if (test_mode_ == BLOCK_READ) {
 | 
						|
      EXPECT_EQ(1, get_response_headers_ct_);
 | 
						|
      EXPECT_EQ(1, read_ct_);
 | 
						|
    } else {
 | 
						|
      EXPECT_EQ(0, get_response_headers_ct_);
 | 
						|
      EXPECT_EQ(0, read_ct_);
 | 
						|
    }
 | 
						|
 | 
						|
    std::move(destroy_callback_).Run();
 | 
						|
  }
 | 
						|
 | 
						|
  bool Open(CefRefPtr<CefRequest> request,
 | 
						|
            bool& handle_request,
 | 
						|
            CefRefPtr<CefCallback> callback) override {
 | 
						|
    EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
 | 
						|
 | 
						|
    open_ct_++;
 | 
						|
 | 
						|
    if (test_mode_ == BLOCK_OPEN) {
 | 
						|
      // Never release or execute this callback.
 | 
						|
      incomplete_open_callback_ = callback;
 | 
						|
    } else {
 | 
						|
      // Continue immediately.
 | 
						|
      handle_request = true;
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  bool ProcessRequest(CefRefPtr<CefRequest> request,
 | 
						|
                      CefRefPtr<CefCallback> callback) override {
 | 
						|
    EXPECT_TRUE(false);  // Not reached.
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  void GetResponseHeaders(CefRefPtr<CefResponse> response,
 | 
						|
                          int64_t& response_length,
 | 
						|
                          CefString& redirectUrl) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(test_mode_, BLOCK_READ);
 | 
						|
 | 
						|
    get_response_headers_ct_++;
 | 
						|
 | 
						|
    response->SetStatus(200);
 | 
						|
    response->SetStatusText("OK");
 | 
						|
    response->SetMimeType(mime_type_);
 | 
						|
    response_length = 100;
 | 
						|
  }
 | 
						|
 | 
						|
  bool Read(void* data_out,
 | 
						|
            int bytes_to_read,
 | 
						|
            int& bytes_read,
 | 
						|
            CefRefPtr<CefResourceReadCallback> callback) override {
 | 
						|
    EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
 | 
						|
    EXPECT_EQ(test_mode_, BLOCK_READ);
 | 
						|
 | 
						|
    read_ct_++;
 | 
						|
 | 
						|
    // Never release or execute this callback.
 | 
						|
    incomplete_read_callback_ = callback;
 | 
						|
    bytes_read = 0;
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  bool ReadResponse(void* data_out,
 | 
						|
                    int bytes_to_read,
 | 
						|
                    int& bytes_read,
 | 
						|
                    CefRefPtr<CefCallback> callback) override {
 | 
						|
    EXPECT_TRUE(false);  // Not reached.
 | 
						|
    bytes_read = -2;
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  void Cancel() override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    cancel_ct_++;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  const TestMode test_mode_;
 | 
						|
  const std::string mime_type_;
 | 
						|
  base::OnceClosure destroy_callback_;
 | 
						|
 | 
						|
  int open_ct_ = 0;
 | 
						|
  int get_response_headers_ct_ = 0;
 | 
						|
  int read_ct_ = 0;
 | 
						|
  int cancel_ct_ = 0;
 | 
						|
 | 
						|
  CefRefPtr<CefCallback> incomplete_open_callback_;
 | 
						|
  CefRefPtr<CefResourceReadCallback> incomplete_read_callback_;
 | 
						|
 | 
						|
  IMPLEMENT_REFCOUNTING(IncompleteResourceHandler);
 | 
						|
  DISALLOW_COPY_AND_ASSIGN(IncompleteResourceHandler);
 | 
						|
};
 | 
						|
 | 
						|
class BasicResponseTest : public TestHandler {
 | 
						|
 public:
 | 
						|
  enum TestMode {
 | 
						|
    // Normal load, nothing fancy.
 | 
						|
    LOAD,
 | 
						|
 | 
						|
    // Close the browser in OnAfterCreated to verify destruction handling of
 | 
						|
    // uninitialized requests.
 | 
						|
    ABORT_AFTER_CREATED,
 | 
						|
 | 
						|
    // Close the browser in OnBeforeBrowse to verify destruction handling of
 | 
						|
    // uninitialized requests.
 | 
						|
    ABORT_BEFORE_BROWSE,
 | 
						|
 | 
						|
    // Don't continue from OnBeforeResourceLoad, then close the browser to
 | 
						|
    // verify destruction handling of in-progress requests.
 | 
						|
    INCOMPLETE_BEFORE_RESOURCE_LOAD,
 | 
						|
 | 
						|
    // Modify the request (add headers) in OnBeforeResourceLoad.
 | 
						|
    MODIFY_BEFORE_RESOURCE_LOAD,
 | 
						|
 | 
						|
    // Redirect the request (change the URL) in OnBeforeResourceLoad.
 | 
						|
    REDIRECT_BEFORE_RESOURCE_LOAD,
 | 
						|
 | 
						|
    // Return a CefResourceHandler from GetResourceHandler that continues
 | 
						|
    // immediately by using the callback object instead of the return value.
 | 
						|
    IMMEDIATE_REQUEST_HANDLER_OPEN,
 | 
						|
    IMMEDIATE_REQUEST_HANDLER_READ,
 | 
						|
    IMMEDIATE_REQUEST_HANDLER_ALL,
 | 
						|
 | 
						|
    // Return a CefResourceHandler from GetResourceHandler that continues with
 | 
						|
    // a delay by using the callback object.
 | 
						|
    DELAYED_REQUEST_HANDLER_OPEN,
 | 
						|
    DELAYED_REQUEST_HANDLER_READ,
 | 
						|
    DELAYED_REQUEST_HANDLER_ALL,
 | 
						|
 | 
						|
    // Return a CefResourceHandler from GetResourceHandler that never completes,
 | 
						|
    // then close the browser to verify destruction handling of in-progress
 | 
						|
    // requests.
 | 
						|
    INCOMPLETE_REQUEST_HANDLER_OPEN,
 | 
						|
    INCOMPLETE_REQUEST_HANDLER_READ,
 | 
						|
 | 
						|
    // Redirect the request using a CefResourceHandler returned from
 | 
						|
    // GetResourceHandler.
 | 
						|
    REDIRECT_REQUEST_HANDLER,
 | 
						|
 | 
						|
    // Redirect the request (change the URL) an additional time in
 | 
						|
    // OnResourceRedirect after using a CefResourceHandler returned from
 | 
						|
    // GetResourceHandler for the first redirect.
 | 
						|
    REDIRECT_RESOURCE_REDIRECT,
 | 
						|
 | 
						|
    // Redirect the request (change the URL) in OnResourceResponse.
 | 
						|
    REDIRECT_RESOURCE_RESPONSE,
 | 
						|
 | 
						|
    // Restart the request (add headers) in OnResourceResponse.
 | 
						|
    RESTART_RESOURCE_RESPONSE,
 | 
						|
  };
 | 
						|
 | 
						|
  // If |custom_scheme| is true all requests will use a custom scheme.
 | 
						|
  // If |unhandled| is true the final request (after any redirects) will be
 | 
						|
  // unhandled, meaning that default handling is disabled and GetResourceHandler
 | 
						|
  // returns null.
 | 
						|
  BasicResponseTest(TestMode mode, bool custom_scheme, bool unhandled)
 | 
						|
      : mode_(mode), custom_scheme_(custom_scheme), unhandled_(unhandled) {}
 | 
						|
 | 
						|
  void RunTest() override {
 | 
						|
    CreateBrowser(GetStartupURL());
 | 
						|
    SetTestTimeout();
 | 
						|
  }
 | 
						|
 | 
						|
  void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
 | 
						|
    EXPECT_UI_THREAD();
 | 
						|
    TestHandler::OnAfterCreated(browser);
 | 
						|
 | 
						|
    if (mode_ == ABORT_AFTER_CREATED) {
 | 
						|
      SetSignalTestCompletionCount(1U);
 | 
						|
      CloseBrowser(browser, false);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
 | 
						|
    EXPECT_UI_THREAD();
 | 
						|
    TestHandler::OnBeforeClose(browser);
 | 
						|
 | 
						|
    if (IsAborted()) {
 | 
						|
      DestroyTest();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
 | 
						|
                      CefRefPtr<CefFrame> frame,
 | 
						|
                      CefRefPtr<CefRequest> request,
 | 
						|
                      bool user_gesture,
 | 
						|
                      bool is_redirect) override {
 | 
						|
    EXPECT_UI_THREAD();
 | 
						|
    if (browser_id_ == 0) {
 | 
						|
      // This is the first callback that provides a browser ID.
 | 
						|
      browser_id_ = browser->GetIdentifier();
 | 
						|
      EXPECT_GT(browser_id_, 0);
 | 
						|
    } else {
 | 
						|
      EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
    }
 | 
						|
    EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
    if (IsChromeRuntimeEnabled()) {
 | 
						|
      // With the Chrome runtime this is true on initial navigation via
 | 
						|
      // chrome::AddTabAt() and also true for clicked links.
 | 
						|
      EXPECT_TRUE(user_gesture);
 | 
						|
    } else {
 | 
						|
      EXPECT_FALSE(user_gesture);
 | 
						|
    }
 | 
						|
    if (on_before_browse_ct_ == 0 || mode_ == RESTART_RESOURCE_RESPONSE) {
 | 
						|
      EXPECT_FALSE(is_redirect) << on_before_browse_ct_;
 | 
						|
    } else {
 | 
						|
      EXPECT_TRUE(is_redirect) << on_before_browse_ct_;
 | 
						|
    }
 | 
						|
 | 
						|
    on_before_browse_ct_++;
 | 
						|
 | 
						|
    VerifyState(kOnBeforeBrowse, request, nullptr);
 | 
						|
 | 
						|
    if (mode_ == ABORT_BEFORE_BROWSE) {
 | 
						|
      SetSignalTestCompletionCount(1U);
 | 
						|
      CloseBrowser(browser, false);
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request,
 | 
						|
      bool is_navigation,
 | 
						|
      bool is_download,
 | 
						|
      const CefString& request_initiator,
 | 
						|
      bool& disable_default_handling) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
    EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
    if (request_id_ == 0U) {
 | 
						|
      // This is the first callback that provides a request ID.
 | 
						|
      request_id_ = request->GetIdentifier();
 | 
						|
      EXPECT_GT(request_id_, 0U);
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyState(kGetResourceRequestHandler, request, nullptr);
 | 
						|
 | 
						|
    EXPECT_TRUE(is_navigation);
 | 
						|
    EXPECT_FALSE(is_download);
 | 
						|
    EXPECT_STREQ("null", request_initiator.ToString().c_str());
 | 
						|
 | 
						|
    // Check expected default value.
 | 
						|
    if (custom_scheme_) {
 | 
						|
      // There is no default handling for custom schemes.
 | 
						|
      EXPECT_TRUE(disable_default_handling);
 | 
						|
    } else {
 | 
						|
      EXPECT_FALSE(disable_default_handling);
 | 
						|
      // If |unhandled_| is true then we don't want default handling of requests
 | 
						|
      // (e.g. attempts to resolve over the network).
 | 
						|
      disable_default_handling = unhandled_;
 | 
						|
    }
 | 
						|
 | 
						|
    get_resource_request_handler_ct_++;
 | 
						|
 | 
						|
    return this;
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
    EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
    VerifyState(kGetCookieAccessFilter, request, nullptr);
 | 
						|
 | 
						|
    get_cookie_access_filter_ct_++;
 | 
						|
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  cef_return_value_t OnBeforeResourceLoad(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request,
 | 
						|
      CefRefPtr<CefCallback> callback) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
 | 
						|
      // Ignore favicon requests.
 | 
						|
      return RV_CANCEL;
 | 
						|
    }
 | 
						|
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
    EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
    VerifyState(kOnBeforeResourceLoad, request, nullptr);
 | 
						|
 | 
						|
    on_before_resource_load_ct_++;
 | 
						|
 | 
						|
    if (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD) {
 | 
						|
      incomplete_callback_ = callback;
 | 
						|
 | 
						|
      // Close the browser asynchronously to complete the test.
 | 
						|
      CloseBrowserAsync();
 | 
						|
      return RV_CONTINUE_ASYNC;
 | 
						|
    }
 | 
						|
 | 
						|
    if (mode_ == MODIFY_BEFORE_RESOURCE_LOAD) {
 | 
						|
      // Expect this data in the request for future callbacks.
 | 
						|
      SetCustomHeader(request);
 | 
						|
    } else if (mode_ == REDIRECT_BEFORE_RESOURCE_LOAD) {
 | 
						|
      // Redirect to this URL.
 | 
						|
      request->SetURL(GetURL(RESULT_HTML));
 | 
						|
    }
 | 
						|
 | 
						|
    // Other continuation modes are tested by
 | 
						|
    // ResourceRequestHandlerTest.BeforeResourceLoad*.
 | 
						|
    return RV_CONTINUE;
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceHandler> GetResourceHandler(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
    EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
    VerifyState(kGetResourceHandler, request, nullptr);
 | 
						|
 | 
						|
    get_resource_handler_ct_++;
 | 
						|
 | 
						|
    if (IsIncompleteRequestHandler()) {
 | 
						|
      // Close the browser asynchronously to complete the test.
 | 
						|
      CloseBrowserAsync();
 | 
						|
      return GetIncompleteResource();
 | 
						|
    }
 | 
						|
 | 
						|
    const std::string& url = request->GetURL();
 | 
						|
    if (url == GetURL(RESULT_HTML) && mode_ == RESTART_RESOURCE_RESPONSE) {
 | 
						|
      if (get_resource_handler_ct_ == 1) {
 | 
						|
        // First request that will be restarted after response.
 | 
						|
        return GetOKResource();
 | 
						|
      } else {
 | 
						|
        // Restarted request.
 | 
						|
        if (unhandled_) {
 | 
						|
          return nullptr;
 | 
						|
        }
 | 
						|
        return GetOKResource();
 | 
						|
      }
 | 
						|
    } else if (url == GetURL(RESULT_HTML)) {
 | 
						|
      if (unhandled_) {
 | 
						|
        return nullptr;
 | 
						|
      }
 | 
						|
      return GetOKResource();
 | 
						|
    } else if (url == GetURL(REDIRECT_HTML) &&
 | 
						|
               mode_ == REDIRECT_RESOURCE_RESPONSE) {
 | 
						|
      if (get_resource_handler_ct_ == 1) {
 | 
						|
        // First request that will be redirected after response.
 | 
						|
        return GetOKResource();
 | 
						|
      } else {
 | 
						|
        // Redirected request.
 | 
						|
        if (unhandled_) {
 | 
						|
          return nullptr;
 | 
						|
        }
 | 
						|
        return GetOKResource();
 | 
						|
      }
 | 
						|
    } else if (url == GetURL(REDIRECT_HTML) || url == GetURL(REDIRECT2_HTML)) {
 | 
						|
      std::string redirect_url;
 | 
						|
      if (mode_ == REDIRECT_REQUEST_HANDLER ||
 | 
						|
          mode_ == REDIRECT_RESOURCE_RESPONSE) {
 | 
						|
        EXPECT_STREQ(GetURL(REDIRECT_HTML), url.c_str());
 | 
						|
        redirect_url = GetURL(RESULT_HTML);
 | 
						|
      } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
 | 
						|
        EXPECT_STREQ(GetURL(REDIRECT2_HTML), url.c_str());
 | 
						|
        redirect_url = GetURL(REDIRECT_HTML);
 | 
						|
      } else {
 | 
						|
        NOTREACHED();
 | 
						|
      }
 | 
						|
 | 
						|
      return GetRedirectResource(redirect_url);
 | 
						|
    } else {
 | 
						|
      NOTREACHED();
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
 | 
						|
                          CefRefPtr<CefFrame> frame,
 | 
						|
                          CefRefPtr<CefRequest> request,
 | 
						|
                          CefRefPtr<CefResponse> response,
 | 
						|
                          CefString& new_url) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
    EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
    VerifyState(kOnResourceRedirect, request, response);
 | 
						|
 | 
						|
    if (mode_ == REDIRECT_REQUEST_HANDLER ||
 | 
						|
        mode_ == REDIRECT_RESOURCE_RESPONSE) {
 | 
						|
      // The URL redirected to from GetResourceHandler or OnResourceResponse.
 | 
						|
      EXPECT_STREQ(GetURL(RESULT_HTML), new_url.ToString().c_str());
 | 
						|
    } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
 | 
						|
      if (on_resource_redirect_ct_ == 0) {
 | 
						|
        // The URL redirected to from GetResourceHandler.
 | 
						|
        EXPECT_STREQ(GetURL(REDIRECT_HTML), new_url.ToString().c_str());
 | 
						|
        // Redirect again.
 | 
						|
        new_url = GetURL(RESULT_HTML);
 | 
						|
      } else {
 | 
						|
        NOTREACHED();
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    on_resource_redirect_ct_++;
 | 
						|
  }
 | 
						|
 | 
						|
  bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
 | 
						|
                          CefRefPtr<CefFrame> frame,
 | 
						|
                          CefRefPtr<CefRequest> request,
 | 
						|
                          CefRefPtr<CefResponse> response) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
    EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
    VerifyState(kOnResourceResponse, request, response);
 | 
						|
 | 
						|
    on_resource_response_ct_++;
 | 
						|
 | 
						|
    if (on_resource_response_ct_ == 1) {
 | 
						|
      if (mode_ == REDIRECT_RESOURCE_RESPONSE) {
 | 
						|
        // Redirect the request to this URL.
 | 
						|
        request->SetURL(GetURL(RESULT_HTML));
 | 
						|
        return true;
 | 
						|
      } else if (mode_ == RESTART_RESOURCE_RESPONSE) {
 | 
						|
        // Restart the request loading this data.
 | 
						|
        SetCustomHeader(request);
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request,
 | 
						|
      CefRefPtr<CefResponse> response) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
    EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
    VerifyState(kGetResourceResponseFilter, request, response);
 | 
						|
 | 
						|
    get_resource_response_filter_ct_++;
 | 
						|
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
 | 
						|
                              CefRefPtr<CefFrame> frame,
 | 
						|
                              CefRefPtr<CefRequest> request,
 | 
						|
                              CefRefPtr<CefResponse> response,
 | 
						|
                              URLRequestStatus status,
 | 
						|
                              int64_t received_content_length) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
 | 
						|
    if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
 | 
						|
      // Ignore favicon requests.
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
    EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
    VerifyState(kOnResourceLoadComplete, request, response);
 | 
						|
 | 
						|
    if (unhandled_ || IsIncomplete() || (IsAborted() && status == UR_FAILED)) {
 | 
						|
      EXPECT_EQ(UR_FAILED, status);
 | 
						|
      EXPECT_EQ(0, received_content_length);
 | 
						|
    } else {
 | 
						|
      EXPECT_EQ(UR_SUCCESS, status);
 | 
						|
      EXPECT_EQ(static_cast<int64_t>(GetResponseBody().length()),
 | 
						|
                received_content_length);
 | 
						|
    }
 | 
						|
 | 
						|
    on_resource_load_complete_ct_++;
 | 
						|
 | 
						|
    if (IsIncomplete()) {
 | 
						|
      MaybeDestroyTest(false);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
 | 
						|
                           CefRefPtr<CefFrame> frame,
 | 
						|
                           CefRefPtr<CefRequest> request,
 | 
						|
                           bool& allow_os_execution) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
    EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
    EXPECT_TRUE(custom_scheme_);
 | 
						|
    EXPECT_TRUE(unhandled_);
 | 
						|
 | 
						|
    // Check expected default value.
 | 
						|
    EXPECT_FALSE(allow_os_execution);
 | 
						|
 | 
						|
    VerifyState(kOnProtocolExecution, request, nullptr);
 | 
						|
    on_protocol_execution_ct_++;
 | 
						|
  }
 | 
						|
 | 
						|
  void OnLoadEnd(CefRefPtr<CefBrowser> browser,
 | 
						|
                 CefRefPtr<CefFrame> frame,
 | 
						|
                 int httpStatusCode) override {
 | 
						|
    EXPECT_UI_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
    EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
    if (unhandled_) {
 | 
						|
      if (IsRedirect()) {
 | 
						|
        EXPECT_EQ(httpStatusCode, 307);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(httpStatusCode, 0);
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      EXPECT_EQ(httpStatusCode, 200);
 | 
						|
    }
 | 
						|
 | 
						|
    on_load_end_ct_++;
 | 
						|
 | 
						|
    TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
 | 
						|
    DestroyTest();
 | 
						|
  }
 | 
						|
 | 
						|
  void DestroyTest() override {
 | 
						|
    if (mode_ == RESTART_RESOURCE_RESPONSE) {
 | 
						|
      EXPECT_EQ(1, on_before_browse_ct_);
 | 
						|
      EXPECT_EQ(2, get_resource_request_handler_ct_);
 | 
						|
      EXPECT_EQ(2, get_cookie_access_filter_ct_);
 | 
						|
      EXPECT_EQ(2, on_before_resource_load_ct_);
 | 
						|
      EXPECT_EQ(2, get_resource_handler_ct_);
 | 
						|
      EXPECT_EQ(0, on_resource_redirect_ct_);
 | 
						|
      // Unhandled requests won't see a call to GetResourceResponseFilter or
 | 
						|
      // OnResourceResponse. In this case we're restarting from inside
 | 
						|
      // OnResourceResponse.
 | 
						|
      if (unhandled_) {
 | 
						|
        EXPECT_EQ(0, get_resource_response_filter_ct_);
 | 
						|
        EXPECT_EQ(1, on_resource_response_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(1, get_resource_response_filter_ct_);
 | 
						|
        EXPECT_EQ(2, on_resource_response_ct_);
 | 
						|
      }
 | 
						|
    } else if (IsLoad()) {
 | 
						|
      EXPECT_EQ(1, on_before_browse_ct_);
 | 
						|
      EXPECT_EQ(1, get_resource_request_handler_ct_);
 | 
						|
      EXPECT_EQ(1, get_cookie_access_filter_ct_);
 | 
						|
      EXPECT_EQ(1, on_before_resource_load_ct_);
 | 
						|
      EXPECT_EQ(1, get_resource_handler_ct_);
 | 
						|
      EXPECT_EQ(0, on_resource_redirect_ct_);
 | 
						|
 | 
						|
      // Unhandled requests won't see a call to GetResourceResponseFilter
 | 
						|
      // or OnResourceResponse.
 | 
						|
      if (unhandled_) {
 | 
						|
        EXPECT_EQ(0, get_resource_response_filter_ct_);
 | 
						|
        EXPECT_EQ(0, on_resource_response_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(1, get_resource_response_filter_ct_);
 | 
						|
        EXPECT_EQ(1, on_resource_response_ct_);
 | 
						|
      }
 | 
						|
    } else if (IsRedirect()) {
 | 
						|
      EXPECT_EQ(2, on_before_browse_ct_);
 | 
						|
      EXPECT_EQ(2, get_resource_request_handler_ct_);
 | 
						|
      EXPECT_EQ(2, get_cookie_access_filter_ct_);
 | 
						|
      EXPECT_EQ(2, on_before_resource_load_ct_);
 | 
						|
      if (mode_ == REDIRECT_BEFORE_RESOURCE_LOAD) {
 | 
						|
        EXPECT_EQ(1, get_resource_handler_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(2, get_resource_handler_ct_);
 | 
						|
      }
 | 
						|
      EXPECT_EQ(1, on_resource_redirect_ct_);
 | 
						|
 | 
						|
      // Unhandled requests won't see a call to GetResourceResponseFilter.
 | 
						|
      if (unhandled_) {
 | 
						|
        EXPECT_EQ(0, get_resource_response_filter_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(1, get_resource_response_filter_ct_);
 | 
						|
      }
 | 
						|
 | 
						|
      // Unhandled requests won't see a call to OnResourceResponse.
 | 
						|
      if (mode_ == REDIRECT_RESOURCE_RESPONSE) {
 | 
						|
        // In this case we're redirecting from inside OnResourceResponse.
 | 
						|
        if (unhandled_) {
 | 
						|
          EXPECT_EQ(1, on_resource_response_ct_);
 | 
						|
        } else {
 | 
						|
          EXPECT_EQ(2, on_resource_response_ct_);
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        if (unhandled_) {
 | 
						|
          EXPECT_EQ(0, on_resource_response_ct_);
 | 
						|
        } else {
 | 
						|
          EXPECT_EQ(1, on_resource_response_ct_);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else if (IsIncomplete()) {
 | 
						|
      EXPECT_EQ(1, on_before_browse_ct_);
 | 
						|
      EXPECT_EQ(1, get_resource_request_handler_ct_);
 | 
						|
      EXPECT_EQ(1, get_cookie_access_filter_ct_);
 | 
						|
      EXPECT_EQ(1, on_before_resource_load_ct_);
 | 
						|
 | 
						|
      if (IsIncompleteRequestHandler()) {
 | 
						|
        EXPECT_EQ(1, get_resource_handler_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(0, get_resource_handler_ct_);
 | 
						|
      }
 | 
						|
 | 
						|
      EXPECT_EQ(0, on_resource_redirect_ct_);
 | 
						|
 | 
						|
      if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ) {
 | 
						|
        EXPECT_EQ(1, get_resource_response_filter_ct_);
 | 
						|
        EXPECT_EQ(1, on_resource_response_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(0, get_resource_response_filter_ct_);
 | 
						|
        EXPECT_EQ(0, on_resource_response_ct_);
 | 
						|
      }
 | 
						|
    } else if (IsAborted()) {
 | 
						|
      EXPECT_EQ(1, on_before_browse_ct_);
 | 
						|
      // The callbacks executed may vary based on timing.
 | 
						|
      EXPECT_NEAR(0, get_resource_request_handler_ct_, 1);
 | 
						|
      EXPECT_NEAR(0, get_cookie_access_filter_ct_, 1);
 | 
						|
      EXPECT_NEAR(0, on_before_resource_load_ct_, 1);
 | 
						|
      EXPECT_NEAR(0, get_resource_handler_ct_, 1);
 | 
						|
      EXPECT_NEAR(0, get_resource_response_filter_ct_, 1);
 | 
						|
      EXPECT_NEAR(0, on_resource_response_ct_, 1);
 | 
						|
      EXPECT_EQ(0, on_resource_redirect_ct_);
 | 
						|
    } else {
 | 
						|
      NOTREACHED();
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsAborted()) {
 | 
						|
      // The callbacks executed may vary based on timing.
 | 
						|
      EXPECT_NEAR(0, on_load_end_ct_, 1);
 | 
						|
      EXPECT_NEAR(resource_handler_created_ct_, resource_handler_destroyed_ct_,
 | 
						|
                  1);
 | 
						|
      EXPECT_NEAR(0, on_resource_load_complete_ct_, 1);
 | 
						|
    } else {
 | 
						|
      EXPECT_EQ(resource_handler_created_ct_, resource_handler_destroyed_ct_);
 | 
						|
      EXPECT_EQ(1, on_resource_load_complete_ct_);
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsIncomplete()) {
 | 
						|
      EXPECT_EQ(0, on_load_end_ct_);
 | 
						|
    } else if (!IsAborted()) {
 | 
						|
      EXPECT_EQ(1, on_load_end_ct_);
 | 
						|
    }
 | 
						|
 | 
						|
    if (custom_scheme_ && unhandled_ && !(IsIncomplete() || IsAborted())) {
 | 
						|
      EXPECT_EQ(1, on_protocol_execution_ct_);
 | 
						|
    } else if (IsAborted()) {
 | 
						|
      // The callbacks executed may vary based on timing.
 | 
						|
      EXPECT_NEAR(0, on_protocol_execution_ct_, 1);
 | 
						|
    } else {
 | 
						|
      EXPECT_EQ(0, on_protocol_execution_ct_);
 | 
						|
    }
 | 
						|
 | 
						|
    TestHandler::DestroyTest();
 | 
						|
 | 
						|
    if (!AllowTestCompletionWhenAllBrowsersClose()) {
 | 
						|
      // Complete asynchronously so the call stack has a chance to unwind.
 | 
						|
      CefPostTask(TID_UI, base::BindOnce(
 | 
						|
                              &BasicResponseTest::SignalTestCompletion, this));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  enum TestUrl {
 | 
						|
    RESULT_HTML,
 | 
						|
    REDIRECT_HTML,
 | 
						|
    REDIRECT2_HTML,
 | 
						|
  };
 | 
						|
 | 
						|
  const char* GetURL(TestUrl url) const {
 | 
						|
    if (custom_scheme_) {
 | 
						|
      if (url == RESULT_HTML) {
 | 
						|
        return "rrhcustom://test.com/result.html";
 | 
						|
      }
 | 
						|
      if (url == REDIRECT_HTML) {
 | 
						|
        return "rrhcustom://test.com/redirect.html";
 | 
						|
      }
 | 
						|
      if (url == REDIRECT2_HTML) {
 | 
						|
        return "rrhcustom://test.com/redirect2.html";
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      if (url == RESULT_HTML) {
 | 
						|
        return "https://test.com/result.html";
 | 
						|
      }
 | 
						|
      if (url == REDIRECT_HTML) {
 | 
						|
        return "https://test.com/redirect.html";
 | 
						|
      }
 | 
						|
      if (url == REDIRECT2_HTML) {
 | 
						|
        return "https://test.com/redirect2.html";
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    NOTREACHED();
 | 
						|
    return "";
 | 
						|
  }
 | 
						|
 | 
						|
  const char* GetStartupURL() const {
 | 
						|
    if (IsLoad() || IsIncomplete() || IsAborted()) {
 | 
						|
      return GetURL(RESULT_HTML);
 | 
						|
    } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
 | 
						|
      return GetURL(REDIRECT2_HTML);
 | 
						|
    } else if (IsRedirect()) {
 | 
						|
      return GetURL(REDIRECT_HTML);
 | 
						|
    }
 | 
						|
 | 
						|
    NOTREACHED();
 | 
						|
    return "";
 | 
						|
  }
 | 
						|
 | 
						|
  std::string GetResponseBody() const {
 | 
						|
    return "<html><body>Response</body></html>";
 | 
						|
  }
 | 
						|
  std::string GetRedirectBody() const {
 | 
						|
    return "<html><body>Redirect</body></html>";
 | 
						|
  }
 | 
						|
 | 
						|
  base::OnceClosure GetResourceDestroyCallback() {
 | 
						|
    resource_handler_created_ct_++;
 | 
						|
    return base::BindOnce(&BasicResponseTest::MaybeDestroyTest, this, true);
 | 
						|
  }
 | 
						|
 | 
						|
  bool GetCallbackResourceHandlerMode(CallbackResourceHandler::Mode& mode) {
 | 
						|
    switch (mode_) {
 | 
						|
      case IMMEDIATE_REQUEST_HANDLER_OPEN:
 | 
						|
        mode = CallbackResourceHandler::IMMEDIATE_OPEN;
 | 
						|
        return true;
 | 
						|
      case IMMEDIATE_REQUEST_HANDLER_READ:
 | 
						|
        mode = CallbackResourceHandler::IMMEDIATE_READ;
 | 
						|
        return true;
 | 
						|
      case IMMEDIATE_REQUEST_HANDLER_ALL:
 | 
						|
        mode = CallbackResourceHandler::IMMEDIATE_ALL;
 | 
						|
        return true;
 | 
						|
      case DELAYED_REQUEST_HANDLER_OPEN:
 | 
						|
        mode = CallbackResourceHandler::DELAYED_OPEN;
 | 
						|
        return true;
 | 
						|
      case DELAYED_REQUEST_HANDLER_READ:
 | 
						|
        mode = CallbackResourceHandler::DELAYED_READ;
 | 
						|
        return true;
 | 
						|
      case DELAYED_REQUEST_HANDLER_ALL:
 | 
						|
        mode = CallbackResourceHandler::DELAYED_ALL;
 | 
						|
        return true;
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceHandler> GetResource(int status_code,
 | 
						|
                                            const CefString& status_text,
 | 
						|
                                            const CefString& mime_type,
 | 
						|
                                            CefResponse::HeaderMap header_map,
 | 
						|
                                            const std::string& body) {
 | 
						|
    CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
 | 
						|
        const_cast<char*>(body.c_str()), body.size());
 | 
						|
 | 
						|
    CallbackResourceHandler::Mode handler_mode;
 | 
						|
    if (GetCallbackResourceHandlerMode(handler_mode)) {
 | 
						|
      return new CallbackResourceHandler(handler_mode, status_code, status_text,
 | 
						|
                                         mime_type, header_map, stream,
 | 
						|
                                         GetResourceDestroyCallback());
 | 
						|
    }
 | 
						|
 | 
						|
    return new NormalResourceHandler(status_code, status_text, mime_type,
 | 
						|
                                     header_map, stream,
 | 
						|
                                     GetResourceDestroyCallback());
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceHandler> GetOKResource() {
 | 
						|
    return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(),
 | 
						|
                       GetResponseBody());
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceHandler> GetRedirectResource(
 | 
						|
      const std::string& redirect_url) {
 | 
						|
    CefResponse::HeaderMap headerMap;
 | 
						|
    headerMap.insert(std::make_pair("Location", redirect_url));
 | 
						|
 | 
						|
    return GetResource(307, "Temporary Redirect", "text/html", headerMap,
 | 
						|
                       GetRedirectBody());
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceHandler> GetIncompleteResource() {
 | 
						|
    if (TestOldResourceAPI()) {
 | 
						|
      return new IncompleteResourceHandlerOld(
 | 
						|
          mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN
 | 
						|
              ? IncompleteResourceHandlerOld::BLOCK_PROCESS_REQUEST
 | 
						|
              : IncompleteResourceHandlerOld::BLOCK_READ_RESPONSE,
 | 
						|
          "text/html", GetResourceDestroyCallback());
 | 
						|
    }
 | 
						|
 | 
						|
    return new IncompleteResourceHandler(
 | 
						|
        mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN
 | 
						|
            ? IncompleteResourceHandler::BLOCK_OPEN
 | 
						|
            : IncompleteResourceHandler::BLOCK_READ,
 | 
						|
        "text/html", GetResourceDestroyCallback());
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsLoad() const {
 | 
						|
    return mode_ == LOAD || mode_ == MODIFY_BEFORE_RESOURCE_LOAD ||
 | 
						|
           mode_ == RESTART_RESOURCE_RESPONSE ||
 | 
						|
           mode_ == IMMEDIATE_REQUEST_HANDLER_OPEN ||
 | 
						|
           mode_ == IMMEDIATE_REQUEST_HANDLER_READ ||
 | 
						|
           mode_ == IMMEDIATE_REQUEST_HANDLER_ALL ||
 | 
						|
           mode_ == DELAYED_REQUEST_HANDLER_OPEN ||
 | 
						|
           mode_ == DELAYED_REQUEST_HANDLER_READ ||
 | 
						|
           mode_ == DELAYED_REQUEST_HANDLER_ALL;
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsIncompleteRequestHandler() const {
 | 
						|
    return mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN ||
 | 
						|
           mode_ == INCOMPLETE_REQUEST_HANDLER_READ;
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsIncomplete() const {
 | 
						|
    return mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD ||
 | 
						|
           IsIncompleteRequestHandler();
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsAborted() const {
 | 
						|
    return mode_ == ABORT_AFTER_CREATED || mode_ == ABORT_BEFORE_BROWSE;
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsRedirect() const {
 | 
						|
    return mode_ == REDIRECT_BEFORE_RESOURCE_LOAD ||
 | 
						|
           mode_ == REDIRECT_REQUEST_HANDLER ||
 | 
						|
           mode_ == REDIRECT_RESOURCE_REDIRECT ||
 | 
						|
           mode_ == REDIRECT_RESOURCE_RESPONSE;
 | 
						|
  }
 | 
						|
 | 
						|
  static void SetCustomHeader(CefRefPtr<CefRequest> request) {
 | 
						|
    EXPECT_FALSE(request->IsReadOnly());
 | 
						|
    request->SetHeaderByName("X-Custom-Header", "value", false);
 | 
						|
  }
 | 
						|
 | 
						|
  static std::string GetCustomHeader(CefRefPtr<CefRequest> request) {
 | 
						|
    return request->GetHeaderByName("X-Custom-Header");
 | 
						|
  }
 | 
						|
 | 
						|
  // Resource-related callbacks.
 | 
						|
  enum Callback {
 | 
						|
    kOnBeforeBrowse,
 | 
						|
    kGetResourceRequestHandler,
 | 
						|
    kGetCookieAccessFilter,
 | 
						|
    kOnBeforeResourceLoad,
 | 
						|
    kGetResourceHandler,
 | 
						|
    kOnResourceRedirect,
 | 
						|
    kOnResourceResponse,
 | 
						|
    kGetResourceResponseFilter,
 | 
						|
    kOnResourceLoadComplete,
 | 
						|
    kOnProtocolExecution,
 | 
						|
  };
 | 
						|
 | 
						|
  bool ShouldHaveResponse(Callback callback) const {
 | 
						|
    return callback >= kOnResourceRedirect &&
 | 
						|
           callback <= kOnResourceLoadComplete;
 | 
						|
  }
 | 
						|
 | 
						|
  bool ShouldHaveWritableRequest(Callback callback) const {
 | 
						|
    return callback == kOnBeforeResourceLoad || callback == kOnResourceResponse;
 | 
						|
  }
 | 
						|
 | 
						|
  void VerifyState(Callback callback,
 | 
						|
                   CefRefPtr<CefRequest> request,
 | 
						|
                   CefRefPtr<CefResponse> response) const {
 | 
						|
    EXPECT_TRUE(request) << callback;
 | 
						|
 | 
						|
    if (ShouldHaveResponse(callback)) {
 | 
						|
      EXPECT_TRUE(response) << callback;
 | 
						|
      EXPECT_TRUE(response->IsReadOnly()) << callback;
 | 
						|
    } else {
 | 
						|
      EXPECT_FALSE(response) << callback;
 | 
						|
    }
 | 
						|
 | 
						|
    if (ShouldHaveWritableRequest(callback)) {
 | 
						|
      EXPECT_FALSE(request->IsReadOnly()) << callback;
 | 
						|
    } else {
 | 
						|
      EXPECT_TRUE(request->IsReadOnly()) << callback;
 | 
						|
    }
 | 
						|
 | 
						|
    if (callback == kOnBeforeBrowse) {
 | 
						|
      // Browser-side navigation no longer exposes the actual request
 | 
						|
      // information.
 | 
						|
      EXPECT_EQ(0U, request->GetIdentifier()) << callback;
 | 
						|
    } else {
 | 
						|
      // All resource-related callbacks share the same request ID.
 | 
						|
      EXPECT_EQ(request_id_, request->GetIdentifier()) << callback;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsLoad() || IsIncomplete() || IsAborted()) {
 | 
						|
      EXPECT_STREQ("GET", request->GetMethod().ToString().c_str()) << callback;
 | 
						|
      EXPECT_STREQ(GetURL(RESULT_HTML), request->GetURL().ToString().c_str())
 | 
						|
          << callback;
 | 
						|
 | 
						|
      // Expect the header for all callbacks following the callback that
 | 
						|
      // initially sets it.
 | 
						|
      const std::string& custom_header = GetCustomHeader(request);
 | 
						|
      if ((mode_ == RESTART_RESOURCE_RESPONSE &&
 | 
						|
           on_resource_response_ct_ > 0) ||
 | 
						|
          (mode_ == MODIFY_BEFORE_RESOURCE_LOAD &&
 | 
						|
           on_before_resource_load_ct_ > 0)) {
 | 
						|
        EXPECT_STREQ("value", custom_header.c_str()) << callback;
 | 
						|
      } else {
 | 
						|
        EXPECT_STREQ("", custom_header.c_str()) << callback;
 | 
						|
      }
 | 
						|
 | 
						|
      if (response) {
 | 
						|
        VerifyOKResponse(callback, response);
 | 
						|
      }
 | 
						|
    } else if (IsRedirect()) {
 | 
						|
      EXPECT_STREQ("GET", request->GetMethod().ToString().c_str()) << callback;
 | 
						|
      if (on_before_browse_ct_ == 1) {
 | 
						|
        // Before the redirect.
 | 
						|
        EXPECT_STREQ(GetStartupURL(), request->GetURL().ToString().c_str())
 | 
						|
            << callback;
 | 
						|
      } else if (on_before_browse_ct_ == 2) {
 | 
						|
        // After the redirect.
 | 
						|
        EXPECT_STREQ(GetURL(RESULT_HTML), request->GetURL().ToString().c_str())
 | 
						|
            << callback;
 | 
						|
      } else {
 | 
						|
        NOTREACHED() << callback;
 | 
						|
      }
 | 
						|
 | 
						|
      if (response) {
 | 
						|
        if (callback == kOnResourceRedirect) {
 | 
						|
          // Before the redirect.
 | 
						|
          VerifyRedirectResponse(callback, response);
 | 
						|
        } else {
 | 
						|
          // After the redirect.
 | 
						|
          VerifyOKResponse(callback, response);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      NOTREACHED() << callback;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void VerifyOKResponse(Callback callback,
 | 
						|
                        CefRefPtr<CefResponse> response) const {
 | 
						|
    const auto error_code = response->GetError();
 | 
						|
 | 
						|
    // True for the first response in cases where we're redirecting/restarting
 | 
						|
    // from inside OnResourceResponse (e.g. the first response always succeeds).
 | 
						|
    const bool override_unhandled = unhandled_ &&
 | 
						|
                                    (mode_ == REDIRECT_RESOURCE_RESPONSE ||
 | 
						|
                                     mode_ == RESTART_RESOURCE_RESPONSE) &&
 | 
						|
                                    get_resource_handler_ct_ == 1;
 | 
						|
 | 
						|
    // True for tests where the request will be incomplete and never receive a
 | 
						|
    // response.
 | 
						|
    const bool incomplete_unhandled =
 | 
						|
        (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD ||
 | 
						|
         mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN ||
 | 
						|
         (IsAborted() && !custom_scheme_ && error_code != ERR_NONE));
 | 
						|
 | 
						|
    if ((unhandled_ && !override_unhandled) || incomplete_unhandled) {
 | 
						|
      EXPECT_TRUE(ERR_ABORTED == error_code ||
 | 
						|
                  ERR_UNKNOWN_URL_SCHEME == error_code)
 | 
						|
          << callback << error_code;
 | 
						|
      EXPECT_EQ(0, response->GetStatus()) << callback;
 | 
						|
      EXPECT_STREQ("", response->GetStatusText().ToString().c_str())
 | 
						|
          << callback;
 | 
						|
      EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
 | 
						|
      EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback;
 | 
						|
      EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
 | 
						|
    } else {
 | 
						|
      if ((mode_ == INCOMPLETE_REQUEST_HANDLER_READ || IsAborted()) &&
 | 
						|
          callback == kOnResourceLoadComplete &&
 | 
						|
          response->GetError() != ERR_NONE) {
 | 
						|
        // We got a response, but we also got aborted.
 | 
						|
        EXPECT_EQ(ERR_ABORTED, response->GetError()) << callback;
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(ERR_NONE, response->GetError()) << callback;
 | 
						|
      }
 | 
						|
      EXPECT_EQ(200, response->GetStatus()) << callback;
 | 
						|
      EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str())
 | 
						|
          << callback;
 | 
						|
      EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
 | 
						|
      EXPECT_STREQ("text/html", response->GetMimeType().ToString().c_str())
 | 
						|
          << callback;
 | 
						|
      EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void VerifyRedirectResponse(Callback callback,
 | 
						|
                              CefRefPtr<CefResponse> response) const {
 | 
						|
    EXPECT_EQ(ERR_NONE, response->GetError()) << callback;
 | 
						|
    EXPECT_EQ(307, response->GetStatus()) << callback;
 | 
						|
    const std::string& status_text = response->GetStatusText();
 | 
						|
    EXPECT_TRUE(status_text == "Internal Redirect" ||
 | 
						|
                status_text == "Temporary Redirect")
 | 
						|
        << status_text << callback;
 | 
						|
    EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
 | 
						|
    EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback;
 | 
						|
    EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
 | 
						|
  }
 | 
						|
 | 
						|
  void CloseBrowserAsync() {
 | 
						|
    EXPECT_TRUE(IsIncomplete());
 | 
						|
    SetSignalTestCompletionCount(1U);
 | 
						|
    CefPostDelayedTask(
 | 
						|
        TID_UI, base::BindOnce(&TestHandler::CloseBrowser, GetBrowser(), false),
 | 
						|
        100);
 | 
						|
  }
 | 
						|
 | 
						|
  void MaybeDestroyTest(bool from_handler) {
 | 
						|
    if (!CefCurrentlyOn(TID_UI)) {
 | 
						|
      CefPostTask(TID_UI, base::BindOnce(&BasicResponseTest::MaybeDestroyTest,
 | 
						|
                                         this, from_handler));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (from_handler) {
 | 
						|
      resource_handler_destroyed_ct_++;
 | 
						|
    }
 | 
						|
 | 
						|
    bool destroy_test = false;
 | 
						|
    if (IsIncomplete()) {
 | 
						|
      // Destroy the test if we got OnResourceLoadComplete and either the
 | 
						|
      // resource handler will never complete or it was destroyed.
 | 
						|
      destroy_test =
 | 
						|
          on_resource_load_complete_ct_ > 0 &&
 | 
						|
          (!IsIncompleteRequestHandler() ||
 | 
						|
           resource_handler_destroyed_ct_ == resource_handler_created_ct_);
 | 
						|
    } else {
 | 
						|
      // Destroy the test if we got OnLoadEnd and the expected number of
 | 
						|
      // resource handlers were destroyed.
 | 
						|
      destroy_test = on_load_end_ct_ > 0 && resource_handler_destroyed_ct_ ==
 | 
						|
                                                resource_handler_created_ct_;
 | 
						|
    }
 | 
						|
 | 
						|
    if (destroy_test) {
 | 
						|
      DestroyTest();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  const TestMode mode_;
 | 
						|
  const bool custom_scheme_;
 | 
						|
  const bool unhandled_;
 | 
						|
 | 
						|
  int browser_id_ = 0;
 | 
						|
  uint64_t request_id_ = 0U;
 | 
						|
 | 
						|
  int resource_handler_created_ct_ = 0;
 | 
						|
 | 
						|
  int on_before_browse_ct_ = 0;
 | 
						|
  int on_load_end_ct_ = 0;
 | 
						|
 | 
						|
  int get_resource_request_handler_ct_ = 0;
 | 
						|
  int on_before_resource_load_ct_ = 0;
 | 
						|
  int get_cookie_access_filter_ct_ = 0;
 | 
						|
  int get_resource_handler_ct_ = 0;
 | 
						|
  int on_resource_redirect_ct_ = 0;
 | 
						|
  int on_resource_response_ct_ = 0;
 | 
						|
  int get_resource_response_filter_ct_ = 0;
 | 
						|
  int on_resource_load_complete_ct_ = 0;
 | 
						|
  int on_protocol_execution_ct_ = 0;
 | 
						|
  int resource_handler_destroyed_ct_ = 0;
 | 
						|
 | 
						|
  // Used with INCOMPLETE_BEFORE_RESOURCE_LOAD.
 | 
						|
  CefRefPtr<CefCallback> incomplete_callback_;
 | 
						|
 | 
						|
  DISALLOW_COPY_AND_ASSIGN(BasicResponseTest);
 | 
						|
  IMPLEMENT_REFCOUNTING(BasicResponseTest);
 | 
						|
};
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
#define BASIC_TEST(name, test_mode, custom, unhandled)            \
 | 
						|
  TEST(ResourceRequestHandlerTest, Basic##name) {                 \
 | 
						|
    CefRefPtr<BasicResponseTest> handler = new BasicResponseTest( \
 | 
						|
        BasicResponseTest::test_mode, custom, unhandled);         \
 | 
						|
    handler->ExecuteTest();                                       \
 | 
						|
    ReleaseAndWaitForDestructor(handler);                         \
 | 
						|
  }
 | 
						|
 | 
						|
#define BASIC_TEST_ALL_MODES(name, custom, unhandled)                          \
 | 
						|
  BASIC_TEST(name##Load, LOAD, custom, unhandled)                              \
 | 
						|
  BASIC_TEST(name##AbortAfterCreated, ABORT_AFTER_CREATED, custom, unhandled)  \
 | 
						|
  BASIC_TEST(name##AbortBeforeBrowse, ABORT_BEFORE_BROWSE, custom, unhandled)  \
 | 
						|
  BASIC_TEST(name##ModifyBeforeResourceLoad, MODIFY_BEFORE_RESOURCE_LOAD,      \
 | 
						|
             custom, unhandled)                                                \
 | 
						|
  BASIC_TEST(name##RedirectBeforeResourceLoad, REDIRECT_BEFORE_RESOURCE_LOAD,  \
 | 
						|
             custom, unhandled)                                                \
 | 
						|
  BASIC_TEST(name##RedirectRequestHandler, REDIRECT_REQUEST_HANDLER, custom,   \
 | 
						|
             unhandled)                                                        \
 | 
						|
  BASIC_TEST(name##RedirectResourceRedirect, REDIRECT_RESOURCE_REDIRECT,       \
 | 
						|
             custom, unhandled)                                                \
 | 
						|
  BASIC_TEST(name##RedirectResourceResponse, REDIRECT_RESOURCE_RESPONSE,       \
 | 
						|
             custom, unhandled)                                                \
 | 
						|
  BASIC_TEST(name##RestartResourceResponse, RESTART_RESOURCE_RESPONSE, custom, \
 | 
						|
             unhandled)
 | 
						|
 | 
						|
// Tests only supported in handled mode.
 | 
						|
#define BASIC_TEST_HANDLED_MODES(name, custom)                                \
 | 
						|
  BASIC_TEST(name##ImmediateRequestHandlerOpen,                               \
 | 
						|
             IMMEDIATE_REQUEST_HANDLER_OPEN, custom, false)                   \
 | 
						|
  BASIC_TEST(name##ImmediateRequestHandlerRead,                               \
 | 
						|
             IMMEDIATE_REQUEST_HANDLER_READ, custom, false)                   \
 | 
						|
  BASIC_TEST(name##ImmediateRequestHandlerAll, IMMEDIATE_REQUEST_HANDLER_ALL, \
 | 
						|
             custom, false)                                                   \
 | 
						|
  BASIC_TEST(name##DelayedRequestHandlerOpen, DELAYED_REQUEST_HANDLER_OPEN,   \
 | 
						|
             custom, false)                                                   \
 | 
						|
  BASIC_TEST(name##DelayedRequestHandlerRead, DELAYED_REQUEST_HANDLER_READ,   \
 | 
						|
             custom, false)                                                   \
 | 
						|
  BASIC_TEST(name##DelayedRequestHandlerAll, DELAYED_REQUEST_HANDLER_ALL,     \
 | 
						|
             custom, false)                                                   \
 | 
						|
  BASIC_TEST(name##IncompleteBeforeResourceLoad,                              \
 | 
						|
             INCOMPLETE_BEFORE_RESOURCE_LOAD, custom, false)                  \
 | 
						|
  BASIC_TEST(name##IncompleteRequestHandlerOpen,                              \
 | 
						|
             INCOMPLETE_REQUEST_HANDLER_OPEN, custom, false)                  \
 | 
						|
  BASIC_TEST(name##IncompleteRequestHandlerRead,                              \
 | 
						|
             INCOMPLETE_REQUEST_HANDLER_READ, custom, false)
 | 
						|
 | 
						|
BASIC_TEST_ALL_MODES(StandardHandled, false, false)
 | 
						|
BASIC_TEST_ALL_MODES(StandardUnhandled, false, true)
 | 
						|
BASIC_TEST_ALL_MODES(CustomHandled, true, false)
 | 
						|
BASIC_TEST_ALL_MODES(CustomUnhandled, true, true)
 | 
						|
 | 
						|
BASIC_TEST_HANDLED_MODES(StandardHandled, false)
 | 
						|
BASIC_TEST_HANDLED_MODES(CustomHandled, true)
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
const char kSubresourceProcessMsg[] = "SubresourceMsg";
 | 
						|
 | 
						|
class SubresourceResponseTest : public RoutingTestHandler {
 | 
						|
 public:
 | 
						|
  enum TestMode {
 | 
						|
    // Normal load, nothing fancy.
 | 
						|
    LOAD,
 | 
						|
 | 
						|
    // Don't continue from OnBeforeResourceLoad, then close the browser to
 | 
						|
    // verify destruction handling of in-progress requests.
 | 
						|
    INCOMPLETE_BEFORE_RESOURCE_LOAD,
 | 
						|
 | 
						|
    // Modify the request (add headers) in OnBeforeResourceLoad.
 | 
						|
    MODIFY_BEFORE_RESOURCE_LOAD,
 | 
						|
 | 
						|
    // Redirect the request (change the URL) in OnBeforeResourceLoad.
 | 
						|
    REDIRECT_BEFORE_RESOURCE_LOAD,
 | 
						|
 | 
						|
    // Return a CefResourceHandler from GetResourceHandler that continues
 | 
						|
    // immediately by using the callback object instead of the return value.
 | 
						|
    IMMEDIATE_REQUEST_HANDLER_OPEN,
 | 
						|
    IMMEDIATE_REQUEST_HANDLER_READ,
 | 
						|
    IMMEDIATE_REQUEST_HANDLER_ALL,
 | 
						|
 | 
						|
    // Return a CefResourceHandler from GetResourceHandler that continues with
 | 
						|
    // a delay by using the callback object.
 | 
						|
    DELAYED_REQUEST_HANDLER_OPEN,
 | 
						|
    DELAYED_REQUEST_HANDLER_READ,
 | 
						|
    DELAYED_REQUEST_HANDLER_ALL,
 | 
						|
 | 
						|
    // Return a CefResourceHandler from GetResourceHandler that never completes,
 | 
						|
    // then close the browser to verify destruction handling of in-progress
 | 
						|
    // requests.
 | 
						|
    INCOMPLETE_REQUEST_HANDLER_OPEN,
 | 
						|
    INCOMPLETE_REQUEST_HANDLER_READ,
 | 
						|
 | 
						|
    // Redirect the request using a CefResourceHandler returned from
 | 
						|
    // GetResourceHandler.
 | 
						|
    REDIRECT_REQUEST_HANDLER,
 | 
						|
 | 
						|
    // Redirect the request (change the URL) an additional time in
 | 
						|
    // OnResourceRedirect after using a CefResourceHandler returned from
 | 
						|
    // GetResourceHandler for the first redirect.
 | 
						|
    REDIRECT_RESOURCE_REDIRECT,
 | 
						|
 | 
						|
    // Redirect the request (change the URL) in OnResourceResponse.
 | 
						|
    REDIRECT_RESOURCE_RESPONSE,
 | 
						|
 | 
						|
    // Restart the request (add headers) in OnResourceResponse.
 | 
						|
    RESTART_RESOURCE_RESPONSE,
 | 
						|
  };
 | 
						|
 | 
						|
  // If |custom_scheme| is true all requests will use a custom scheme.
 | 
						|
  // If |unhandled| is true the final request (after any redirects) will be
 | 
						|
  // unhandled, meaning that default handling is disabled and GetResourceHandler
 | 
						|
  // returns null.
 | 
						|
  // If |subframe| is true the resource will be loaded in an iframe.
 | 
						|
  SubresourceResponseTest(TestMode mode,
 | 
						|
                          bool custom_scheme,
 | 
						|
                          bool unhandled,
 | 
						|
                          bool subframe)
 | 
						|
      : mode_(mode),
 | 
						|
        custom_scheme_(custom_scheme),
 | 
						|
        unhandled_(unhandled),
 | 
						|
        subframe_(subframe) {}
 | 
						|
 | 
						|
  void RunTest() override {
 | 
						|
    CreateBrowser(GetMainURL());
 | 
						|
    SetTestTimeout();
 | 
						|
  }
 | 
						|
 | 
						|
  bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
 | 
						|
                      CefRefPtr<CefFrame> frame,
 | 
						|
                      CefRefPtr<CefRequest> request,
 | 
						|
                      bool user_gesture,
 | 
						|
                      bool is_redirect) override {
 | 
						|
    EXPECT_UI_THREAD();
 | 
						|
    if (browser_id_ == 0) {
 | 
						|
      // This is the first callback that provides a browser ID.
 | 
						|
      browser_id_ = browser->GetIdentifier();
 | 
						|
      EXPECT_GT(browser_id_, 0);
 | 
						|
    } else {
 | 
						|
      EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
    }
 | 
						|
 | 
						|
    const std::string& url = request->GetURL();
 | 
						|
    if (IsMainURL(url)) {
 | 
						|
      EXPECT_TRUE(frame->IsMain());
 | 
						|
    } else if (IsSubURL(url)) {
 | 
						|
      EXPECT_FALSE(frame->IsMain());
 | 
						|
      EXPECT_TRUE(subframe_);
 | 
						|
    } else {
 | 
						|
      EXPECT_FALSE(true);  // Not reached.
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsChromeRuntimeEnabled() && IsMainURL(url)) {
 | 
						|
      // With the Chrome runtime this is true on initial navigation via
 | 
						|
      // chrome::AddTabAt() and also true for clicked links.
 | 
						|
      EXPECT_TRUE(user_gesture);
 | 
						|
    } else {
 | 
						|
      EXPECT_FALSE(user_gesture);
 | 
						|
    }
 | 
						|
 | 
						|
    EXPECT_FALSE(is_redirect);
 | 
						|
 | 
						|
    on_before_browse_ct_++;
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request,
 | 
						|
      bool is_navigation,
 | 
						|
      bool is_download,
 | 
						|
      const CefString& request_initiator,
 | 
						|
      bool& disable_default_handling) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
    const std::string& url = request->GetURL();
 | 
						|
    if (IgnoreURL(url)) {
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
    const bool is_main_url = IsMainURL(url);
 | 
						|
    const bool is_sub_url = IsSubURL(url);
 | 
						|
 | 
						|
    if (is_main_url) {
 | 
						|
      EXPECT_TRUE(frame->IsMain());
 | 
						|
    } else if (is_sub_url) {
 | 
						|
      EXPECT_FALSE(frame->IsMain());
 | 
						|
      EXPECT_TRUE(subframe_);
 | 
						|
    }
 | 
						|
 | 
						|
    if (is_main_url || is_sub_url) {
 | 
						|
      // Track the frame ID that we'll expect for resource callbacks.
 | 
						|
      // Do this here instead of OnBeforeBrowse because OnBeforeBrowse may
 | 
						|
      // return -4 (kInvalidFrameId) for the initial navigation.
 | 
						|
      if (frame_id_ == 0) {
 | 
						|
        if (subframe_) {
 | 
						|
          if (is_sub_url) {
 | 
						|
            frame_id_ = frame->GetIdentifier();
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          frame_id_ = frame->GetIdentifier();
 | 
						|
        }
 | 
						|
      }
 | 
						|
      return this;
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyFrame(kGetResourceRequestHandler, frame);
 | 
						|
 | 
						|
    if (request_id_ == 0U) {
 | 
						|
      // This is the first callback that provides a request ID.
 | 
						|
      request_id_ = request->GetIdentifier();
 | 
						|
      EXPECT_GT(request_id_, 0U);
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyState(kGetResourceRequestHandler, request, nullptr);
 | 
						|
 | 
						|
    EXPECT_FALSE(is_navigation);
 | 
						|
    EXPECT_FALSE(is_download);
 | 
						|
    EXPECT_STREQ(GetOrigin(), request_initiator.ToString().c_str());
 | 
						|
 | 
						|
    // Check expected default value.
 | 
						|
    if (custom_scheme_) {
 | 
						|
      // There is no default handling for custom schemes.
 | 
						|
      EXPECT_TRUE(disable_default_handling);
 | 
						|
    } else {
 | 
						|
      EXPECT_FALSE(disable_default_handling);
 | 
						|
      // If |unhandled_| is true then we don't want default handling of requests
 | 
						|
      // (e.g. attempts to resolve over the network).
 | 
						|
      disable_default_handling = unhandled_;
 | 
						|
    }
 | 
						|
 | 
						|
    get_resource_request_handler_ct_++;
 | 
						|
 | 
						|
    return this;
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
    const std::string& url = request->GetURL();
 | 
						|
    if (IgnoreURL(url)) {
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsMainURL(url)) {
 | 
						|
      EXPECT_TRUE(frame->IsMain());
 | 
						|
      return nullptr;
 | 
						|
    } else if (IsSubURL(url)) {
 | 
						|
      EXPECT_FALSE(frame->IsMain());
 | 
						|
      EXPECT_TRUE(subframe_);
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyFrame(kGetCookieAccessFilter, frame);
 | 
						|
 | 
						|
    VerifyState(kGetCookieAccessFilter, request, nullptr);
 | 
						|
 | 
						|
    get_cookie_access_filter_ct_++;
 | 
						|
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  cef_return_value_t OnBeforeResourceLoad(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request,
 | 
						|
      CefRefPtr<CefCallback> callback) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
 | 
						|
    if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
 | 
						|
      // Ignore favicon requests.
 | 
						|
      return RV_CANCEL;
 | 
						|
    }
 | 
						|
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
    if (IsMainURL(request->GetURL())) {
 | 
						|
      EXPECT_TRUE(frame->IsMain());
 | 
						|
      return RV_CONTINUE;
 | 
						|
    } else if (IsSubURL(request->GetURL())) {
 | 
						|
      EXPECT_FALSE(frame->IsMain());
 | 
						|
      EXPECT_TRUE(subframe_);
 | 
						|
      return RV_CONTINUE;
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyFrame(kOnBeforeResourceLoad, frame);
 | 
						|
 | 
						|
    VerifyState(kOnBeforeResourceLoad, request, nullptr);
 | 
						|
 | 
						|
    on_before_resource_load_ct_++;
 | 
						|
 | 
						|
    if (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD) {
 | 
						|
      incomplete_callback_ = callback;
 | 
						|
 | 
						|
      // Close the browser asynchronously to complete the test.
 | 
						|
      CloseBrowserAsync();
 | 
						|
      return RV_CONTINUE_ASYNC;
 | 
						|
    }
 | 
						|
 | 
						|
    if (mode_ == MODIFY_BEFORE_RESOURCE_LOAD) {
 | 
						|
      // Expect this data in the request for future callbacks.
 | 
						|
      SetCustomHeader(request);
 | 
						|
    } else if (mode_ == REDIRECT_BEFORE_RESOURCE_LOAD) {
 | 
						|
      // Redirect to this URL.
 | 
						|
      request->SetURL(GetURL(RESULT_JS));
 | 
						|
    }
 | 
						|
 | 
						|
    // Other continuation modes are tested by
 | 
						|
    // ResourceRequestHandlerTest.BeforeResourceLoad*.
 | 
						|
    return RV_CONTINUE;
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceHandler> GetResourceHandler(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
    if (IsMainURL(request->GetURL())) {
 | 
						|
      EXPECT_TRUE(frame->IsMain());
 | 
						|
      return GetMainResource();
 | 
						|
    } else if (IsSubURL(request->GetURL())) {
 | 
						|
      EXPECT_FALSE(frame->IsMain());
 | 
						|
      EXPECT_TRUE(subframe_);
 | 
						|
      return GetSubResource();
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyFrame(kGetResourceHandler, frame);
 | 
						|
 | 
						|
    VerifyState(kGetResourceHandler, request, nullptr);
 | 
						|
 | 
						|
    get_resource_handler_ct_++;
 | 
						|
 | 
						|
    if (IsIncompleteRequestHandler()) {
 | 
						|
      // Close the browser asynchronously to complete the test.
 | 
						|
      CloseBrowserAsync();
 | 
						|
      return GetIncompleteResource();
 | 
						|
    }
 | 
						|
 | 
						|
    const std::string& url = request->GetURL();
 | 
						|
    if (url == GetURL(RESULT_JS) && mode_ == RESTART_RESOURCE_RESPONSE) {
 | 
						|
      if (get_resource_handler_ct_ == 1) {
 | 
						|
        // First request that will be restarted after response.
 | 
						|
        return GetOKResource();
 | 
						|
      } else {
 | 
						|
        // Restarted request.
 | 
						|
        if (unhandled_) {
 | 
						|
          return nullptr;
 | 
						|
        }
 | 
						|
        return GetOKResource();
 | 
						|
      }
 | 
						|
    } else if (url == GetURL(RESULT_JS)) {
 | 
						|
      if (unhandled_) {
 | 
						|
        return nullptr;
 | 
						|
      }
 | 
						|
      return GetOKResource();
 | 
						|
    } else if (url == GetURL(REDIRECT_JS) &&
 | 
						|
               mode_ == REDIRECT_RESOURCE_RESPONSE) {
 | 
						|
      if (get_resource_handler_ct_ == 1) {
 | 
						|
        // First request that will be redirected after response.
 | 
						|
        return GetOKResource();
 | 
						|
      } else {
 | 
						|
        // Redirected request.
 | 
						|
        if (unhandled_) {
 | 
						|
          return nullptr;
 | 
						|
        }
 | 
						|
        return GetOKResource();
 | 
						|
      }
 | 
						|
    } else if (url == GetURL(REDIRECT_JS) || url == GetURL(REDIRECT2_JS)) {
 | 
						|
      std::string redirect_url;
 | 
						|
      if (mode_ == REDIRECT_REQUEST_HANDLER ||
 | 
						|
          mode_ == REDIRECT_RESOURCE_RESPONSE) {
 | 
						|
        EXPECT_STREQ(GetURL(REDIRECT_JS), url.c_str());
 | 
						|
        redirect_url = GetURL(RESULT_JS);
 | 
						|
      } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
 | 
						|
        EXPECT_STREQ(GetURL(REDIRECT2_JS), url.c_str());
 | 
						|
        redirect_url = GetURL(REDIRECT_JS);
 | 
						|
      } else {
 | 
						|
        NOTREACHED();
 | 
						|
      }
 | 
						|
 | 
						|
      return GetRedirectResource(redirect_url);
 | 
						|
    } else {
 | 
						|
      NOTREACHED();
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
 | 
						|
                          CefRefPtr<CefFrame> frame,
 | 
						|
                          CefRefPtr<CefRequest> request,
 | 
						|
                          CefRefPtr<CefResponse> response,
 | 
						|
                          CefString& new_url) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
    if (IsMainURL(request->GetURL()) || IsSubURL(request->GetURL())) {
 | 
						|
      EXPECT_FALSE(true);  // Not reached.
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyFrame(kOnResourceRedirect, frame);
 | 
						|
 | 
						|
    VerifyState(kOnResourceRedirect, request, response);
 | 
						|
 | 
						|
    if (mode_ == REDIRECT_REQUEST_HANDLER ||
 | 
						|
        mode_ == REDIRECT_RESOURCE_RESPONSE) {
 | 
						|
      // The URL redirected to from GetResourceHandler or OnResourceResponse.
 | 
						|
      EXPECT_STREQ(GetURL(RESULT_JS), new_url.ToString().c_str());
 | 
						|
    } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
 | 
						|
      if (on_resource_redirect_ct_ == 0) {
 | 
						|
        // The URL redirected to from GetResourceHandler.
 | 
						|
        EXPECT_STREQ(GetURL(REDIRECT_JS), new_url.ToString().c_str());
 | 
						|
        // Redirect again.
 | 
						|
        new_url = GetURL(RESULT_JS);
 | 
						|
      } else {
 | 
						|
        NOTREACHED();
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    on_resource_redirect_ct_++;
 | 
						|
  }
 | 
						|
 | 
						|
  bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
 | 
						|
                          CefRefPtr<CefFrame> frame,
 | 
						|
                          CefRefPtr<CefRequest> request,
 | 
						|
                          CefRefPtr<CefResponse> response) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
    if (IsMainURL(request->GetURL())) {
 | 
						|
      EXPECT_TRUE(frame->IsMain());
 | 
						|
      return false;
 | 
						|
    } else if (IsSubURL(request->GetURL())) {
 | 
						|
      EXPECT_FALSE(frame->IsMain());
 | 
						|
      EXPECT_TRUE(subframe_);
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyFrame(kOnResourceResponse, frame);
 | 
						|
 | 
						|
    VerifyState(kOnResourceResponse, request, response);
 | 
						|
 | 
						|
    on_resource_response_ct_++;
 | 
						|
 | 
						|
    if (on_resource_response_ct_ == 1) {
 | 
						|
      if (mode_ == REDIRECT_RESOURCE_RESPONSE) {
 | 
						|
        // Redirect the request to this URL.
 | 
						|
        request->SetURL(GetURL(RESULT_JS));
 | 
						|
        return true;
 | 
						|
      } else if (mode_ == RESTART_RESOURCE_RESPONSE) {
 | 
						|
        // Restart the request loading this data.
 | 
						|
        SetCustomHeader(request);
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request,
 | 
						|
      CefRefPtr<CefResponse> response) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
    if (IsMainURL(request->GetURL())) {
 | 
						|
      EXPECT_TRUE(frame->IsMain());
 | 
						|
      return nullptr;
 | 
						|
    } else if (IsSubURL(request->GetURL())) {
 | 
						|
      EXPECT_FALSE(frame->IsMain());
 | 
						|
      EXPECT_TRUE(subframe_);
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyFrame(kGetResourceResponseFilter, frame);
 | 
						|
 | 
						|
    VerifyState(kGetResourceResponseFilter, request, response);
 | 
						|
 | 
						|
    get_resource_response_filter_ct_++;
 | 
						|
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
 | 
						|
                              CefRefPtr<CefFrame> frame,
 | 
						|
                              CefRefPtr<CefRequest> request,
 | 
						|
                              CefRefPtr<CefResponse> response,
 | 
						|
                              URLRequestStatus status,
 | 
						|
                              int64_t received_content_length) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
 | 
						|
    if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
 | 
						|
      // Ignore favicon requests.
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
    if (IsMainURL(request->GetURL())) {
 | 
						|
      EXPECT_TRUE(frame->IsMain());
 | 
						|
      EXPECT_EQ(UR_SUCCESS, status);
 | 
						|
      EXPECT_EQ(static_cast<int64_t>(GetMainResponseBody().length()),
 | 
						|
                received_content_length);
 | 
						|
      return;
 | 
						|
    } else if (IsSubURL(request->GetURL())) {
 | 
						|
      EXPECT_FALSE(frame->IsMain());
 | 
						|
      EXPECT_EQ(UR_SUCCESS, status);
 | 
						|
      EXPECT_EQ(static_cast<int64_t>(GetSubResponseBody().length()),
 | 
						|
                received_content_length);
 | 
						|
      EXPECT_TRUE(subframe_);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyFrame(kOnResourceLoadComplete, frame);
 | 
						|
 | 
						|
    VerifyState(kOnResourceLoadComplete, request, response);
 | 
						|
 | 
						|
    if (unhandled_ || IsIncomplete()) {
 | 
						|
      EXPECT_EQ(UR_FAILED, status);
 | 
						|
      EXPECT_EQ(0, received_content_length);
 | 
						|
    } else {
 | 
						|
      EXPECT_EQ(UR_SUCCESS, status);
 | 
						|
      EXPECT_EQ(static_cast<int64_t>(GetResponseBody().length()),
 | 
						|
                received_content_length);
 | 
						|
    }
 | 
						|
 | 
						|
    on_resource_load_complete_ct_++;
 | 
						|
 | 
						|
    if (IsIncomplete()) {
 | 
						|
      MaybeDestroyTest(false);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
 | 
						|
                           CefRefPtr<CefFrame> frame,
 | 
						|
                           CefRefPtr<CefRequest> request,
 | 
						|
                           bool& allow_os_execution) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
    if (IsMainURL(request->GetURL()) || IsSubURL(request->GetURL())) {
 | 
						|
      EXPECT_FALSE(true);  // Not reached.
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyFrame(kOnProtocolExecution, frame);
 | 
						|
 | 
						|
    EXPECT_TRUE(custom_scheme_);
 | 
						|
    EXPECT_TRUE(unhandled_);
 | 
						|
 | 
						|
    // Check expected default value.
 | 
						|
    EXPECT_FALSE(allow_os_execution);
 | 
						|
 | 
						|
    VerifyState(kOnProtocolExecution, request, nullptr);
 | 
						|
    on_protocol_execution_ct_++;
 | 
						|
  }
 | 
						|
 | 
						|
  void OnLoadEnd(CefRefPtr<CefBrowser> browser,
 | 
						|
                 CefRefPtr<CefFrame> frame,
 | 
						|
                 int httpStatusCode) override {
 | 
						|
    EXPECT_UI_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
    EXPECT_EQ(httpStatusCode, 200);
 | 
						|
 | 
						|
    on_load_end_ct_++;
 | 
						|
 | 
						|
    TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
 | 
						|
    MaybeDestroyTest(false);
 | 
						|
  }
 | 
						|
 | 
						|
  bool OnQuery(CefRefPtr<CefBrowser> browser,
 | 
						|
               CefRefPtr<CefFrame> frame,
 | 
						|
               int64_t query_id,
 | 
						|
               const CefString& request,
 | 
						|
               bool persistent,
 | 
						|
               CefRefPtr<Callback> callback) override {
 | 
						|
    EXPECT_UI_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
    EXPECT_STREQ(kSubresourceProcessMsg, request.ToString().c_str());
 | 
						|
 | 
						|
    VerifyFrame(kOnQuery, frame);
 | 
						|
 | 
						|
    callback->Success("");
 | 
						|
 | 
						|
    on_query_ct_++;
 | 
						|
    MaybeDestroyTest(false);
 | 
						|
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  void DestroyTest() override {
 | 
						|
    // Only called for the main and/or sub frame load.
 | 
						|
    if (subframe_) {
 | 
						|
      EXPECT_EQ(2, on_before_browse_ct_);
 | 
						|
    } else {
 | 
						|
      EXPECT_EQ(1, on_before_browse_ct_);
 | 
						|
    }
 | 
						|
 | 
						|
    if (mode_ == RESTART_RESOURCE_RESPONSE) {
 | 
						|
      EXPECT_EQ(2, get_resource_request_handler_ct_);
 | 
						|
      EXPECT_EQ(2, get_cookie_access_filter_ct_);
 | 
						|
      EXPECT_EQ(2, on_before_resource_load_ct_);
 | 
						|
      EXPECT_EQ(2, get_resource_handler_ct_);
 | 
						|
      EXPECT_EQ(0, on_resource_redirect_ct_);
 | 
						|
      // Unhandled requests won't see a call to GetResourceResponseFilter or
 | 
						|
      // OnResourceResponse. In this case we're restarting from inside
 | 
						|
      // OnResourceResponse.
 | 
						|
      if (unhandled_) {
 | 
						|
        EXPECT_EQ(0, get_resource_response_filter_ct_);
 | 
						|
        EXPECT_EQ(1, on_resource_response_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(1, get_resource_response_filter_ct_);
 | 
						|
        EXPECT_EQ(2, on_resource_response_ct_);
 | 
						|
      }
 | 
						|
    } else if (IsLoad()) {
 | 
						|
      EXPECT_EQ(1, get_resource_request_handler_ct_);
 | 
						|
      EXPECT_EQ(1, get_cookie_access_filter_ct_);
 | 
						|
      EXPECT_EQ(1, on_before_resource_load_ct_);
 | 
						|
      EXPECT_EQ(1, get_resource_handler_ct_);
 | 
						|
      EXPECT_EQ(0, on_resource_redirect_ct_);
 | 
						|
      // Unhandled requests won't see a call to GetResourceResponseFilter or
 | 
						|
      // OnResourceResponse.
 | 
						|
      if (unhandled_) {
 | 
						|
        EXPECT_EQ(0, get_resource_response_filter_ct_);
 | 
						|
        EXPECT_EQ(0, on_resource_response_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(1, get_resource_response_filter_ct_);
 | 
						|
        EXPECT_EQ(1, on_resource_response_ct_);
 | 
						|
      }
 | 
						|
    } else if (IsRedirect()) {
 | 
						|
      EXPECT_EQ(2, get_resource_request_handler_ct_);
 | 
						|
      EXPECT_EQ(2, get_cookie_access_filter_ct_);
 | 
						|
      EXPECT_EQ(2, on_before_resource_load_ct_);
 | 
						|
      if (mode_ == REDIRECT_BEFORE_RESOURCE_LOAD) {
 | 
						|
        EXPECT_EQ(1, get_resource_handler_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(2, get_resource_handler_ct_);
 | 
						|
      }
 | 
						|
      EXPECT_EQ(1, on_resource_redirect_ct_);
 | 
						|
 | 
						|
      // Unhandled requests won't see a call to GetResourceResponseFilter.
 | 
						|
      if (unhandled_) {
 | 
						|
        EXPECT_EQ(0, get_resource_response_filter_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(1, get_resource_response_filter_ct_);
 | 
						|
      }
 | 
						|
 | 
						|
      // Unhandled requests won't see a call to OnResourceResponse.
 | 
						|
      if (mode_ == REDIRECT_RESOURCE_RESPONSE) {
 | 
						|
        // In this case we're redirecting from inside OnResourceResponse.
 | 
						|
        if (unhandled_) {
 | 
						|
          EXPECT_EQ(1, on_resource_response_ct_);
 | 
						|
        } else {
 | 
						|
          EXPECT_EQ(2, on_resource_response_ct_);
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        if (unhandled_) {
 | 
						|
          EXPECT_EQ(0, on_resource_response_ct_);
 | 
						|
        } else {
 | 
						|
          EXPECT_EQ(1, on_resource_response_ct_);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else if (IsIncomplete()) {
 | 
						|
      EXPECT_EQ(1, get_resource_request_handler_ct_);
 | 
						|
      EXPECT_EQ(1, get_cookie_access_filter_ct_);
 | 
						|
      EXPECT_EQ(1, on_before_resource_load_ct_);
 | 
						|
 | 
						|
      if (IsIncompleteRequestHandler()) {
 | 
						|
        EXPECT_EQ(1, get_resource_handler_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(0, get_resource_handler_ct_);
 | 
						|
      }
 | 
						|
 | 
						|
      EXPECT_EQ(0, on_resource_redirect_ct_);
 | 
						|
 | 
						|
      if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ) {
 | 
						|
        EXPECT_EQ(1, get_resource_response_filter_ct_);
 | 
						|
        EXPECT_EQ(1, on_resource_response_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(0, get_resource_response_filter_ct_);
 | 
						|
        EXPECT_EQ(0, on_resource_response_ct_);
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      NOTREACHED();
 | 
						|
    }
 | 
						|
 | 
						|
    EXPECT_EQ(resource_handler_created_ct_, resource_handler_destroyed_ct_);
 | 
						|
    EXPECT_EQ(1, on_resource_load_complete_ct_);
 | 
						|
 | 
						|
    // Only called for the main and/or sub frame load.
 | 
						|
    if (IsIncomplete()) {
 | 
						|
      EXPECT_EQ(0, on_load_end_ct_);
 | 
						|
    } else {
 | 
						|
      if (subframe_) {
 | 
						|
        EXPECT_EQ(2, on_load_end_ct_);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(1, on_load_end_ct_);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (unhandled_ || IsIncomplete()) {
 | 
						|
      EXPECT_EQ(0, on_query_ct_);
 | 
						|
    } else {
 | 
						|
      EXPECT_EQ(1, on_query_ct_);
 | 
						|
    }
 | 
						|
 | 
						|
    if (custom_scheme_ && unhandled_ && !IsIncomplete()) {
 | 
						|
      EXPECT_EQ(1, on_protocol_execution_ct_);
 | 
						|
    } else {
 | 
						|
      EXPECT_EQ(0, on_protocol_execution_ct_);
 | 
						|
    }
 | 
						|
 | 
						|
    TestHandler::DestroyTest();
 | 
						|
 | 
						|
    if (!AllowTestCompletionWhenAllBrowsersClose()) {
 | 
						|
      // Complete asynchronously so the call stack has a chance to unwind.
 | 
						|
      CefPostTask(
 | 
						|
          TID_UI,
 | 
						|
          base::BindOnce(&SubresourceResponseTest::SignalTestCompletion, this));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  const char* GetMainURL() const {
 | 
						|
    if (custom_scheme_) {
 | 
						|
      return "rrhcustom://test.com/main.html";
 | 
						|
    } else {
 | 
						|
      return "https://test.com/main.html";
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  const char* GetSubURL() const {
 | 
						|
    if (custom_scheme_) {
 | 
						|
      return "rrhcustom://test.com/subframe.html";
 | 
						|
    } else {
 | 
						|
      return "https://test.com/subframe.html";
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  const char* GetOrigin() const {
 | 
						|
    if (custom_scheme_) {
 | 
						|
      return "rrhcustom://test.com";
 | 
						|
    } else {
 | 
						|
      return "https://test.com";
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsMainURL(const std::string& url) const { return url == GetMainURL(); }
 | 
						|
  bool IsSubURL(const std::string& url) const { return url == GetSubURL(); }
 | 
						|
 | 
						|
  enum TestUrl {
 | 
						|
    RESULT_JS,
 | 
						|
    REDIRECT_JS,
 | 
						|
    REDIRECT2_JS,
 | 
						|
  };
 | 
						|
 | 
						|
  const char* GetURL(TestUrl url) const {
 | 
						|
    if (custom_scheme_) {
 | 
						|
      if (url == RESULT_JS) {
 | 
						|
        return "rrhcustom://test.com/result.js";
 | 
						|
      }
 | 
						|
      if (url == REDIRECT_JS) {
 | 
						|
        return "rrhcustom://test.com/redirect.js";
 | 
						|
      }
 | 
						|
      if (url == REDIRECT2_JS) {
 | 
						|
        return "rrhcustom://test.com/redirect2.js";
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      if (url == RESULT_JS) {
 | 
						|
        return "https://test.com/result.js";
 | 
						|
      }
 | 
						|
      if (url == REDIRECT_JS) {
 | 
						|
        return "https://test.com/redirect.js";
 | 
						|
      }
 | 
						|
      if (url == REDIRECT2_JS) {
 | 
						|
        return "https://test.com/redirect2.js";
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    NOTREACHED();
 | 
						|
    return "";
 | 
						|
  }
 | 
						|
 | 
						|
  const char* GetStartupURL() const {
 | 
						|
    if (IsLoad() || IsIncomplete()) {
 | 
						|
      return GetURL(RESULT_JS);
 | 
						|
    } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
 | 
						|
      return GetURL(REDIRECT2_JS);
 | 
						|
    } else if (IsRedirect()) {
 | 
						|
      return GetURL(REDIRECT_JS);
 | 
						|
    }
 | 
						|
 | 
						|
    NOTREACHED();
 | 
						|
    return "";
 | 
						|
  }
 | 
						|
 | 
						|
  std::string GetMainResponseBody() const {
 | 
						|
    std::stringstream html;
 | 
						|
    html << "<html><head>";
 | 
						|
 | 
						|
    if (subframe_) {
 | 
						|
      const std::string& url = GetSubURL();
 | 
						|
      html << "<iframe src=\"" << url << "\"></iframe>";
 | 
						|
    } else {
 | 
						|
      const std::string& url = GetStartupURL();
 | 
						|
      html << "<script type=\"text/javascript\" src=\"" << url
 | 
						|
           << "\"></script>";
 | 
						|
    }
 | 
						|
 | 
						|
    html << "</head><body><p>Main</p></body></html>";
 | 
						|
    return html.str();
 | 
						|
  }
 | 
						|
 | 
						|
  std::string GetSubResponseBody() const {
 | 
						|
    EXPECT_TRUE(subframe_);
 | 
						|
 | 
						|
    std::stringstream html;
 | 
						|
    html << "<html><head>";
 | 
						|
 | 
						|
    const std::string& url = GetStartupURL();
 | 
						|
    html << "<script type=\"text/javascript\" src=\"" << url << "\"></script>";
 | 
						|
 | 
						|
    html << "</head><body><p>Sub</p></body></html>";
 | 
						|
    return html.str();
 | 
						|
  }
 | 
						|
 | 
						|
  std::string GetResponseBody() const {
 | 
						|
    return "window.testQuery({request:'" + std::string(kSubresourceProcessMsg) +
 | 
						|
           "'});";
 | 
						|
  }
 | 
						|
  std::string GetRedirectBody() const {
 | 
						|
    return "<html><body>Redirect</body></html>";
 | 
						|
  }
 | 
						|
 | 
						|
  base::OnceClosure GetResourceDestroyCallback() {
 | 
						|
    resource_handler_created_ct_++;
 | 
						|
    return base::BindOnce(&SubresourceResponseTest::MaybeDestroyTest, this,
 | 
						|
                          true);
 | 
						|
  }
 | 
						|
 | 
						|
  bool GetCallbackResourceHandlerMode(CallbackResourceHandler::Mode& mode) {
 | 
						|
    switch (mode_) {
 | 
						|
      case IMMEDIATE_REQUEST_HANDLER_OPEN:
 | 
						|
        mode = CallbackResourceHandler::IMMEDIATE_OPEN;
 | 
						|
        return true;
 | 
						|
      case IMMEDIATE_REQUEST_HANDLER_READ:
 | 
						|
        mode = CallbackResourceHandler::IMMEDIATE_READ;
 | 
						|
        return true;
 | 
						|
      case IMMEDIATE_REQUEST_HANDLER_ALL:
 | 
						|
        mode = CallbackResourceHandler::IMMEDIATE_ALL;
 | 
						|
        return true;
 | 
						|
      case DELAYED_REQUEST_HANDLER_OPEN:
 | 
						|
        mode = CallbackResourceHandler::DELAYED_OPEN;
 | 
						|
        return true;
 | 
						|
      case DELAYED_REQUEST_HANDLER_READ:
 | 
						|
        mode = CallbackResourceHandler::DELAYED_READ;
 | 
						|
        return true;
 | 
						|
      case DELAYED_REQUEST_HANDLER_ALL:
 | 
						|
        mode = CallbackResourceHandler::DELAYED_ALL;
 | 
						|
        return true;
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceHandler> GetResource(int status_code,
 | 
						|
                                            const CefString& status_text,
 | 
						|
                                            const CefString& mime_type,
 | 
						|
                                            CefResponse::HeaderMap header_map,
 | 
						|
                                            const std::string& body) {
 | 
						|
    CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
 | 
						|
        const_cast<char*>(body.c_str()), body.size());
 | 
						|
 | 
						|
    CallbackResourceHandler::Mode handler_mode;
 | 
						|
    if (GetCallbackResourceHandlerMode(handler_mode)) {
 | 
						|
      return new CallbackResourceHandler(handler_mode, status_code, status_text,
 | 
						|
                                         mime_type, header_map, stream,
 | 
						|
                                         GetResourceDestroyCallback());
 | 
						|
    }
 | 
						|
 | 
						|
    return new NormalResourceHandler(status_code, status_text, mime_type,
 | 
						|
                                     header_map, stream,
 | 
						|
                                     GetResourceDestroyCallback());
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceHandler> GetMainResource() {
 | 
						|
    return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(),
 | 
						|
                       GetMainResponseBody());
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceHandler> GetSubResource() {
 | 
						|
    return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(),
 | 
						|
                       GetSubResponseBody());
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceHandler> GetOKResource() {
 | 
						|
    return GetResource(200, "OK", "text/javascript", CefResponse::HeaderMap(),
 | 
						|
                       GetResponseBody());
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceHandler> GetRedirectResource(
 | 
						|
      const std::string& redirect_url) {
 | 
						|
    CefResponse::HeaderMap headerMap;
 | 
						|
    headerMap.insert(std::make_pair("Location", redirect_url));
 | 
						|
 | 
						|
    return GetResource(307, "Temporary Redirect", "text/javascript", headerMap,
 | 
						|
                       GetRedirectBody());
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceHandler> GetIncompleteResource() {
 | 
						|
    if (TestOldResourceAPI()) {
 | 
						|
      return new IncompleteResourceHandlerOld(
 | 
						|
          mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN
 | 
						|
              ? IncompleteResourceHandlerOld::BLOCK_PROCESS_REQUEST
 | 
						|
              : IncompleteResourceHandlerOld::BLOCK_READ_RESPONSE,
 | 
						|
          "text/javascript", GetResourceDestroyCallback());
 | 
						|
    }
 | 
						|
 | 
						|
    return new IncompleteResourceHandler(
 | 
						|
        mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN
 | 
						|
            ? IncompleteResourceHandler::BLOCK_OPEN
 | 
						|
            : IncompleteResourceHandler::BLOCK_READ,
 | 
						|
        "text/javascript", GetResourceDestroyCallback());
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsLoad() const {
 | 
						|
    return mode_ == LOAD || mode_ == MODIFY_BEFORE_RESOURCE_LOAD ||
 | 
						|
           mode_ == RESTART_RESOURCE_RESPONSE ||
 | 
						|
           mode_ == IMMEDIATE_REQUEST_HANDLER_OPEN ||
 | 
						|
           mode_ == IMMEDIATE_REQUEST_HANDLER_READ ||
 | 
						|
           mode_ == IMMEDIATE_REQUEST_HANDLER_ALL ||
 | 
						|
           mode_ == DELAYED_REQUEST_HANDLER_OPEN ||
 | 
						|
           mode_ == DELAYED_REQUEST_HANDLER_READ ||
 | 
						|
           mode_ == DELAYED_REQUEST_HANDLER_ALL;
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsIncompleteRequestHandler() const {
 | 
						|
    return mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN ||
 | 
						|
           mode_ == INCOMPLETE_REQUEST_HANDLER_READ;
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsIncomplete() const {
 | 
						|
    return mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD ||
 | 
						|
           IsIncompleteRequestHandler();
 | 
						|
  }
 | 
						|
 | 
						|
  bool IsRedirect() const {
 | 
						|
    return mode_ == REDIRECT_BEFORE_RESOURCE_LOAD ||
 | 
						|
           mode_ == REDIRECT_REQUEST_HANDLER ||
 | 
						|
           mode_ == REDIRECT_RESOURCE_REDIRECT ||
 | 
						|
           mode_ == REDIRECT_RESOURCE_RESPONSE;
 | 
						|
  }
 | 
						|
 | 
						|
  static void SetCustomHeader(CefRefPtr<CefRequest> request) {
 | 
						|
    EXPECT_FALSE(request->IsReadOnly());
 | 
						|
    request->SetHeaderByName("X-Custom-Header", "value", false);
 | 
						|
  }
 | 
						|
 | 
						|
  static std::string GetCustomHeader(CefRefPtr<CefRequest> request) {
 | 
						|
    return request->GetHeaderByName("X-Custom-Header");
 | 
						|
  }
 | 
						|
 | 
						|
  // Resource-related callbacks.
 | 
						|
  enum Callback {
 | 
						|
    kGetResourceRequestHandler,
 | 
						|
    kGetCookieAccessFilter,
 | 
						|
    kOnBeforeResourceLoad,
 | 
						|
    kGetResourceHandler,
 | 
						|
    kOnResourceRedirect,
 | 
						|
    kOnResourceResponse,
 | 
						|
    kGetResourceResponseFilter,
 | 
						|
    kOnResourceLoadComplete,
 | 
						|
    kOnProtocolExecution,
 | 
						|
    kOnQuery,
 | 
						|
  };
 | 
						|
 | 
						|
  bool ShouldHaveResponse(Callback callback) const {
 | 
						|
    return callback >= kOnResourceRedirect &&
 | 
						|
           callback <= kOnResourceLoadComplete;
 | 
						|
  }
 | 
						|
 | 
						|
  bool ShouldHaveWritableRequest(Callback callback) const {
 | 
						|
    return callback == kOnBeforeResourceLoad || callback == kOnResourceResponse;
 | 
						|
  }
 | 
						|
 | 
						|
  void VerifyFrame(Callback callback, CefRefPtr<CefFrame> frame) const {
 | 
						|
    EXPECT_TRUE(frame);
 | 
						|
 | 
						|
    if (subframe_) {
 | 
						|
      EXPECT_FALSE(frame->IsMain()) << callback;
 | 
						|
    } else {
 | 
						|
      EXPECT_TRUE(frame->IsMain()) << callback;
 | 
						|
    }
 | 
						|
 | 
						|
    EXPECT_EQ(frame_id_, frame->GetIdentifier()) << callback;
 | 
						|
  }
 | 
						|
 | 
						|
  void VerifyState(Callback callback,
 | 
						|
                   CefRefPtr<CefRequest> request,
 | 
						|
                   CefRefPtr<CefResponse> response) const {
 | 
						|
    EXPECT_TRUE(request) << callback;
 | 
						|
 | 
						|
    if (ShouldHaveResponse(callback)) {
 | 
						|
      EXPECT_TRUE(response) << callback;
 | 
						|
      EXPECT_TRUE(response->IsReadOnly()) << callback;
 | 
						|
    } else {
 | 
						|
      EXPECT_FALSE(response) << callback;
 | 
						|
    }
 | 
						|
 | 
						|
    if (ShouldHaveWritableRequest(callback)) {
 | 
						|
      EXPECT_FALSE(request->IsReadOnly()) << callback;
 | 
						|
    } else {
 | 
						|
      EXPECT_TRUE(request->IsReadOnly()) << callback;
 | 
						|
    }
 | 
						|
 | 
						|
    // All resource-related callbacks share the same request ID.
 | 
						|
    EXPECT_EQ(request_id_, request->GetIdentifier()) << callback;
 | 
						|
 | 
						|
    if (IsLoad() || IsIncomplete()) {
 | 
						|
      EXPECT_STREQ("GET", request->GetMethod().ToString().c_str()) << callback;
 | 
						|
      EXPECT_STREQ(GetURL(RESULT_JS), request->GetURL().ToString().c_str())
 | 
						|
          << callback;
 | 
						|
 | 
						|
      // Expect the header for all callbacks following the callback that
 | 
						|
      // initially sets it.
 | 
						|
      const std::string& custom_header = GetCustomHeader(request);
 | 
						|
      if ((mode_ == RESTART_RESOURCE_RESPONSE &&
 | 
						|
           on_resource_response_ct_ > 0) ||
 | 
						|
          (mode_ == MODIFY_BEFORE_RESOURCE_LOAD &&
 | 
						|
           on_before_resource_load_ct_ > 0)) {
 | 
						|
        EXPECT_STREQ("value", custom_header.c_str()) << callback;
 | 
						|
      } else {
 | 
						|
        EXPECT_STREQ("", custom_header.c_str()) << callback;
 | 
						|
      }
 | 
						|
 | 
						|
      if (response) {
 | 
						|
        VerifyOKResponse(callback, response);
 | 
						|
      }
 | 
						|
    } else if (IsRedirect()) {
 | 
						|
      EXPECT_STREQ("GET", request->GetMethod().ToString().c_str()) << callback;
 | 
						|
      // Subresource loads don't get OnBeforeBrowse calls, so this check is a
 | 
						|
      // bit less exact then with main resource loads.
 | 
						|
      if (on_resource_redirect_ct_ == 0) {
 | 
						|
        // Before the redirect.
 | 
						|
        EXPECT_STREQ(GetStartupURL(), request->GetURL().ToString().c_str())
 | 
						|
            << callback;
 | 
						|
      } else {
 | 
						|
        // After the redirect.
 | 
						|
        EXPECT_STREQ(GetURL(RESULT_JS), request->GetURL().ToString().c_str())
 | 
						|
            << callback;
 | 
						|
      }
 | 
						|
 | 
						|
      if (response) {
 | 
						|
        if (callback == kOnResourceRedirect) {
 | 
						|
          // Before the redirect.
 | 
						|
          VerifyRedirectResponse(callback, response);
 | 
						|
        } else {
 | 
						|
          // After the redirect.
 | 
						|
          VerifyOKResponse(callback, response);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      NOTREACHED() << callback;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void VerifyOKResponse(Callback callback,
 | 
						|
                        CefRefPtr<CefResponse> response) const {
 | 
						|
    // True for the first response in cases where we're redirecting/restarting
 | 
						|
    // from inside OnResourceResponse (e.g. the first response always succeeds).
 | 
						|
    const bool override_unhandled = unhandled_ &&
 | 
						|
                                    (mode_ == REDIRECT_RESOURCE_RESPONSE ||
 | 
						|
                                     mode_ == RESTART_RESOURCE_RESPONSE) &&
 | 
						|
                                    get_resource_handler_ct_ == 1;
 | 
						|
 | 
						|
    // True for tests where the request will be incomplete and never receive a
 | 
						|
    // response.
 | 
						|
    const bool incomplete_unhandled =
 | 
						|
        (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD ||
 | 
						|
         mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN);
 | 
						|
 | 
						|
    if ((unhandled_ && !override_unhandled) || incomplete_unhandled) {
 | 
						|
      if (incomplete_unhandled) {
 | 
						|
        EXPECT_EQ(ERR_ABORTED, response->GetError()) << callback;
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(ERR_UNKNOWN_URL_SCHEME, response->GetError()) << callback;
 | 
						|
      }
 | 
						|
      EXPECT_EQ(0, response->GetStatus()) << callback;
 | 
						|
      EXPECT_STREQ("", response->GetStatusText().ToString().c_str())
 | 
						|
          << callback;
 | 
						|
      EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
 | 
						|
      EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback;
 | 
						|
      EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
 | 
						|
    } else {
 | 
						|
      if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ &&
 | 
						|
          callback == kOnResourceLoadComplete) {
 | 
						|
        // We got a response, but we also got aborted.
 | 
						|
        EXPECT_EQ(ERR_ABORTED, response->GetError()) << callback;
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(ERR_NONE, response->GetError()) << callback;
 | 
						|
      }
 | 
						|
      EXPECT_EQ(200, response->GetStatus()) << callback;
 | 
						|
      EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str())
 | 
						|
          << callback;
 | 
						|
      EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
 | 
						|
      EXPECT_STREQ("text/javascript",
 | 
						|
                   response->GetMimeType().ToString().c_str())
 | 
						|
          << callback;
 | 
						|
      EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void VerifyRedirectResponse(Callback callback,
 | 
						|
                              CefRefPtr<CefResponse> response) const {
 | 
						|
    EXPECT_EQ(ERR_NONE, response->GetError()) << callback;
 | 
						|
    EXPECT_EQ(307, response->GetStatus()) << callback;
 | 
						|
    const std::string& status_text = response->GetStatusText();
 | 
						|
    EXPECT_TRUE(status_text == "Internal Redirect" ||
 | 
						|
                status_text == "Temporary Redirect")
 | 
						|
        << status_text << callback;
 | 
						|
    EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
 | 
						|
    EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback;
 | 
						|
    EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
 | 
						|
  }
 | 
						|
 | 
						|
  void CloseBrowserAsync() {
 | 
						|
    EXPECT_TRUE(IsIncomplete());
 | 
						|
    SetSignalTestCompletionCount(1U);
 | 
						|
    CefPostDelayedTask(
 | 
						|
        TID_UI, base::BindOnce(&TestHandler::CloseBrowser, GetBrowser(), false),
 | 
						|
        100);
 | 
						|
  }
 | 
						|
 | 
						|
  void MaybeDestroyTest(bool from_handler) {
 | 
						|
    if (!CefCurrentlyOn(TID_UI)) {
 | 
						|
      CefPostTask(TID_UI,
 | 
						|
                  base::BindOnce(&SubresourceResponseTest::MaybeDestroyTest,
 | 
						|
                                 this, from_handler));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (from_handler) {
 | 
						|
      resource_handler_destroyed_ct_++;
 | 
						|
    }
 | 
						|
 | 
						|
    bool destroy_test = false;
 | 
						|
    if (IsIncomplete()) {
 | 
						|
      // Destroy the test if we got OnResourceLoadComplete and either the
 | 
						|
      // resource handler will never complete or it was destroyed.
 | 
						|
      destroy_test =
 | 
						|
          on_resource_load_complete_ct_ > 0 &&
 | 
						|
          (!IsIncompleteRequestHandler() ||
 | 
						|
           resource_handler_destroyed_ct_ == resource_handler_created_ct_);
 | 
						|
    } else {
 | 
						|
      // Destroy the test if we got the expected number of OnLoadEnd and
 | 
						|
      // OnQuery, and the expected number of resource handlers were destroyed.
 | 
						|
      destroy_test =
 | 
						|
          on_load_end_ct_ > (subframe_ ? 1 : 0) &&
 | 
						|
          (on_query_ct_ > 0 || unhandled_) &&
 | 
						|
          resource_handler_destroyed_ct_ == resource_handler_created_ct_;
 | 
						|
    }
 | 
						|
 | 
						|
    if (destroy_test) {
 | 
						|
      DestroyTest();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  const TestMode mode_;
 | 
						|
  const bool custom_scheme_;
 | 
						|
  const bool unhandled_;
 | 
						|
  const bool subframe_;
 | 
						|
 | 
						|
  int browser_id_ = 0;
 | 
						|
  int64_t frame_id_ = 0;
 | 
						|
  uint64_t request_id_ = 0U;
 | 
						|
 | 
						|
  int resource_handler_created_ct_ = 0;
 | 
						|
 | 
						|
  int on_before_browse_ct_ = 0;
 | 
						|
  int on_load_end_ct_ = 0;
 | 
						|
  int on_query_ct_ = 0;
 | 
						|
 | 
						|
  int get_resource_request_handler_ct_ = 0;
 | 
						|
  int get_cookie_access_filter_ct_ = 0;
 | 
						|
  int on_before_resource_load_ct_ = 0;
 | 
						|
  int get_resource_handler_ct_ = 0;
 | 
						|
  int on_resource_redirect_ct_ = 0;
 | 
						|
  int on_resource_response_ct_ = 0;
 | 
						|
  int get_resource_response_filter_ct_ = 0;
 | 
						|
  int on_resource_load_complete_ct_ = 0;
 | 
						|
  int on_protocol_execution_ct_ = 0;
 | 
						|
  int resource_handler_destroyed_ct_ = 0;
 | 
						|
 | 
						|
  // Used with INCOMPLETE_BEFORE_RESOURCE_LOAD.
 | 
						|
  CefRefPtr<CefCallback> incomplete_callback_;
 | 
						|
 | 
						|
  DISALLOW_COPY_AND_ASSIGN(SubresourceResponseTest);
 | 
						|
  IMPLEMENT_REFCOUNTING(SubresourceResponseTest);
 | 
						|
};
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
#define SUBRESOURCE_TEST(name, test_mode, custom, unhandled, subframe)        \
 | 
						|
  TEST(ResourceRequestHandlerTest, Subresource##name) {                       \
 | 
						|
    CefRefPtr<SubresourceResponseTest> handler = new SubresourceResponseTest( \
 | 
						|
        SubresourceResponseTest::test_mode, custom, unhandled, subframe);     \
 | 
						|
    handler->ExecuteTest();                                                   \
 | 
						|
    ReleaseAndWaitForDestructor(handler);                                     \
 | 
						|
  }
 | 
						|
 | 
						|
#define SUBRESOURCE_TEST_ALL_MODES(name, custom, unhandled, subframe)          \
 | 
						|
  SUBRESOURCE_TEST(name##Load, LOAD, custom, unhandled, subframe)              \
 | 
						|
  SUBRESOURCE_TEST(name##ModifyBeforeResourceLoad,                             \
 | 
						|
                   MODIFY_BEFORE_RESOURCE_LOAD, custom, unhandled, subframe)   \
 | 
						|
  SUBRESOURCE_TEST(name##RedirectBeforeResourceLoad,                           \
 | 
						|
                   REDIRECT_BEFORE_RESOURCE_LOAD, custom, unhandled, subframe) \
 | 
						|
  SUBRESOURCE_TEST(name##RedirectRequestHandler, REDIRECT_REQUEST_HANDLER,     \
 | 
						|
                   custom, unhandled, subframe)                                \
 | 
						|
  SUBRESOURCE_TEST(name##RedirectResourceRedirect, REDIRECT_RESOURCE_REDIRECT, \
 | 
						|
                   custom, unhandled, subframe)                                \
 | 
						|
  SUBRESOURCE_TEST(name##RedirectResourceResponse, REDIRECT_RESOURCE_RESPONSE, \
 | 
						|
                   custom, unhandled, subframe)                                \
 | 
						|
  SUBRESOURCE_TEST(name##RestartResourceResponse, RESTART_RESOURCE_RESPONSE,   \
 | 
						|
                   custom, unhandled, subframe)
 | 
						|
 | 
						|
// Tests only supported in handled mode.
 | 
						|
#define SUBRESOURCE_TEST_HANDLED_MODES(name, custom, subframe)               \
 | 
						|
  SUBRESOURCE_TEST(name##ImmediateRequestHandlerOpen,                        \
 | 
						|
                   IMMEDIATE_REQUEST_HANDLER_OPEN, custom, false, subframe)  \
 | 
						|
  SUBRESOURCE_TEST(name##ImmediateRequestHandlerRead,                        \
 | 
						|
                   IMMEDIATE_REQUEST_HANDLER_READ, custom, false, subframe)  \
 | 
						|
  SUBRESOURCE_TEST(name##ImmediateRequestHandlerAll,                         \
 | 
						|
                   IMMEDIATE_REQUEST_HANDLER_ALL, custom, false, subframe)   \
 | 
						|
  SUBRESOURCE_TEST(name##DelayedRequestHandlerOpen,                          \
 | 
						|
                   DELAYED_REQUEST_HANDLER_OPEN, custom, false, subframe)    \
 | 
						|
  SUBRESOURCE_TEST(name##DelayedRequestHandlerRead,                          \
 | 
						|
                   DELAYED_REQUEST_HANDLER_READ, custom, false, subframe)    \
 | 
						|
  SUBRESOURCE_TEST(name##DelayedRequestHandlerAll,                           \
 | 
						|
                   DELAYED_REQUEST_HANDLER_ALL, custom, false, subframe)     \
 | 
						|
  SUBRESOURCE_TEST(name##IncompleteBeforeResourceLoad,                       \
 | 
						|
                   INCOMPLETE_BEFORE_RESOURCE_LOAD, custom, false, subframe) \
 | 
						|
  SUBRESOURCE_TEST(name##IncompleteRequestHandlerOpen,                       \
 | 
						|
                   INCOMPLETE_REQUEST_HANDLER_OPEN, custom, false, subframe) \
 | 
						|
  SUBRESOURCE_TEST(name##IncompleteRequestHandlerRead,                       \
 | 
						|
                   INCOMPLETE_REQUEST_HANDLER_READ, custom, false, subframe)
 | 
						|
 | 
						|
SUBRESOURCE_TEST_ALL_MODES(StandardHandledMainFrame, false, false, false)
 | 
						|
SUBRESOURCE_TEST_ALL_MODES(StandardUnhandledMainFrame, false, true, false)
 | 
						|
SUBRESOURCE_TEST_ALL_MODES(CustomHandledMainFrame, true, false, false)
 | 
						|
SUBRESOURCE_TEST_ALL_MODES(CustomUnhandledMainFrame, true, true, false)
 | 
						|
 | 
						|
SUBRESOURCE_TEST_ALL_MODES(StandardHandledSubFrame, false, false, true)
 | 
						|
SUBRESOURCE_TEST_ALL_MODES(StandardUnhandledSubFrame, false, true, true)
 | 
						|
SUBRESOURCE_TEST_ALL_MODES(CustomHandledSubFrame, true, false, true)
 | 
						|
SUBRESOURCE_TEST_ALL_MODES(CustomUnhandledSubFrame, true, true, true)
 | 
						|
 | 
						|
SUBRESOURCE_TEST_HANDLED_MODES(StandardHandledMainFrame, false, false)
 | 
						|
SUBRESOURCE_TEST_HANDLED_MODES(CustomHandledMainFrame, true, false)
 | 
						|
 | 
						|
SUBRESOURCE_TEST_HANDLED_MODES(StandardHandledSubFrame, false, true)
 | 
						|
SUBRESOURCE_TEST_HANDLED_MODES(CustomHandledSubFrame, true, true)
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
const char kResourceTestHtml[] = "https://test.com/resource.html";
 | 
						|
 | 
						|
class RedirectResponseTest : public TestHandler {
 | 
						|
 public:
 | 
						|
  enum TestMode {
 | 
						|
    URL,
 | 
						|
    HEADER,
 | 
						|
    POST,
 | 
						|
  };
 | 
						|
 | 
						|
  RedirectResponseTest(TestMode mode, bool via_request_context_handler)
 | 
						|
      : via_request_context_handler_(via_request_context_handler) {
 | 
						|
    if (mode == URL) {
 | 
						|
      resource_test_.reset(new UrlResourceTest);
 | 
						|
    } else if (mode == HEADER) {
 | 
						|
      resource_test_.reset(new HeaderResourceTest);
 | 
						|
    } else {
 | 
						|
      resource_test_.reset(new PostResourceTest);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void RunTest() override {
 | 
						|
    AddResource(kResourceTestHtml, GetHtml(), "text/html");
 | 
						|
 | 
						|
    resource_request_handler_ = new ResourceRequestHandler(this);
 | 
						|
 | 
						|
    CefRefPtr<CefRequestContext> request_context =
 | 
						|
        CefRequestContext::GetGlobalContext();
 | 
						|
    if (via_request_context_handler_) {
 | 
						|
      CefRefPtr<CefRequestContextHandler> request_context_handler =
 | 
						|
          new RequestContextHandler(resource_request_handler_.get());
 | 
						|
      CefRequestContextSettings settings;
 | 
						|
      request_context = CefRequestContext::CreateContext(
 | 
						|
          request_context, request_context_handler);
 | 
						|
    }
 | 
						|
 | 
						|
    CreateBrowser(kResourceTestHtml, request_context);
 | 
						|
    SetTestTimeout();
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request,
 | 
						|
      bool is_navigation,
 | 
						|
      bool is_download,
 | 
						|
      const CefString& request_initiator,
 | 
						|
      bool& disable_default_handling) override {
 | 
						|
    if (via_request_context_handler_) {
 | 
						|
      // Use the handler returned by RequestContextHandler.
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
    return resource_request_handler_.get();
 | 
						|
  }
 | 
						|
 | 
						|
  bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
 | 
						|
                      CefRefPtr<CefFrame> frame,
 | 
						|
                      CefRefPtr<CefRequest> request,
 | 
						|
                      bool user_gesture,
 | 
						|
                      bool is_redirect) override {
 | 
						|
    EXPECT_UI_THREAD();
 | 
						|
    EXPECT_EQ(0, browser_id_);
 | 
						|
    browser_id_ = browser->GetIdentifier();
 | 
						|
    EXPECT_GT(browser_id_, 0);
 | 
						|
 | 
						|
    // This method is only called for the main resource.
 | 
						|
    EXPECT_STREQ(kResourceTestHtml, request->GetURL().ToString().c_str());
 | 
						|
 | 
						|
    // Browser-side navigation no longer exposes the actual request information.
 | 
						|
    EXPECT_EQ(0U, request->GetIdentifier());
 | 
						|
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  void OnLoadEnd(CefRefPtr<CefBrowser> browser,
 | 
						|
                 CefRefPtr<CefFrame> frame,
 | 
						|
                 int httpStatusCode) override {
 | 
						|
    EXPECT_UI_THREAD();
 | 
						|
    EXPECT_EQ(browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
    TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
 | 
						|
    DestroyTest();
 | 
						|
  }
 | 
						|
 | 
						|
  void DestroyTest() override {
 | 
						|
    resource_test_->CheckExpected();
 | 
						|
    resource_test_.reset(nullptr);
 | 
						|
 | 
						|
    TestHandler::DestroyTest();
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  std::string GetHtml() const {
 | 
						|
    std::stringstream html;
 | 
						|
    html << "<html><head>";
 | 
						|
 | 
						|
    const std::string& url = resource_test_->start_url();
 | 
						|
    html << "<script type=\"text/javascript\" src=\"" << url << "\"></script>";
 | 
						|
 | 
						|
    html << "</head><body><p>Main</p></body></html>";
 | 
						|
    return html.str();
 | 
						|
  }
 | 
						|
 | 
						|
  class ResourceTest {
 | 
						|
   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)
 | 
						|
        : start_url_(start_url),
 | 
						|
          expected_resource_response_ct_(expected_resource_response_ct),
 | 
						|
          expected_before_resource_load_ct_(expected_before_resource_load_ct),
 | 
						|
          expected_resource_redirect_ct_(expected_resource_redirect_ct),
 | 
						|
          expected_resource_load_complete_ct_(
 | 
						|
              expected_resource_load_complete_ct) {}
 | 
						|
    virtual ~ResourceTest() {}
 | 
						|
 | 
						|
    const std::string& start_url() const { return start_url_; }
 | 
						|
 | 
						|
    virtual bool OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
 | 
						|
                                      CefRefPtr<CefFrame> frame,
 | 
						|
                                      CefRefPtr<CefRequest> request) {
 | 
						|
      before_resource_load_ct_++;
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    virtual CefRefPtr<CefResourceHandler> GetResourceHandler(
 | 
						|
        CefRefPtr<CefBrowser> browser,
 | 
						|
        CefRefPtr<CefFrame> frame,
 | 
						|
        CefRefPtr<CefRequest> request) {
 | 
						|
      get_resource_handler_ct_++;
 | 
						|
 | 
						|
      const std::string& js_content = "<!-- -->";
 | 
						|
 | 
						|
      CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
 | 
						|
          const_cast<char*>(js_content.c_str()), js_content.size());
 | 
						|
 | 
						|
      return new CefStreamResourceHandler(200, "OK", "text/javascript",
 | 
						|
                                          CefResponse::HeaderMap(), stream);
 | 
						|
    }
 | 
						|
 | 
						|
    virtual void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
 | 
						|
                                    CefRefPtr<CefFrame> frame,
 | 
						|
                                    CefRefPtr<CefRequest> request,
 | 
						|
                                    CefString& new_url) {
 | 
						|
      resource_redirect_ct_++;
 | 
						|
    }
 | 
						|
 | 
						|
    bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
 | 
						|
                            CefRefPtr<CefFrame> frame,
 | 
						|
                            CefRefPtr<CefRequest> request,
 | 
						|
                            CefRefPtr<CefResponse> response) {
 | 
						|
      EXPECT_TRUE(CheckUrl(request->GetURL()));
 | 
						|
 | 
						|
      // Verify the response returned by GetResourceHandler.
 | 
						|
      EXPECT_EQ(200, response->GetStatus());
 | 
						|
      EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str());
 | 
						|
      EXPECT_STREQ("text/javascript",
 | 
						|
                   response->GetMimeType().ToString().c_str());
 | 
						|
 | 
						|
      if (resource_response_ct_++ == 0U) {
 | 
						|
        // Always redirect at least one time.
 | 
						|
        OnResourceReceived(browser, frame, request, response);
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
 | 
						|
      OnRetryReceived(browser, frame, request, response);
 | 
						|
      return (resource_response_ct_ < expected_resource_response_ct_);
 | 
						|
    }
 | 
						|
 | 
						|
    CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
 | 
						|
        CefRefPtr<CefBrowser> browser,
 | 
						|
        CefRefPtr<CefFrame> frame,
 | 
						|
        CefRefPtr<CefRequest> request,
 | 
						|
        CefRefPtr<CefResponse> response) {
 | 
						|
      get_resource_response_filter_ct_++;
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
    void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
 | 
						|
                                CefRefPtr<CefFrame> frame,
 | 
						|
                                CefRefPtr<CefRequest> request,
 | 
						|
                                CefRefPtr<CefResponse> response,
 | 
						|
                                URLRequestStatus status,
 | 
						|
                                int64_t received_content_length) {
 | 
						|
      EXPECT_TRUE(CheckUrl(request->GetURL()));
 | 
						|
 | 
						|
      // Verify the response returned by GetResourceHandler.
 | 
						|
      EXPECT_EQ(200, response->GetStatus());
 | 
						|
      EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str());
 | 
						|
      EXPECT_STREQ("text/javascript",
 | 
						|
                   response->GetMimeType().ToString().c_str());
 | 
						|
 | 
						|
      resource_load_complete_ct_++;
 | 
						|
    }
 | 
						|
 | 
						|
    virtual bool CheckUrl(const std::string& url) const {
 | 
						|
      return (url == start_url_);
 | 
						|
    }
 | 
						|
 | 
						|
    virtual void CheckExpected() {
 | 
						|
      EXPECT_TRUE(got_resource_);
 | 
						|
      EXPECT_TRUE(got_resource_retry_);
 | 
						|
 | 
						|
      EXPECT_EQ(expected_resource_response_ct_, resource_response_ct_);
 | 
						|
      EXPECT_EQ(expected_resource_response_ct_, get_resource_handler_ct_);
 | 
						|
      EXPECT_EQ(expected_resource_load_complete_ct_,
 | 
						|
                get_resource_response_filter_ct_);
 | 
						|
      EXPECT_EQ(expected_before_resource_load_ct_, before_resource_load_ct_);
 | 
						|
      EXPECT_EQ(expected_resource_redirect_ct_, resource_redirect_ct_);
 | 
						|
      EXPECT_EQ(expected_resource_load_complete_ct_,
 | 
						|
                resource_load_complete_ct_);
 | 
						|
    }
 | 
						|
 | 
						|
   protected:
 | 
						|
    virtual void OnResourceReceived(CefRefPtr<CefBrowser> browser,
 | 
						|
                                    CefRefPtr<CefFrame> frame,
 | 
						|
                                    CefRefPtr<CefRequest> request,
 | 
						|
                                    CefRefPtr<CefResponse> response) {
 | 
						|
      got_resource_.yes();
 | 
						|
    }
 | 
						|
 | 
						|
    virtual void OnRetryReceived(CefRefPtr<CefBrowser> browser,
 | 
						|
                                 CefRefPtr<CefFrame> frame,
 | 
						|
                                 CefRefPtr<CefRequest> request,
 | 
						|
                                 CefRefPtr<CefResponse> response) {
 | 
						|
      got_resource_retry_.yes();
 | 
						|
    }
 | 
						|
 | 
						|
   private:
 | 
						|
    std::string start_url_;
 | 
						|
 | 
						|
    size_t resource_response_ct_ = 0U;
 | 
						|
    size_t expected_resource_response_ct_;
 | 
						|
    size_t before_resource_load_ct_ = 0U;
 | 
						|
    size_t expected_before_resource_load_ct_;
 | 
						|
    size_t get_resource_handler_ct_ = 0U;
 | 
						|
    size_t resource_redirect_ct_ = 0U;
 | 
						|
    size_t expected_resource_redirect_ct_;
 | 
						|
    size_t get_resource_response_filter_ct_ = 0U;
 | 
						|
    size_t resource_load_complete_ct_ = 0U;
 | 
						|
    size_t expected_resource_load_complete_ct_;
 | 
						|
 | 
						|
    TrackCallback got_resource_;
 | 
						|
    TrackCallback got_resource_retry_;
 | 
						|
  };
 | 
						|
 | 
						|
  class UrlResourceTest : public ResourceTest {
 | 
						|
   public:
 | 
						|
    // With NetworkService we don't get an additional (unnecessary) redirect
 | 
						|
    // callback.
 | 
						|
    UrlResourceTest()
 | 
						|
        : ResourceTest("https://test.com/start_url.js", 2U, 2U, 1U) {
 | 
						|
      redirect_url_ = "https://test.com/redirect_url.js";
 | 
						|
    }
 | 
						|
 | 
						|
    bool CheckUrl(const std::string& url) const override {
 | 
						|
      if (url == redirect_url_) {
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
 | 
						|
      return ResourceTest::CheckUrl(url);
 | 
						|
    }
 | 
						|
 | 
						|
    void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
 | 
						|
                            CefRefPtr<CefFrame> frame,
 | 
						|
                            CefRefPtr<CefRequest> request,
 | 
						|
                            CefString& new_url) override {
 | 
						|
      ResourceTest::OnResourceRedirect(browser, frame, request, new_url);
 | 
						|
      const std::string& old_url = request->GetURL();
 | 
						|
      EXPECT_STREQ(start_url().c_str(), old_url.c_str());
 | 
						|
      EXPECT_STREQ(redirect_url_.c_str(), new_url.ToString().c_str());
 | 
						|
    }
 | 
						|
 | 
						|
   private:
 | 
						|
    void OnResourceReceived(CefRefPtr<CefBrowser> browser,
 | 
						|
                            CefRefPtr<CefFrame> frame,
 | 
						|
                            CefRefPtr<CefRequest> request,
 | 
						|
                            CefRefPtr<CefResponse> response) override {
 | 
						|
      ResourceTest::OnResourceReceived(browser, frame, request, response);
 | 
						|
      request->SetURL(redirect_url_);
 | 
						|
    }
 | 
						|
 | 
						|
    void OnRetryReceived(CefRefPtr<CefBrowser> browser,
 | 
						|
                         CefRefPtr<CefFrame> frame,
 | 
						|
                         CefRefPtr<CefRequest> request,
 | 
						|
                         CefRefPtr<CefResponse> response) override {
 | 
						|
      ResourceTest::OnRetryReceived(browser, frame, request, response);
 | 
						|
      const std::string& new_url = request->GetURL();
 | 
						|
      EXPECT_STREQ(redirect_url_.c_str(), new_url.c_str());
 | 
						|
    }
 | 
						|
 | 
						|
    std::string redirect_url_;
 | 
						|
  };
 | 
						|
 | 
						|
  class HeaderResourceTest : public ResourceTest {
 | 
						|
   public:
 | 
						|
    // With NetworkService we restart the request, so we get another call to
 | 
						|
    // OnBeforeResourceLoad.
 | 
						|
    HeaderResourceTest()
 | 
						|
        : ResourceTest("https://test.com/start_header.js", 2U, 2U) {
 | 
						|
      expected_headers_.insert(std::make_pair("Test-Key1", "Value1"));
 | 
						|
      expected_headers_.insert(std::make_pair("Test-Key2", "Value2"));
 | 
						|
    }
 | 
						|
 | 
						|
   private:
 | 
						|
    void OnResourceReceived(CefRefPtr<CefBrowser> browser,
 | 
						|
                            CefRefPtr<CefFrame> frame,
 | 
						|
                            CefRefPtr<CefRequest> request,
 | 
						|
                            CefRefPtr<CefResponse> response) override {
 | 
						|
      ResourceTest::OnResourceReceived(browser, frame, request, response);
 | 
						|
      request->SetHeaderMap(expected_headers_);
 | 
						|
    }
 | 
						|
 | 
						|
    void OnRetryReceived(CefRefPtr<CefBrowser> browser,
 | 
						|
                         CefRefPtr<CefFrame> frame,
 | 
						|
                         CefRefPtr<CefRequest> request,
 | 
						|
                         CefRefPtr<CefResponse> response) override {
 | 
						|
      ResourceTest::OnRetryReceived(browser, frame, request, response);
 | 
						|
      CefRequest::HeaderMap actual_headers;
 | 
						|
      request->GetHeaderMap(actual_headers);
 | 
						|
      TestMapEqual(expected_headers_, actual_headers, true);
 | 
						|
    }
 | 
						|
 | 
						|
    CefRequest::HeaderMap expected_headers_;
 | 
						|
  };
 | 
						|
 | 
						|
  class PostResourceTest : public ResourceTest {
 | 
						|
   public:
 | 
						|
    // With NetworkService we restart the request, so we get another call to
 | 
						|
    // OnBeforeResourceLoad.
 | 
						|
    PostResourceTest()
 | 
						|
        : ResourceTest("https://test.com/start_post.js", 2U, 2U) {
 | 
						|
      CefRefPtr<CefPostDataElement> elem = CefPostDataElement::Create();
 | 
						|
      const std::string data("Test Post Data");
 | 
						|
      elem->SetToBytes(data.size(), data.c_str());
 | 
						|
 | 
						|
      expected_post_ = CefPostData::Create();
 | 
						|
      expected_post_->AddElement(elem);
 | 
						|
    }
 | 
						|
 | 
						|
   private:
 | 
						|
    void OnResourceReceived(CefRefPtr<CefBrowser> browser,
 | 
						|
                            CefRefPtr<CefFrame> frame,
 | 
						|
                            CefRefPtr<CefRequest> request,
 | 
						|
                            CefRefPtr<CefResponse> response) override {
 | 
						|
      ResourceTest::OnResourceReceived(browser, frame, request, response);
 | 
						|
      request->SetPostData(expected_post_);
 | 
						|
    }
 | 
						|
 | 
						|
    void OnRetryReceived(CefRefPtr<CefBrowser> browser,
 | 
						|
                         CefRefPtr<CefFrame> frame,
 | 
						|
                         CefRefPtr<CefRequest> request,
 | 
						|
                         CefRefPtr<CefResponse> response) override {
 | 
						|
      ResourceTest::OnRetryReceived(browser, frame, request, response);
 | 
						|
      CefRefPtr<CefPostData> actual_post = request->GetPostData();
 | 
						|
      TestPostDataEqual(expected_post_, actual_post);
 | 
						|
    }
 | 
						|
 | 
						|
    CefRefPtr<CefPostData> expected_post_;
 | 
						|
  };
 | 
						|
 | 
						|
  class RequestContextHandler : public CefRequestContextHandler {
 | 
						|
   public:
 | 
						|
    explicit RequestContextHandler(
 | 
						|
        CefRefPtr<CefResourceRequestHandler> resource_request_handler)
 | 
						|
        : resource_request_handler_(resource_request_handler) {}
 | 
						|
 | 
						|
    CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
 | 
						|
        CefRefPtr<CefBrowser> browser,
 | 
						|
        CefRefPtr<CefFrame> frame,
 | 
						|
        CefRefPtr<CefRequest> request,
 | 
						|
        bool is_navigation,
 | 
						|
        bool is_download,
 | 
						|
        const CefString& request_initiator,
 | 
						|
        bool& disable_default_handling) override {
 | 
						|
      return resource_request_handler_;
 | 
						|
    }
 | 
						|
 | 
						|
   private:
 | 
						|
    CefRefPtr<CefResourceRequestHandler> resource_request_handler_;
 | 
						|
 | 
						|
    IMPLEMENT_REFCOUNTING(RequestContextHandler);
 | 
						|
    DISALLOW_COPY_AND_ASSIGN(RequestContextHandler);
 | 
						|
  };
 | 
						|
 | 
						|
  class ResourceRequestHandler : public CefResourceRequestHandler {
 | 
						|
   public:
 | 
						|
    explicit ResourceRequestHandler(RedirectResponseTest* test) : test_(test) {}
 | 
						|
 | 
						|
    cef_return_value_t OnBeforeResourceLoad(
 | 
						|
        CefRefPtr<CefBrowser> browser,
 | 
						|
        CefRefPtr<CefFrame> frame,
 | 
						|
        CefRefPtr<CefRequest> request,
 | 
						|
        CefRefPtr<CefCallback> callback) override {
 | 
						|
      EXPECT_IO_THREAD();
 | 
						|
 | 
						|
      if (IsChromeRuntimeEnabled() &&
 | 
						|
          request->GetResourceType() == RT_FAVICON) {
 | 
						|
        // Ignore favicon requests.
 | 
						|
        return RV_CANCEL;
 | 
						|
      }
 | 
						|
 | 
						|
      EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
      if (request->GetURL() == kResourceTestHtml) {
 | 
						|
        // All loads of the main resource should keep the same request id.
 | 
						|
        EXPECT_EQ(0U, main_request_id_);
 | 
						|
        main_request_id_ = request->GetIdentifier();
 | 
						|
        EXPECT_GT(main_request_id_, 0U);
 | 
						|
        return RV_CONTINUE;
 | 
						|
      }
 | 
						|
 | 
						|
      // All redirects of the sub-resource should keep the same request id.
 | 
						|
      if (sub_request_id_ == 0U) {
 | 
						|
        sub_request_id_ = request->GetIdentifier();
 | 
						|
        EXPECT_GT(sub_request_id_, 0U);
 | 
						|
      } else {
 | 
						|
        EXPECT_EQ(sub_request_id_, request->GetIdentifier());
 | 
						|
      }
 | 
						|
 | 
						|
      return test_->resource_test_->OnBeforeResourceLoad(browser, frame,
 | 
						|
                                                         request)
 | 
						|
                 ? RV_CANCEL
 | 
						|
                 : RV_CONTINUE;
 | 
						|
    }
 | 
						|
 | 
						|
    CefRefPtr<CefResourceHandler> GetResourceHandler(
 | 
						|
        CefRefPtr<CefBrowser> browser,
 | 
						|
        CefRefPtr<CefFrame> frame,
 | 
						|
        CefRefPtr<CefRequest> request) override {
 | 
						|
      EXPECT_IO_THREAD();
 | 
						|
      EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
      if (request->GetURL() == kResourceTestHtml) {
 | 
						|
        EXPECT_EQ(main_request_id_, request->GetIdentifier());
 | 
						|
        return test_->GetResourceHandler(browser, frame, request);
 | 
						|
      }
 | 
						|
 | 
						|
      EXPECT_EQ(sub_request_id_, request->GetIdentifier());
 | 
						|
      return test_->resource_test_->GetResourceHandler(browser, frame, request);
 | 
						|
    }
 | 
						|
 | 
						|
    void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
 | 
						|
                            CefRefPtr<CefFrame> frame,
 | 
						|
                            CefRefPtr<CefRequest> request,
 | 
						|
                            CefRefPtr<CefResponse> response,
 | 
						|
                            CefString& new_url) override {
 | 
						|
      EXPECT_IO_THREAD();
 | 
						|
      EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
 | 
						|
      EXPECT_EQ(sub_request_id_, request->GetIdentifier());
 | 
						|
 | 
						|
      test_->resource_test_->OnResourceRedirect(browser, frame, request,
 | 
						|
                                                new_url);
 | 
						|
    }
 | 
						|
 | 
						|
    bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
 | 
						|
                            CefRefPtr<CefFrame> frame,
 | 
						|
                            CefRefPtr<CefRequest> request,
 | 
						|
                            CefRefPtr<CefResponse> response) override {
 | 
						|
      EXPECT_IO_THREAD();
 | 
						|
      EXPECT_TRUE(browser.get());
 | 
						|
      EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
      EXPECT_TRUE(frame.get());
 | 
						|
      EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
      if (request->GetURL() == kResourceTestHtml) {
 | 
						|
        EXPECT_EQ(main_request_id_, request->GetIdentifier());
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      EXPECT_EQ(sub_request_id_, request->GetIdentifier());
 | 
						|
      return test_->resource_test_->OnResourceResponse(browser, frame, request,
 | 
						|
                                                       response);
 | 
						|
    }
 | 
						|
 | 
						|
    CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
 | 
						|
        CefRefPtr<CefBrowser> browser,
 | 
						|
        CefRefPtr<CefFrame> frame,
 | 
						|
        CefRefPtr<CefRequest> request,
 | 
						|
        CefRefPtr<CefResponse> response) override {
 | 
						|
      EXPECT_IO_THREAD();
 | 
						|
      EXPECT_TRUE(browser.get());
 | 
						|
      EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
      EXPECT_TRUE(frame.get());
 | 
						|
      EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
      if (request->GetURL() == kResourceTestHtml) {
 | 
						|
        EXPECT_EQ(main_request_id_, request->GetIdentifier());
 | 
						|
        return nullptr;
 | 
						|
      }
 | 
						|
 | 
						|
      return test_->resource_test_->GetResourceResponseFilter(
 | 
						|
          browser, frame, request, response);
 | 
						|
    }
 | 
						|
 | 
						|
    void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
 | 
						|
                                CefRefPtr<CefFrame> frame,
 | 
						|
                                CefRefPtr<CefRequest> request,
 | 
						|
                                CefRefPtr<CefResponse> response,
 | 
						|
                                URLRequestStatus status,
 | 
						|
                                int64_t received_content_length) override {
 | 
						|
      EXPECT_IO_THREAD();
 | 
						|
 | 
						|
      if (IsChromeRuntimeEnabled() &&
 | 
						|
          request->GetResourceType() == RT_FAVICON) {
 | 
						|
        // Ignore favicon requests.
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      EXPECT_TRUE(browser.get());
 | 
						|
      EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
 | 
						|
 | 
						|
      EXPECT_TRUE(frame.get());
 | 
						|
      EXPECT_TRUE(frame->IsMain());
 | 
						|
 | 
						|
      if (request->GetURL() == kResourceTestHtml) {
 | 
						|
        EXPECT_EQ(main_request_id_, request->GetIdentifier());
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      EXPECT_EQ(sub_request_id_, request->GetIdentifier());
 | 
						|
      test_->resource_test_->OnResourceLoadComplete(
 | 
						|
          browser, frame, request, response, status, received_content_length);
 | 
						|
    }
 | 
						|
 | 
						|
   private:
 | 
						|
    RedirectResponseTest* const test_;
 | 
						|
 | 
						|
    uint64_t main_request_id_ = 0U;
 | 
						|
    uint64_t sub_request_id_ = 0U;
 | 
						|
 | 
						|
    IMPLEMENT_REFCOUNTING(ResourceRequestHandler);
 | 
						|
    DISALLOW_COPY_AND_ASSIGN(ResourceRequestHandler);
 | 
						|
  };
 | 
						|
 | 
						|
  const bool via_request_context_handler_;
 | 
						|
 | 
						|
  int browser_id_ = 0;
 | 
						|
  std::unique_ptr<ResourceTest> resource_test_;
 | 
						|
  CefRefPtr<ResourceRequestHandler> resource_request_handler_;
 | 
						|
 | 
						|
  IMPLEMENT_REFCOUNTING(RedirectResponseTest);
 | 
						|
};
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
// Verify redirect with client handler.
 | 
						|
TEST(ResourceRequestHandlerTest, RedirectURLViaClient) {
 | 
						|
  CefRefPtr<RedirectResponseTest> handler =
 | 
						|
      new RedirectResponseTest(RedirectResponseTest::URL, false);
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
// Verify redirect + modified headers with client handler.
 | 
						|
TEST(ResourceRequestHandlerTest, RedirectHeaderViaClient) {
 | 
						|
  CefRefPtr<RedirectResponseTest> handler =
 | 
						|
      new RedirectResponseTest(RedirectResponseTest::HEADER, false);
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
// Verify redirect + modified post data with client handler.
 | 
						|
TEST(ResourceRequestHandlerTest, RedirectPostViaClient) {
 | 
						|
  CefRefPtr<RedirectResponseTest> handler =
 | 
						|
      new RedirectResponseTest(RedirectResponseTest::POST, false);
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
// Verify redirect with context handler.
 | 
						|
TEST(ResourceRequestHandlerTest, RedirectURLViaContext) {
 | 
						|
  CefRefPtr<RedirectResponseTest> handler =
 | 
						|
      new RedirectResponseTest(RedirectResponseTest::URL, true);
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
// Verify redirect + modified headers with context handler.
 | 
						|
TEST(ResourceRequestHandlerTest, RedirectHeaderViaContext) {
 | 
						|
  CefRefPtr<RedirectResponseTest> handler =
 | 
						|
      new RedirectResponseTest(RedirectResponseTest::HEADER, true);
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
// Verify redirect + modified post data with context handler.
 | 
						|
TEST(ResourceRequestHandlerTest, RedirectPostViaContext) {
 | 
						|
  CefRefPtr<RedirectResponseTest> handler =
 | 
						|
      new RedirectResponseTest(RedirectResponseTest::POST, true);
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
const char kResourceTestHtml2[] = "https://test.com/resource2.html";
 | 
						|
 | 
						|
class BeforeResourceLoadTest : public TestHandler {
 | 
						|
 public:
 | 
						|
  enum TestMode {
 | 
						|
    CANCEL,
 | 
						|
    CANCEL_ASYNC,
 | 
						|
    CANCEL_NAV,
 | 
						|
    CONTINUE,
 | 
						|
    CONTINUE_ASYNC,
 | 
						|
  };
 | 
						|
 | 
						|
  explicit BeforeResourceLoadTest(TestMode mode) : test_mode_(mode) {}
 | 
						|
 | 
						|
  void RunTest() override {
 | 
						|
    AddResource(kResourceTestHtml, "<html><body>Test</body></html>",
 | 
						|
                "text/html");
 | 
						|
    AddResource(kResourceTestHtml2, "<html><body>Test2</body></html>",
 | 
						|
                "text/html");
 | 
						|
    CreateBrowser(kResourceTestHtml);
 | 
						|
    SetTestTimeout();
 | 
						|
  }
 | 
						|
 | 
						|
  cef_return_value_t OnBeforeResourceLoad(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request,
 | 
						|
      CefRefPtr<CefCallback> callback) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
 | 
						|
    if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
 | 
						|
      // Ignore favicon requests.
 | 
						|
      return RV_CANCEL;
 | 
						|
    }
 | 
						|
 | 
						|
    // Allow the 2nd navigation to continue.
 | 
						|
    const std::string& url = request->GetURL();
 | 
						|
    if (url == kResourceTestHtml2) {
 | 
						|
      got_before_resource_load2_.yes();
 | 
						|
      EXPECT_EQ(CANCEL_NAV, test_mode_);
 | 
						|
      return RV_CONTINUE;
 | 
						|
    }
 | 
						|
 | 
						|
    EXPECT_FALSE(got_before_resource_load_);
 | 
						|
    got_before_resource_load_.yes();
 | 
						|
 | 
						|
    if (test_mode_ == CANCEL) {
 | 
						|
      // Cancel immediately.
 | 
						|
      return RV_CANCEL;
 | 
						|
    } else if (test_mode_ == CONTINUE) {
 | 
						|
      // Continue immediately.
 | 
						|
      return RV_CONTINUE;
 | 
						|
    } else {
 | 
						|
      if (test_mode_ == CANCEL_NAV) {
 | 
						|
        // Cancel the request by navigating to a new URL.
 | 
						|
        browser->GetMainFrame()->LoadURL(kResourceTestHtml2);
 | 
						|
      } else if (test_mode_ == CONTINUE_ASYNC) {
 | 
						|
        // Continue asynchronously.
 | 
						|
        CefPostTask(TID_UI,
 | 
						|
                    base::BindOnce(&CefCallback::Continue, callback.get()));
 | 
						|
      } else {
 | 
						|
        // Cancel asynchronously.
 | 
						|
        CefPostTask(TID_UI,
 | 
						|
                    base::BindOnce(&CefCallback::Cancel, callback.get()));
 | 
						|
      }
 | 
						|
      return RV_CONTINUE_ASYNC;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void OnLoadEnd(CefRefPtr<CefBrowser> browser,
 | 
						|
                 CefRefPtr<CefFrame> frame,
 | 
						|
                 int httpStatusCode) override {
 | 
						|
    EXPECT_UI_THREAD();
 | 
						|
 | 
						|
    EXPECT_FALSE(got_load_end_);
 | 
						|
    got_load_end_.yes();
 | 
						|
 | 
						|
    const std::string& url = frame->GetURL();
 | 
						|
    if (test_mode_ == CANCEL_NAV) {
 | 
						|
      EXPECT_STREQ(kResourceTestHtml2, url.data());
 | 
						|
    } else {
 | 
						|
      EXPECT_STREQ(kResourceTestHtml, url.data());
 | 
						|
    }
 | 
						|
 | 
						|
    TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
 | 
						|
    DestroyTest();
 | 
						|
  }
 | 
						|
 | 
						|
  void OnLoadError(CefRefPtr<CefBrowser> browser,
 | 
						|
                   CefRefPtr<CefFrame> frame,
 | 
						|
                   ErrorCode errorCode,
 | 
						|
                   const CefString& errorText,
 | 
						|
                   const CefString& failedUrl) override {
 | 
						|
    EXPECT_UI_THREAD();
 | 
						|
 | 
						|
    EXPECT_FALSE(got_load_error_);
 | 
						|
    got_load_error_.yes();
 | 
						|
 | 
						|
    const std::string& url = failedUrl;
 | 
						|
    EXPECT_STREQ(kResourceTestHtml, url.data());
 | 
						|
 | 
						|
    TestHandler::OnLoadError(browser, frame, errorCode, errorText, failedUrl);
 | 
						|
    if (test_mode_ != CANCEL_NAV) {
 | 
						|
      DestroyTest();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void DestroyTest() override {
 | 
						|
    EXPECT_TRUE(got_before_resource_load_);
 | 
						|
 | 
						|
    if (test_mode_ == CANCEL_NAV) {
 | 
						|
      EXPECT_TRUE(got_before_resource_load2_);
 | 
						|
    } else {
 | 
						|
      EXPECT_FALSE(got_before_resource_load2_);
 | 
						|
    }
 | 
						|
 | 
						|
    if (test_mode_ == CONTINUE || test_mode_ == CONTINUE_ASYNC) {
 | 
						|
      EXPECT_TRUE(got_load_end_);
 | 
						|
      EXPECT_FALSE(got_load_error_);
 | 
						|
    } else if (test_mode_ == CANCEL || test_mode_ == CANCEL_ASYNC) {
 | 
						|
      EXPECT_FALSE(got_load_end_);
 | 
						|
      EXPECT_TRUE(got_load_error_);
 | 
						|
    }
 | 
						|
 | 
						|
    TestHandler::DestroyTest();
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  const TestMode test_mode_;
 | 
						|
 | 
						|
  TrackCallback got_before_resource_load_;
 | 
						|
  TrackCallback got_before_resource_load2_;
 | 
						|
  TrackCallback got_load_end_;
 | 
						|
  TrackCallback got_load_error_;
 | 
						|
 | 
						|
  IMPLEMENT_REFCOUNTING(BeforeResourceLoadTest);
 | 
						|
};
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
TEST(ResourceRequestHandlerTest, BeforeResourceLoadCancel) {
 | 
						|
  CefRefPtr<BeforeResourceLoadTest> handler =
 | 
						|
      new BeforeResourceLoadTest(BeforeResourceLoadTest::CANCEL);
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
TEST(ResourceRequestHandlerTest, BeforeResourceLoadCancelAsync) {
 | 
						|
  CefRefPtr<BeforeResourceLoadTest> handler =
 | 
						|
      new BeforeResourceLoadTest(BeforeResourceLoadTest::CANCEL_ASYNC);
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
TEST(ResourceRequestHandlerTest, BeforeResourceLoadCancelNav) {
 | 
						|
  CefRefPtr<BeforeResourceLoadTest> handler =
 | 
						|
      new BeforeResourceLoadTest(BeforeResourceLoadTest::CANCEL_NAV);
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
TEST(ResourceRequestHandlerTest, BeforeResourceLoadContinue) {
 | 
						|
  CefRefPtr<BeforeResourceLoadTest> handler =
 | 
						|
      new BeforeResourceLoadTest(BeforeResourceLoadTest::CONTINUE);
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
TEST(ResourceRequestHandlerTest, BeforeResourceLoadContinueAsync) {
 | 
						|
  CefRefPtr<BeforeResourceLoadTest> handler =
 | 
						|
      new BeforeResourceLoadTest(BeforeResourceLoadTest::CONTINUE_ASYNC);
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
// For response filtering we need to test:
 | 
						|
// - Passing through content unchanged.
 | 
						|
// - Not reading all of the input buffer.
 | 
						|
// - Needing more input and getting it.
 | 
						|
// - Needing more input and not getting it.
 | 
						|
// - Filter error.
 | 
						|
 | 
						|
const char kResponseFilterTestUrl[] = "https://test.com/response_filter.html";
 | 
						|
 | 
						|
size_t GetResponseBufferSize() {
 | 
						|
  // Match the default |capacity_num_bytes| value from
 | 
						|
  // mojo::Core::CreateDataPipe.
 | 
						|
  return 64 * 1024;  // 64kb
 | 
						|
}
 | 
						|
 | 
						|
const char kInputHeader[] = "<html><head></head><body>";
 | 
						|
const char kInputFooter[] = "</body></html>";
 | 
						|
 | 
						|
// Repeat |content| the minimum number of times necessary to satisfy
 | 
						|
// |desired_min_size|. If |calculated_repeat_ct| is non-nullptr it will be set
 | 
						|
// to the number of times that |content| was repeated.
 | 
						|
std::string CreateInput(const std::string& content,
 | 
						|
                        size_t desired_min_size,
 | 
						|
                        size_t* calculated_repeat_ct = nullptr) {
 | 
						|
  const size_t header_footer_size =
 | 
						|
      sizeof(kInputHeader) + sizeof(kInputFooter) - 2;
 | 
						|
  EXPECT_GE(desired_min_size, header_footer_size + content.size());
 | 
						|
  desired_min_size -= header_footer_size;
 | 
						|
 | 
						|
  size_t repeat_ct =
 | 
						|
      static_cast<size_t>(std::ceil(static_cast<double>(desired_min_size) /
 | 
						|
                                    static_cast<double>(content.size())));
 | 
						|
  if (calculated_repeat_ct) {
 | 
						|
    *calculated_repeat_ct = repeat_ct;
 | 
						|
  }
 | 
						|
 | 
						|
  std::string result;
 | 
						|
  result.reserve(header_footer_size + (content.size() * repeat_ct));
 | 
						|
 | 
						|
  result = kInputHeader;
 | 
						|
  while (repeat_ct--) {
 | 
						|
    result += content;
 | 
						|
  }
 | 
						|
  result += kInputFooter;
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
std::string CreateOutput(const std::string& content, size_t repeat_ct) {
 | 
						|
  const size_t header_footer_size =
 | 
						|
      sizeof(kInputHeader) + sizeof(kInputFooter) - 2;
 | 
						|
 | 
						|
  std::string result;
 | 
						|
  result.reserve(header_footer_size + (content.size() * repeat_ct));
 | 
						|
 | 
						|
  result = kInputHeader;
 | 
						|
  while (repeat_ct--) {
 | 
						|
    result += content;
 | 
						|
  }
 | 
						|
  result += kInputFooter;
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
// Base class for test filters.
 | 
						|
class ResponseFilterTestBase : public CefResponseFilter {
 | 
						|
 public:
 | 
						|
  ResponseFilterTestBase() : filter_count_(0U) {}
 | 
						|
 | 
						|
  bool InitFilter() override {
 | 
						|
    EXPECT_FALSE(got_init_filter_);
 | 
						|
    got_init_filter_.yes();
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  FilterStatus 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) override {
 | 
						|
    if (data_in_size == 0U) {
 | 
						|
      EXPECT_FALSE(data_in);
 | 
						|
    } else {
 | 
						|
      EXPECT_TRUE(data_in);
 | 
						|
    }
 | 
						|
    EXPECT_EQ(data_in_read, 0U);
 | 
						|
    EXPECT_TRUE(data_out);
 | 
						|
    EXPECT_GT(data_out_size, 0U);
 | 
						|
    EXPECT_EQ(data_out_written, 0U);
 | 
						|
    filter_count_++;
 | 
						|
    return RESPONSE_FILTER_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  // Returns the input that will be fed into the filter.
 | 
						|
  virtual std::string GetInput() = 0;
 | 
						|
 | 
						|
  // Verify the output from the filter.
 | 
						|
  virtual void VerifyOutput(cef_urlrequest_status_t status,
 | 
						|
                            int64_t received_content_length,
 | 
						|
                            const std::string& received_content) {
 | 
						|
    EXPECT_TRUE(got_init_filter_);
 | 
						|
    EXPECT_GT(filter_count_, 0U);
 | 
						|
  }
 | 
						|
 | 
						|
  virtual void VerifyStatusCode(int httpStatusCode) const {
 | 
						|
    EXPECT_TRUE(httpStatusCode == 0 || httpStatusCode == 200) << httpStatusCode;
 | 
						|
  }
 | 
						|
 | 
						|
 protected:
 | 
						|
  TrackCallback got_init_filter_;
 | 
						|
  size_t filter_count_;
 | 
						|
 | 
						|
  IMPLEMENT_REFCOUNTING(ResponseFilterTestBase);
 | 
						|
};
 | 
						|
 | 
						|
// Pass through the contents unchanged.
 | 
						|
class ResponseFilterPassThru : public ResponseFilterTestBase {
 | 
						|
 public:
 | 
						|
  explicit ResponseFilterPassThru(bool limit_read) : limit_read_(limit_read) {}
 | 
						|
 | 
						|
  FilterStatus 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) override {
 | 
						|
    ResponseFilterTestBase::Filter(data_in, data_in_size, data_in_read,
 | 
						|
                                   data_out, data_out_size, data_out_written);
 | 
						|
 | 
						|
    if (limit_read_) {
 | 
						|
      // Read at most 1k bytes.
 | 
						|
      data_in_read = std::min(data_in_size, static_cast<size_t>(1024U));
 | 
						|
    } else {
 | 
						|
      // Read all available bytes.
 | 
						|
      data_in_read = data_in_size;
 | 
						|
    }
 | 
						|
 | 
						|
    data_out_written = std::min(data_in_read, data_out_size);
 | 
						|
    memcpy(data_out, data_in, data_out_written);
 | 
						|
 | 
						|
    return RESPONSE_FILTER_DONE;
 | 
						|
  }
 | 
						|
 | 
						|
  std::string GetInput() override {
 | 
						|
    input_ = CreateInput("FOOBAR ", GetResponseBufferSize() * 2U + 1);
 | 
						|
    return input_;
 | 
						|
  }
 | 
						|
 | 
						|
  void VerifyOutput(cef_urlrequest_status_t status,
 | 
						|
                    int64_t received_content_length,
 | 
						|
                    const std::string& received_content) override {
 | 
						|
    ResponseFilterTestBase::VerifyOutput(status, received_content_length,
 | 
						|
                                         received_content);
 | 
						|
 | 
						|
    if (limit_read_) {
 | 
						|
      // Expected to read 2 full buffers of GetResponseBufferSize() at 1kb
 | 
						|
      // increments and one partial buffer.
 | 
						|
      EXPECT_EQ(2U * (GetResponseBufferSize() / 1024) + 1U, filter_count_);
 | 
						|
    } else {
 | 
						|
      // Expected to read 2 full buffers of GetResponseBufferSize() and one
 | 
						|
      // partial buffer.
 | 
						|
      EXPECT_EQ(3U, filter_count_);
 | 
						|
    }
 | 
						|
    EXPECT_STREQ(input_.c_str(), received_content.c_str());
 | 
						|
 | 
						|
    // Input size and content size should match.
 | 
						|
    EXPECT_EQ(input_.size(), static_cast<size_t>(received_content_length));
 | 
						|
    EXPECT_EQ(input_.size(), received_content.size());
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  std::string input_;
 | 
						|
  bool limit_read_;
 | 
						|
};
 | 
						|
 | 
						|
const char kFindString[] = "REPLACE_THIS_STRING";
 | 
						|
const char kReplaceString[] = "This is the replaced string!";
 | 
						|
 | 
						|
// Helper for passing params to Write().
 | 
						|
#define WRITE_PARAMS data_out_ptr, data_out_size, data_out_written
 | 
						|
 | 
						|
// Replace all instances of |kFindString| with |kReplaceString|.
 | 
						|
// This implementation is similar to the example in
 | 
						|
// tests/shared/response_filter_test.cc.
 | 
						|
class ResponseFilterNeedMore : public ResponseFilterTestBase {
 | 
						|
 public:
 | 
						|
  ResponseFilterNeedMore()
 | 
						|
      : find_match_offset_(0U),
 | 
						|
        replace_overflow_size_(0U),
 | 
						|
        input_size_(0U),
 | 
						|
        repeat_ct_(0U) {}
 | 
						|
 | 
						|
  FilterStatus 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) override {
 | 
						|
    ResponseFilterTestBase::Filter(data_in, data_in_size, data_in_read,
 | 
						|
                                   data_out, data_out_size, data_out_written);
 | 
						|
 | 
						|
    // All data will be read.
 | 
						|
    data_in_read = data_in_size;
 | 
						|
 | 
						|
    const size_t find_size = sizeof(kFindString) - 1;
 | 
						|
 | 
						|
    const char* data_in_ptr = static_cast<char*>(data_in);
 | 
						|
    char* data_out_ptr = static_cast<char*>(data_out);
 | 
						|
 | 
						|
    // Reset the overflow.
 | 
						|
    std::string old_overflow;
 | 
						|
    if (!overflow_.empty()) {
 | 
						|
      old_overflow = overflow_;
 | 
						|
      overflow_.clear();
 | 
						|
    }
 | 
						|
 | 
						|
    const size_t likely_out_size =
 | 
						|
        data_in_size + replace_overflow_size_ + old_overflow.size();
 | 
						|
    if (data_out_size < likely_out_size) {
 | 
						|
      // We'll likely need to use the overflow buffer. Size it appropriately.
 | 
						|
      overflow_.reserve(likely_out_size - data_out_size);
 | 
						|
    }
 | 
						|
 | 
						|
    if (!old_overflow.empty()) {
 | 
						|
      // Write the overflow from last time.
 | 
						|
      Write(old_overflow.c_str(), old_overflow.size(), WRITE_PARAMS);
 | 
						|
    }
 | 
						|
 | 
						|
    // Evaluate each character in the input buffer. Track how many characters in
 | 
						|
    // a row match kFindString. If kFindString is completely matched then write
 | 
						|
    // kReplaceString. Otherwise, write the input characters as-is.
 | 
						|
    for (size_t i = 0U; i < data_in_size; ++i) {
 | 
						|
      if (data_in_ptr[i] == kFindString[find_match_offset_]) {
 | 
						|
        // Matched the next character in the find string.
 | 
						|
        if (++find_match_offset_ == find_size) {
 | 
						|
          // Complete match of the find string. Write the replace string.
 | 
						|
          Write(kReplaceString, sizeof(kReplaceString) - 1, WRITE_PARAMS);
 | 
						|
 | 
						|
          // Start over looking for a match.
 | 
						|
          find_match_offset_ = 0;
 | 
						|
        }
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      // Character did not match the find string.
 | 
						|
      if (find_match_offset_ > 0) {
 | 
						|
        // Write the portion of the find string that has matched so far.
 | 
						|
        Write(kFindString, find_match_offset_, WRITE_PARAMS);
 | 
						|
 | 
						|
        // Start over looking for a match.
 | 
						|
        find_match_offset_ = 0;
 | 
						|
      }
 | 
						|
 | 
						|
      // Write the current character.
 | 
						|
      Write(&data_in_ptr[i], 1, WRITE_PARAMS);
 | 
						|
    }
 | 
						|
 | 
						|
    // If a match is currently in-progress and input was provided then we need
 | 
						|
    // more data. Otherwise, we're done.
 | 
						|
    return find_match_offset_ > 0 && data_in_size > 0
 | 
						|
               ? RESPONSE_FILTER_NEED_MORE_DATA
 | 
						|
               : RESPONSE_FILTER_DONE;
 | 
						|
  }
 | 
						|
 | 
						|
  std::string GetInput() override {
 | 
						|
    const std::string& input =
 | 
						|
        CreateInput(std::string(kFindString) + " ",
 | 
						|
                    GetResponseBufferSize() * 2U + 1, &repeat_ct_);
 | 
						|
    input_size_ = input.size();
 | 
						|
 | 
						|
    const size_t find_size = sizeof(kFindString) - 1;
 | 
						|
    const size_t replace_size = sizeof(kReplaceString) - 1;
 | 
						|
 | 
						|
    // Determine a reasonable amount of space for find/replace overflow.
 | 
						|
    if (replace_size > find_size) {
 | 
						|
      replace_overflow_size_ = (replace_size - find_size) * repeat_ct_;
 | 
						|
    }
 | 
						|
 | 
						|
    return input;
 | 
						|
  }
 | 
						|
 | 
						|
  void VerifyOutput(cef_urlrequest_status_t status,
 | 
						|
                    int64_t received_content_length,
 | 
						|
                    const std::string& received_content) override {
 | 
						|
    ResponseFilterTestBase::VerifyOutput(status, received_content_length,
 | 
						|
                                         received_content);
 | 
						|
 | 
						|
    const std::string& output =
 | 
						|
        CreateOutput(std::string(kReplaceString) + " ", repeat_ct_);
 | 
						|
    EXPECT_STREQ(output.c_str(), received_content.c_str());
 | 
						|
 | 
						|
    // Pre-filter content length should be the original input size.
 | 
						|
    EXPECT_EQ(input_size_, static_cast<size_t>(received_content_length));
 | 
						|
 | 
						|
    // Filtered content length should be the output size.
 | 
						|
    EXPECT_EQ(output.size(), received_content.size());
 | 
						|
 | 
						|
    // Expected to read 2 full buffers of GetResponseBufferSize() and one
 | 
						|
    // partial buffer, and then one additional call to drain the overflow.
 | 
						|
    EXPECT_EQ(4U, filter_count_);
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  inline void Write(const char* str,
 | 
						|
                    size_t str_size,
 | 
						|
                    char*& data_out_ptr,
 | 
						|
                    size_t data_out_size,
 | 
						|
                    size_t& data_out_written) {
 | 
						|
    // Number of bytes remaining in the output buffer.
 | 
						|
    const size_t remaining_space = data_out_size - data_out_written;
 | 
						|
    // Maximum number of bytes we can write into the output buffer.
 | 
						|
    const size_t max_write = std::min(str_size, remaining_space);
 | 
						|
 | 
						|
    // Write the maximum portion that fits in the output buffer.
 | 
						|
    if (max_write == 1) {
 | 
						|
      // Small optimization for single character writes.
 | 
						|
      *data_out_ptr = str[0];
 | 
						|
      data_out_ptr += 1;
 | 
						|
      data_out_written += 1;
 | 
						|
    } else if (max_write > 1) {
 | 
						|
      memcpy(data_out_ptr, str, max_write);
 | 
						|
      data_out_ptr += max_write;
 | 
						|
      data_out_written += max_write;
 | 
						|
    }
 | 
						|
 | 
						|
    if (max_write < str_size) {
 | 
						|
      // Need to write more bytes than will fit in the output buffer. Store the
 | 
						|
      // remainder in the overflow buffer.
 | 
						|
      overflow_ += std::string(str + max_write, str_size - max_write);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // The portion of the find string that is currently matching.
 | 
						|
  size_t find_match_offset_;
 | 
						|
 | 
						|
  // The likely amount of overflow.
 | 
						|
  size_t replace_overflow_size_;
 | 
						|
 | 
						|
  // Overflow from the output buffer.
 | 
						|
  std::string overflow_;
 | 
						|
 | 
						|
  // The original input size.
 | 
						|
  size_t input_size_;
 | 
						|
 | 
						|
  // The number of times the find string was repeated.
 | 
						|
  size_t repeat_ct_;
 | 
						|
};
 | 
						|
 | 
						|
// Return a filter error.
 | 
						|
class ResponseFilterError : public ResponseFilterTestBase {
 | 
						|
 public:
 | 
						|
  ResponseFilterError() {}
 | 
						|
 | 
						|
  FilterStatus 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) override {
 | 
						|
    ResponseFilterTestBase::Filter(data_in, data_in_size, data_in_read,
 | 
						|
                                   data_out, data_out_size, data_out_written);
 | 
						|
 | 
						|
    return RESPONSE_FILTER_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  std::string GetInput() override {
 | 
						|
    return kInputHeader + std::string("ERROR") + kInputFooter;
 | 
						|
  }
 | 
						|
 | 
						|
  void VerifyOutput(cef_urlrequest_status_t status,
 | 
						|
                    int64_t received_content_length,
 | 
						|
                    const std::string& received_content) override {
 | 
						|
    ResponseFilterTestBase::VerifyOutput(status, received_content_length,
 | 
						|
                                         received_content);
 | 
						|
 | 
						|
    EXPECT_EQ(UR_FAILED, status);
 | 
						|
 | 
						|
    // Expect empty content.
 | 
						|
    EXPECT_STREQ("", received_content.c_str());
 | 
						|
    EXPECT_EQ(0U, received_content_length);
 | 
						|
 | 
						|
    // Expect to only be called one time.
 | 
						|
    EXPECT_EQ(filter_count_, 1U);
 | 
						|
  }
 | 
						|
 | 
						|
  void VerifyStatusCode(int httpStatusCode) const override {
 | 
						|
    EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, httpStatusCode);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
class ResponseFilterTestHandler : public TestHandler {
 | 
						|
 public:
 | 
						|
  explicit ResponseFilterTestHandler(
 | 
						|
      CefRefPtr<ResponseFilterTestBase> response_filter)
 | 
						|
      : response_filter_(response_filter) {}
 | 
						|
 | 
						|
  void RunTest() override {
 | 
						|
    const std::string& resource = response_filter_->GetInput();
 | 
						|
    AddResource(kResponseFilterTestUrl, resource, "text/html");
 | 
						|
 | 
						|
    // Create the browser.
 | 
						|
    CreateBrowser(kResponseFilterTestUrl);
 | 
						|
 | 
						|
    // Time out the test after a reasonable period of time.
 | 
						|
    SetTestTimeout();
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
 | 
						|
      CefRefPtr<CefBrowser> browser,
 | 
						|
      CefRefPtr<CefFrame> frame,
 | 
						|
      CefRefPtr<CefRequest> request,
 | 
						|
      CefRefPtr<CefResponse> response) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
 | 
						|
    EXPECT_FALSE(got_resource_response_filter_);
 | 
						|
    got_resource_response_filter_.yes();
 | 
						|
    return response_filter_;
 | 
						|
  }
 | 
						|
 | 
						|
  void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
 | 
						|
                              CefRefPtr<CefFrame> frame,
 | 
						|
                              CefRefPtr<CefRequest> request,
 | 
						|
                              CefRefPtr<CefResponse> response,
 | 
						|
                              URLRequestStatus status,
 | 
						|
                              int64_t received_content_length) override {
 | 
						|
    EXPECT_IO_THREAD();
 | 
						|
 | 
						|
    if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
 | 
						|
      // Ignore favicon requests.
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    EXPECT_FALSE(got_resource_load_complete_);
 | 
						|
    got_resource_load_complete_.yes();
 | 
						|
 | 
						|
    status_ = status;
 | 
						|
    received_content_length_ = received_content_length;
 | 
						|
  }
 | 
						|
 | 
						|
  void OnLoadEnd(CefRefPtr<CefBrowser> browser,
 | 
						|
                 CefRefPtr<CefFrame> frame,
 | 
						|
                 int httpStatusCode) override {
 | 
						|
    EXPECT_FALSE(got_load_end_);
 | 
						|
    got_load_end_.yes();
 | 
						|
 | 
						|
    response_filter_->VerifyStatusCode(httpStatusCode);
 | 
						|
 | 
						|
    GetOutputContent(frame);
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  // Retrieve the output content using a StringVisitor. This effectively
 | 
						|
  // serializes the DOM from the renderer process so any comparison to the
 | 
						|
  // filter output is somewhat error-prone.
 | 
						|
  void GetOutputContent(CefRefPtr<CefFrame> frame) {
 | 
						|
    class StringVisitor : public CefStringVisitor {
 | 
						|
     public:
 | 
						|
      using VisitorCallback =
 | 
						|
          base::OnceCallback<void(const std::string& /*received_content*/)>;
 | 
						|
 | 
						|
      explicit StringVisitor(VisitorCallback callback)
 | 
						|
          : callback_(std::move(callback)) {}
 | 
						|
 | 
						|
      void Visit(const CefString& string) override {
 | 
						|
        std::move(callback_).Run(string);
 | 
						|
      }
 | 
						|
 | 
						|
     private:
 | 
						|
      VisitorCallback callback_;
 | 
						|
 | 
						|
      IMPLEMENT_REFCOUNTING(StringVisitor);
 | 
						|
    };
 | 
						|
 | 
						|
    frame->GetSource(new StringVisitor(
 | 
						|
        base::BindOnce(&ResponseFilterTestHandler::VerifyOutput, this)));
 | 
						|
  }
 | 
						|
 | 
						|
  void VerifyOutput(const std::string& received_content) {
 | 
						|
    response_filter_->VerifyOutput(status_, received_content_length_,
 | 
						|
                                   received_content);
 | 
						|
    response_filter_ = nullptr;
 | 
						|
 | 
						|
    DestroyTest();
 | 
						|
  }
 | 
						|
 | 
						|
  void DestroyTest() override {
 | 
						|
    EXPECT_TRUE(got_resource_response_filter_);
 | 
						|
    EXPECT_TRUE(got_resource_load_complete_);
 | 
						|
    EXPECT_TRUE(got_load_end_);
 | 
						|
 | 
						|
    TestHandler::DestroyTest();
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<ResponseFilterTestBase> response_filter_;
 | 
						|
 | 
						|
  TrackCallback got_resource_response_filter_;
 | 
						|
  TrackCallback got_resource_load_complete_;
 | 
						|
  TrackCallback got_load_end_;
 | 
						|
 | 
						|
  URLRequestStatus status_;
 | 
						|
  int64_t received_content_length_;
 | 
						|
 | 
						|
  IMPLEMENT_REFCOUNTING(ResponseFilterTestHandler);
 | 
						|
};
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
// Pass through contents unchanged. Read all available input.
 | 
						|
TEST(ResourceRequestHandlerTest, FilterPassThruReadAll) {
 | 
						|
  CefRefPtr<ResponseFilterTestHandler> handler =
 | 
						|
      new ResponseFilterTestHandler(new ResponseFilterPassThru(false));
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
// Pass through contents unchanged. Read limited input.
 | 
						|
TEST(ResourceRequestHandlerTest, FilterPassThruReadLimited) {
 | 
						|
  CefRefPtr<ResponseFilterTestHandler> handler =
 | 
						|
      new ResponseFilterTestHandler(new ResponseFilterPassThru(true));
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
// Find/replace contents such that we occasionally need more data.
 | 
						|
TEST(ResourceRequestHandlerTest, FilterNeedMore) {
 | 
						|
  CefRefPtr<ResponseFilterTestHandler> handler =
 | 
						|
      new ResponseFilterTestHandler(new ResponseFilterNeedMore());
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
// Error during filtering.
 | 
						|
TEST(ResourceRequestHandlerTest, FilterError) {
 | 
						|
  CefRefPtr<ResponseFilterTestHandler> handler =
 | 
						|
      new ResponseFilterTestHandler(new ResponseFilterError());
 | 
						|
  handler->ExecuteTest();
 | 
						|
  ReleaseAndWaitForDestructor(handler);
 | 
						|
}
 | 
						|
 | 
						|
// Entry point for registering custom schemes.
 | 
						|
// Called from client_app_delegates.cc.
 | 
						|
void RegisterResourceRequestHandlerCustomSchemes(
 | 
						|
    CefRawPtr<CefSchemeRegistrar> registrar) {
 | 
						|
  // Add a custom standard scheme.
 | 
						|
  registrar->AddCustomScheme(
 | 
						|
      "rrhcustom", CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_CORS_ENABLED);
 | 
						|
}
 |