cef/tests/ceftests/plugin_unittest.cc

642 lines
22 KiB
C++
Raw Normal View History

// Copyright (c) 2015 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 "include/base/cef_bind.h"
#include "include/cef_pack_resources.h"
Implement NetworkService request interception/handling (see issue #2622). Implementation notes: - Chromium change: CookieMonster::SetCookieableSchemes needs to be called immediately after the CookieMonster is created in NetworkContext:: ApplyContextParamsToBuilder. Add a Profile::GetCookieableSchemes method and NetworkContextParams.cookieable_schemes member (set from ProfileNetworkContextService::CreateNetworkContextParams) to support that. - Chromium change: Add a ContentBrowserClient::HandleExternalProtocol variant that exposes additional NetworkService request information. - GetResourceResponseFilter is not yet implemented. API changes: - Resource-related callbacks have been moved from CefRequestHandler to a new CefResourceRequestHandler interface which is returned via the GetResourceRequestHandler method. If the CefRequestHandler declines to handle a resource it can optionally be handled by the CefRequestContextHandler, if any, associated with the loading context. - The OnProtocolExecution callback has been moved from CefRequestHandler to CefResourceRequestHandler and will be called if a custom scheme request is unhandled. - Cookie send/save permission callbacks have been moved from CefRequestHandler and CefResourceHandler to CefResourceRequestHandler. - New methods added to CefResourceHandler that better match NetworkService execution sequence expectations. The old methods are now deprecated. - New methods added to CefRequest and CefResponse. Known behavior changes with the NetworkService implementation: - Modifying the |new_url| parameter in OnResourceRedirect will no longer result in the method being called an additional time (likely a bug in the old implementation). - Modifying the request URL in OnResourceResponse would previously cause a redirect. This behavior is now deprecated because the NetworkService does not support this functionality when using default network loaders. Temporary support has been added in combination with CefResourceHandler usage only. - Other changes to the request object in OnResourceResponse will now cause the request to be restarted. This means that OnBeforeResourceLoad, etc, will be called an additional time with the new request information. - CefResponse::GetMimeType will now be empty for non-200 responses. - Requests using custom schemes can now be handled via CefResourceRequestHandler with the same callback behavior as builtin schemes. - Redirects of custom scheme requests will now be followed as expected. - Default handling of builtin schemes can now be disabled by setting |disable_default_handling| to true in GetResourceRequestHandler. - Unhandled requests (custom scheme or builtin scheme with default handling disabled) will fail with an CefResponse::GetError value of ERR_UNKNOWN_URL_SCHEME. - The CefSchemeHandlerFactory::Create callback will now include cookie headers. To test: - Run `cefclient --enable-network-service`. All resources should load successfully (this tests the transparent proxy capability). - All tests pass with NetworkService disabled. - The following tests pass with NetworkService enabled: - CookieTest.* - FrameTest.* (excluding .*Nav) - NavigationTest.* (excluding .Redirect*) - RequestHandlerTest.* - RequestContextTest.Basic* - RequestContextTest.Popup* - RequestTest.* - ResourceManagerTest.* - ResourceRequestHandlerTest.* (excluding .Filter*) - SchemeHandlerTest.* - StreamResourceHandlerTest.*
2019-04-24 04:50:25 +02:00
#include "include/cef_request_context_handler.h"
#include "include/cef_resource_bundle.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/gtest/include/gtest/gtest.h"
#include "tests/shared/browser/client_app_browser.h"
#include "tests/shared/browser/resource_util.h"
namespace {
std::string GetDataResourceAsString(int resource_id) {
void* data;
size_t data_size;
if (CefResourceBundle::GetGlobal()->GetDataResource(resource_id, data,
data_size)) {
return std::string(static_cast<char*>(data), data_size);
}
return std::string();
}
// Browser-side app delegate.
class PluginBrowserTest : public client::ClientAppBrowser::Delegate {
public:
PluginBrowserTest() {}
void OnBeforeCommandLineProcessing(
CefRefPtr<client::ClientAppBrowser> app,
CefRefPtr<CefCommandLine> command_line) override {
// Allow all plugin loading by default.
command_line->AppendSwitchWithValue("plugin-policy", "allow");
}
private:
IMPLEMENT_REFCOUNTING(PluginBrowserTest);
};
const char kPdfTestOrigin[] = "http://tests/";
const char kPdfHtmlUrl[] = "http://tests/pdf.html";
const char kPdfDirectUrl[] = "http://tests/pdf.pdf";
// Delay waiting for the plugin placeholder to load.
const int64 kPlaceholderLoadDelayMs = 1000;
// Delay waiting for iframe tests to load the PDF file.
#if defined(OS_LINUX)
const int64 kPdfLoadDelayMs = 7000;
#else
const int64 kPdfLoadDelayMs = 5000;
#endif
// Browser-side test handler.
class PluginTestHandler : public RoutingTestHandler,
public CefContextMenuHandler {
public:
enum Mode {
// No specified context or handler (implicitly uses the global context).
GLOBAL_DEFAULT,
// Global context with no handler.
GLOBAL_NO_HANDLER,
// Global context with handler that allows plugin load.
GLOBAL_ALLOW,
// Global context with handler that blocks plugin load. Then, load the
// plugin via the context menu.
GLOBAL_BLOCK_LOAD,
// Global context with handler that blocks plugin load. Then, hide the
// plugin via the context menu.
GLOBAL_BLOCK_HIDE,
// Global context with handler that disables plugin load. Then, hide the
// plugin via the context menu.
GLOBAL_DISABLE_HIDE,
// Global context with handler that removes the plugin from the
// `navigator.plugins` list and consequently disables plugin load.
GLOBAL_NO_LIST,
// Custom context with no handler.
CUSTOM_NO_HANDLER,
// Custom context with handler that allows plugin load.
CUSTOM_ALLOW,
// Custom context with handler that blocks plugin load. Then, load the
// plugin via the context menu.
CUSTOM_BLOCK_LOAD,
// Custom context with handler that blocks plugin load. Then, hide the
// plugin via the context menu.
CUSTOM_BLOCK_HIDE,
// Custom context with handler that disables plugin load. Then, hide the
// plugin via the context menu.
CUSTOM_DISABLE_HIDE,
// Custom context with handler that removes the plugin from the
// `navigator.plugins` list and consequently disables plugin load.
CUSTOM_NO_LIST,
};
class RequestContextHandler : public CefRequestContextHandler {
public:
explicit RequestContextHandler(PluginTestHandler* handler)
: handler_(handler) {}
bool OnBeforePluginLoad(const CefString& mime_type,
const CefString& plugin_url,
bool is_main_frame,
const CefString& top_origin_url,
CefRefPtr<CefWebPluginInfo> plugin_info,
PluginPolicy* plugin_policy) override {
const std::string& mime_type_str = mime_type;
EXPECT_STREQ("application/pdf", mime_type_str.c_str());
EXPECT_STREQ("chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/",
plugin_info->GetPath().ToString().c_str());
if (top_origin_url.empty()) {
if (!handler_->got_on_before_plugin_empty_origin_) {
// Checking for PDF support in the plugin frame (navigator.plugins
// listing, pdf load, etc).
handler_->got_on_before_plugin_empty_origin_.yes();
} else if (handler_->HasNoList()) {
// When listing is disabled there should be an additional check in the
// main frame for the navigator.plugins listing.
if (!handler_->got_on_before_plugin_empty_origin2_) {
EXPECT_TRUE(is_main_frame);
handler_->got_on_before_plugin_empty_origin2_.yes();
}
}
if (handler_->HasNoList()) {
// Remove the PDF plugin from the `navigator.plugins` list.
*plugin_policy = PLUGIN_POLICY_DISABLE;
return true;
}
// Ignore requests for building the plugin list.
return false;
}
// Should only get requests for the test origin.
EXPECT_STREQ(kPdfTestOrigin, top_origin_url.ToString().c_str());
if (!handler_->got_on_before_plugin_load_pdf_)
handler_->got_on_before_plugin_load_pdf_.yes();
else
NOTREACHED();
if (handler_->HasAllow()) {
*plugin_policy = PLUGIN_POLICY_ALLOW;
return true;
} else if (handler_->HasBlock()) {
*plugin_policy = PLUGIN_POLICY_BLOCK;
return true;
} else if (handler_->HasDisable()) {
*plugin_policy = PLUGIN_POLICY_DISABLE;
return true;
}
return false;
}
void Detach() { handler_ = NULL; }
private:
PluginTestHandler* handler_;
IMPLEMENT_REFCOUNTING(RequestContextHandler);
};
PluginTestHandler(Mode mode, const std::string& url)
: mode_(mode), url_(url) {}
// Loading the PDF directly in the main frame instead of a sub-frame.
bool HasDirectPluginLoad() const { return url_ == kPdfDirectUrl; }
// Has a specified RequestContext but not necessarily a custom handler.
bool HasRequestContext() const { return mode_ != GLOBAL_DEFAULT; }
// Has a specified RequestContext and custom handler.
bool HasRequestContextHandler() const {
return mode_ != GLOBAL_DEFAULT && mode_ != GLOBAL_NO_HANDLER &&
mode_ != CUSTOM_NO_HANDLER;
}
// Using the global request context, either directly or with a custom handler.
bool HasGlobalRequestContext() const {
return mode_ >= GLOBAL_DEFAULT && mode_ <= GLOBAL_NO_LIST;
}
// Should allow the plugin load via the custom handler.
bool HasAllow() const {
return mode_ == GLOBAL_ALLOW || mode_ == CUSTOM_ALLOW;
}
// Should block the plugin load via the custom handler.
bool HasBlock() const {
return mode_ == GLOBAL_BLOCK_LOAD || mode_ == GLOBAL_BLOCK_HIDE ||
mode_ == CUSTOM_BLOCK_LOAD || mode_ == CUSTOM_BLOCK_HIDE;
}
// Should disable the plugin load via the custom handler.
bool HasDisable() const {
return mode_ == GLOBAL_DISABLE_HIDE || mode_ == CUSTOM_DISABLE_HIDE;
}
// Should exclude the plugin from the `navigator.plugins` list.
bool HasNoList() const {
return mode_ == GLOBAL_NO_LIST || mode_ == CUSTOM_NO_LIST;
}
// Should load the plugin via the context menu.
bool HasContextLoad() const {
return mode_ == GLOBAL_BLOCK_LOAD || mode_ == CUSTOM_BLOCK_LOAD;
}
// Should hide the plugin via the context menu.
bool HasContextHide() const {
return mode_ == GLOBAL_BLOCK_HIDE || mode_ == GLOBAL_DISABLE_HIDE ||
mode_ == CUSTOM_BLOCK_HIDE || mode_ == CUSTOM_DISABLE_HIDE;
}
std::string GetPluginNode() const {
return "document.getElementsByTagName('embed')[0]";
}
void WaitForNavigatorPlugins(CefRefPtr<CefFrame> frame) const {
// Test if the `navigator.plugins` list includes the PDF extension.
const std::string& code =
" if (navigator.plugins['Chrome PDF Viewer'].filename == "
" 'mhjfbmdgcfjbbpaeojofohoefgiehjai') {"
" window.testQuery({request:'pdf_plugin_found'});"
"} else {"
" window.testQuery({request:'pdf_plugin_missing'});"
"}";
frame->ExecuteJavaScript(code, frame->GetURL(), 0);
}
void WaitForPlaceholderLoad(CefRefPtr<CefFrame> frame) {
// Waits for the placeholder to load.
CefPostDelayedTask(TID_UI,
base::Bind(&PluginTestHandler::TriggerContextMenu, this,
frame->GetBrowser()),
kPlaceholderLoadDelayMs);
}
void WaitForPlaceholderHide(CefRefPtr<CefFrame> frame) const {
// Waits for the placeholder to be hidden (style set to display:none).
// See PluginPlaceholderBase::HidePlugin.
const std::string& code =
"var plugin = " + GetPluginNode() +
";"
"var observer = new MutationObserver(function(mutations) {"
" mutations.forEach(function(mutationRecord) {"
" window.testQuery({request:'placeholder_hidden'});"
" observer.disconnect();"
" });"
"});"
"observer.observe(plugin, "
" { attributes : true, attributeFilter : ['style'] });";
frame->ExecuteJavaScript(code, frame->GetURL(), 0);
}
void WaitForPluginLoad(CefRefPtr<CefFrame> frame) {
if (url_ == kPdfHtmlUrl) {
// PDFScriptingAPI does not work with iframes (the LoadCallback will
// never be executed). Use a timeout instead.
if (got_context_menu_dismissed_) {
// After context menu display. Destroy the test.
CefPostDelayedTask(TID_UI,
base::Bind(&PluginTestHandler::DestroyTest, this),
kPdfLoadDelayMs);
} else {
// Trigger the context menu.
CefPostDelayedTask(TID_UI,
base::Bind(&PluginTestHandler::TriggerContextMenu,
this, frame->GetBrowser()),
kPdfLoadDelayMs);
}
return;
}
// Wait for the PDF file to load.
// See chrome/browser/pdf/pdf_extension_test_util.cc.
const std::string& scripting_api_js =
GetDataResourceAsString(IDR_PDF_PDF_SCRIPTING_API_JS);
EXPECT_TRUE(!scripting_api_js.empty());
frame->ExecuteJavaScript(scripting_api_js, frame->GetURL(), 0);
const std::string& code =
"var scriptingAPI = new PDFScriptingAPI(window, " + GetPluginNode() +
");"
"scriptingAPI.setLoadCallback(function(success) {"
" window.testQuery({request:'plugin_ready'});"
"});";
frame->ExecuteJavaScript(code, frame->GetURL(), 0);
}
void EndTest() {
CefPostTask(TID_UI, base::Bind(&PluginTestHandler::DestroyTest, this));
}
CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() override {
return this;
}
void RunTest() override {
CefRefPtr<CefRequestContext> request_context;
if (HasRequestContext()) {
if (HasRequestContextHandler())
context_handler_ = new RequestContextHandler(this);
if (HasGlobalRequestContext()) {
// Use the global request context.
request_context = CefRequestContext::CreateContext(
CefRequestContext::GetGlobalContext(), context_handler_.get());
} else {
// Create the request context that will use an in-memory cache.
CefRequestContextSettings settings;
request_context =
CefRequestContext::CreateContext(settings, context_handler_.get());
}
}
// Create the browser.
CreateBrowser(url_, request_context);
// Time out the test after a reasonable period of time.
SetTestTimeout(5000 + kPdfLoadDelayMs);
}
CefRefPtr<CefResourceHandler> GetResourceHandler(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) override {
const std::string& url = request->GetURL();
if (url == kPdfHtmlUrl) {
CefRefPtr<CefStreamReader> stream =
client::GetBinaryResourceReader("pdf.html");
return new CefStreamResourceHandler("text/html", stream);
} else if (url == kPdfDirectUrl) {
CefRefPtr<CefStreamReader> stream =
client::GetBinaryResourceReader("pdf.pdf");
return new CefStreamResourceHandler("application/pdf", stream);
}
return NULL;
}
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) override {
bool is_pdf1 = false;
const std::string& url = frame->GetURL();
if (url == kPdfHtmlUrl) {
if (!got_on_load_end_html_)
got_on_load_end_html_.yes();
else
NOTREACHED();
} else if (url == kPdfDirectUrl) {
if (!got_on_load_end_pdf1_) {
got_on_load_end_pdf1_.yes();
is_pdf1 = true;
} else if (!got_on_load_end_pdf2_) {
got_on_load_end_pdf2_.yes();
} else {
NOTREACHED();
}
} else {
NOTREACHED();
}
if (HasNoList()) {
// If the plugin is not listed then the PDF documents will never load.
EXPECT_STREQ(kPdfHtmlUrl, url.c_str());
WaitForNavigatorPlugins(frame);
} else if (is_pdf1) {
// The first PDF document has loaded.
WaitForNavigatorPlugins(frame);
}
}
bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) override {
if (request == "pdf_plugin_found" || request == "pdf_plugin_missing") {
if (request == "pdf_plugin_found")
got_pdf_plugin_found_.yes();
else
got_pdf_plugin_missing_.yes();
if (HasNoList()) {
// The plugin will not load. End the test.
EndTest();
} else if (HasBlock() || HasDisable()) {
// Wait for the plugin placeholder for the first PDF file to load. The
// test will continue from OnQuery.
WaitForPlaceholderLoad(frame);
} else {
// Wait for the first PDF file to load.
WaitForPluginLoad(frame);
}
} else if (request == "placeholder_hidden") {
EXPECT_FALSE(got_placeholder_hidden_);
got_placeholder_hidden_.yes();
// The plugin placeholder has been hidden. End the test.
EndTest();
} else if (request == "plugin_ready") {
EXPECT_FALSE(got_plugin_ready_);
got_plugin_ready_.yes();
// The plugin has loaded the PDF file.
if (got_context_menu_dismissed_) {
// After context menu display. End the test.
EndTest();
} else {
// Trigger the context menu.
CefPostTask(TID_UI, base::Bind(&PluginTestHandler::TriggerContextMenu,
this, browser));
}
} else {
NOTREACHED();
}
return true;
}
void TriggerContextMenu(CefRefPtr<CefBrowser> browser) {
CefMouseEvent mouse_event;
// Somewhere in the first plugin.
mouse_event.x = 100;
mouse_event.y = 100;
// Send right-click mouse down and mouse up to tigger context menu.
browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, false, 0);
browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, true, 0);
}
bool RunContextMenu(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefContextMenuParams> params,
CefRefPtr<CefMenuModel> model,
CefRefPtr<CefRunContextMenuCallback> callback) override {
EXPECT_FALSE(got_run_context_menu_);
got_run_context_menu_.yes();
if (HasContextLoad() || HasContextHide()) {
// Should have 4 elements -- plugin name, separator, run, hide.
EXPECT_EQ(4, model->GetCount());
int command_id;
if (HasContextLoad()) {
// Execute the run command.
command_id = model->GetCommandIdAt(2);
} else {
// Wait for the plugin to be hidden.
WaitForPlaceholderHide(frame);
// Execute the hide command.
command_id = model->GetCommandIdAt(3);
}
EXPECT_GE(command_id, MENU_ID_CUSTOM_FIRST);
EXPECT_LE(command_id, MENU_ID_CUSTOM_LAST);
callback->Continue(command_id, static_cast<EventFlags>(0));
} else {
// Do nothing with the context menu.
callback->Cancel();
}
return true;
}
void OnContextMenuDismissed(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame) override {
EXPECT_FALSE(got_context_menu_dismissed_);
got_context_menu_dismissed_.yes();
if (HasContextHide()) {
// Nothing to do here. The test will continue from OnQuery.
return;
}
if (HasContextLoad()) {
// Wait for the PDF plugin to load.
WaitForPluginLoad(frame);
return;
}
EndTest();
}
void DestroyTest() override {
if (context_handler_.get()) {
context_handler_->Detach();
context_handler_ = NULL;
}
if (HasContextHide()) {
EXPECT_TRUE(got_placeholder_hidden_);
EXPECT_FALSE(got_plugin_ready_);
} else {
EXPECT_FALSE(got_placeholder_hidden_);
if (url_ == kPdfDirectUrl)
EXPECT_TRUE(got_plugin_ready_);
else
EXPECT_FALSE(got_plugin_ready_);
}
if (HasRequestContextHandler())
EXPECT_TRUE(got_on_before_plugin_empty_origin_);
else
EXPECT_FALSE(got_on_before_plugin_empty_origin_);
if (HasNoList()) {
EXPECT_TRUE(got_on_before_plugin_empty_origin2_);
EXPECT_FALSE(got_pdf_plugin_found_);
EXPECT_TRUE(got_pdf_plugin_missing_);
EXPECT_FALSE(got_run_context_menu_);
EXPECT_FALSE(got_context_menu_dismissed_);
} else {
EXPECT_FALSE(got_on_before_plugin_empty_origin2_);
EXPECT_TRUE(got_pdf_plugin_found_);
EXPECT_FALSE(got_pdf_plugin_missing_);
EXPECT_TRUE(got_run_context_menu_);
EXPECT_TRUE(got_context_menu_dismissed_);
}
if (url_ == kPdfHtmlUrl) {
// The HTML file will load the PDF twice in iframes.
EXPECT_TRUE(got_on_load_end_html_);
if (!HasNoList()) {
EXPECT_TRUE(got_on_load_end_pdf1_);
EXPECT_TRUE(got_on_load_end_pdf2_);
if (HasRequestContextHandler()) {
EXPECT_TRUE(got_on_before_plugin_load_pdf_);
}
}
} else if (url_ == kPdfDirectUrl) {
// Load the PDF file directly.
EXPECT_FALSE(got_on_load_end_html_);
EXPECT_TRUE(got_on_load_end_pdf1_);
EXPECT_FALSE(got_on_load_end_pdf2_);
if (HasRequestContextHandler()) {
EXPECT_TRUE(got_on_before_plugin_load_pdf_);
}
} else {
NOTREACHED();
}
if (!HasRequestContextHandler() || HasNoList()) {
EXPECT_FALSE(got_on_before_plugin_load_pdf_);
}
TestHandler::DestroyTest();
}
const Mode mode_;
const std::string url_;
TrackCallback got_on_before_plugin_empty_origin_;
TrackCallback got_on_before_plugin_empty_origin2_;
TrackCallback got_on_before_plugin_load_pdf_;
TrackCallback got_on_load_end_html_;
TrackCallback got_on_load_end_pdf1_;
TrackCallback got_on_load_end_pdf2_;
TrackCallback got_pdf_plugin_found_;
TrackCallback got_pdf_plugin_missing_;
TrackCallback got_placeholder_hidden_;
TrackCallback got_plugin_ready_;
TrackCallback got_run_context_menu_;
TrackCallback got_context_menu_dismissed_;
CefRefPtr<RequestContextHandler> context_handler_;
IMPLEMENT_REFCOUNTING(PluginTestHandler);
};
} // namespace
#define RUN_TEST(name, type, url) \
TEST(PluginTest, name) { \
CefRefPtr<PluginTestHandler> handler = \
new PluginTestHandler(PluginTestHandler::type, url); \
handler->ExecuteTest(); \
ReleaseAndWaitForDestructor(handler); \
}
RUN_TEST(GlobalDefaultPdfDirect, GLOBAL_DEFAULT, kPdfDirectUrl)
RUN_TEST(GlobalDefaultPdfHtml, GLOBAL_DEFAULT, kPdfHtmlUrl)
RUN_TEST(GlobalNoHandlerPdfDirect, GLOBAL_NO_HANDLER, kPdfDirectUrl)
RUN_TEST(GlobalNoHandlerPdfHtml, GLOBAL_NO_HANDLER, kPdfHtmlUrl)
RUN_TEST(GlobalAllowPdfDirect, GLOBAL_ALLOW, kPdfDirectUrl)
RUN_TEST(GlobalAllowPdfHtml, GLOBAL_ALLOW, kPdfHtmlUrl)
RUN_TEST(GlobalBlockThenLoadPdfDirect, GLOBAL_BLOCK_LOAD, kPdfDirectUrl)
RUN_TEST(GlobalBlockThenLoadPdfHtml, GLOBAL_BLOCK_LOAD, kPdfHtmlUrl)
RUN_TEST(GlobalBlockThenHidePdfDirect, GLOBAL_BLOCK_HIDE, kPdfDirectUrl)
RUN_TEST(GlobalBlockThenHidePdfHtml, GLOBAL_BLOCK_HIDE, kPdfHtmlUrl)
RUN_TEST(GlobalDisableThenHidePdfDirect, GLOBAL_DISABLE_HIDE, kPdfDirectUrl)
RUN_TEST(GlobalDisableThenHidePdfHtml, GLOBAL_DISABLE_HIDE, kPdfHtmlUrl)
RUN_TEST(GlobalNoListHtml, GLOBAL_NO_LIST, kPdfHtmlUrl)
RUN_TEST(CustomNoHandlerPdfDirect, CUSTOM_NO_HANDLER, kPdfDirectUrl)
RUN_TEST(CustomNoHandlerPdfHtml, CUSTOM_NO_HANDLER, kPdfHtmlUrl)
RUN_TEST(CustomAllowPdfDirect, CUSTOM_ALLOW, kPdfDirectUrl)
RUN_TEST(CustomAllowPdfHtml, CUSTOM_ALLOW, kPdfHtmlUrl)
RUN_TEST(CustomBlockThenLoadPdfDirect, CUSTOM_BLOCK_LOAD, kPdfDirectUrl)
RUN_TEST(CustomBlockThenLoadPdfHtml, CUSTOM_BLOCK_LOAD, kPdfHtmlUrl)
RUN_TEST(CustomBlockThenHidePdfDirect, CUSTOM_BLOCK_HIDE, kPdfDirectUrl)
RUN_TEST(CustomBlockThenHidePdfHtml, CUSTOM_BLOCK_HIDE, kPdfHtmlUrl)
RUN_TEST(CustomDisableThenHidePdfDirect, CUSTOM_DISABLE_HIDE, kPdfDirectUrl)
RUN_TEST(CustomDisableThenHidePdfHtml, CUSTOM_DISABLE_HIDE, kPdfHtmlUrl)
RUN_TEST(CustomNoListHtml, CUSTOM_NO_LIST, kPdfHtmlUrl)
// Entry point for creating plugin browser test objects.
// Called from client_app_delegates.cc.
void CreatePluginBrowserTests(
client::ClientAppBrowser::DelegateSet& delegates) {
delegates.insert(new PluginBrowserTest);
}