Commit 9325d7ca authored by raymes's avatar raymes Committed by Commit bot

Allow URL requests for object/embed tags to be intercepted as streams.

BrowserPlugins make URL requests on behalf of object tags. Requests on behalf of
object tags should be treated in a similar way to requests in behalf of frames
in that they are allowed to be intercepted as a stream request, however unlike frames they should never be downloaded. This CL allows
these requests to be intercepted in that way.

BUG=416310
TBR=mkosiba@chromium.org,benwells@chromium.org

Review URL: https://codereview.chromium.org/694773003

Cr-Commit-Position: refs/heads/master@{#305130}
parent 991568bb
......@@ -138,6 +138,7 @@ TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest, TestHideRequestForURL) {
MSG_ROUTING_NONE,
false, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
false); // is_async
extension_info_map_->RegisterExtensionProcess(
extensions::kWebStoreAppId, process_id, site_instance_id);
......@@ -158,6 +159,7 @@ TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest, TestHideRequestForURL) {
MSG_ROUTING_NONE,
false, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
false); // is_async
EXPECT_TRUE(WebRequestPermissions::HideRequest(
extension_info_map_.get(), sensitive_request.get()));
......
......@@ -136,6 +136,7 @@ class ExtensionProtocolTest : public testing::Test {
-1, // render_frame_id
resource_type == content::RESOURCE_TYPE_MAIN_FRAME, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
false); // is_async
request->Start();
base::MessageLoop::current()->Run();
......
......@@ -235,6 +235,7 @@ TEST_F(PrerenderTrackerTest, PrerenderThrottledRedirectResume) {
MSG_ROUTING_NONE,
false, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
true); // is_async
// Install a prerender throttle.
......@@ -281,6 +282,7 @@ TEST_F(PrerenderTrackerTest, PrerenderThrottledRedirectMainFrame) {
MSG_ROUTING_NONE,
true, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
true); // is_async
// Install a prerender throttle.
......@@ -325,6 +327,7 @@ TEST_F(PrerenderTrackerTest, PrerenderThrottledRedirectSyncXHR) {
MSG_ROUTING_NONE,
false, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
false); // is_async
// Install a prerender throttle.
......
......@@ -86,6 +86,7 @@ class OffDomainInclusionDetectorTest : public testing::Test {
MSG_ROUTING_NONE, // render_frame_id
is_main_frame, // is_main_frame
parent_is_main_frame, // parent_is_main_frame
true, // allow_download
false); // is_async
return url_request.Pass();
......
......@@ -110,6 +110,7 @@ class IframeSourceTest : public testing::Test {
MSG_ROUTING_NONE,
false, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
false); // is_async
}
return request.Pass();
......
......@@ -131,6 +131,7 @@ class TestIOThreadState {
render_frame_id,
true, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
false); // is_async
}
throttle_.reset(new InterceptNavigationResourceThrottle(
......
......@@ -312,9 +312,27 @@ bool BufferedResourceHandler::SelectNextHandler(bool* defer) {
return UseAlternateNextHandler(handler.Pass(), std::string());
}
// Allow requests for object/embed tags to be intercepted as streams.
if (info->GetResourceType() == content::RESOURCE_TYPE_OBJECT) {
DCHECK(!info->allow_download());
std::string payload;
scoped_ptr<ResourceHandler> handler(
host_->MaybeInterceptAsStream(request(), response_.get(), &payload));
if (handler) {
DCHECK(!net::IsSupportedMimeType(mime_type));
return UseAlternateNextHandler(handler.Pass(), payload);
}
}
if (!info->allow_download())
return true;
// info->allow_download() == true implies
// info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME or
// info->GetResourceType() == RESOURCE_TYPE_SUB_FRAME.
DCHECK(info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME ||
info->GetResourceType() == RESOURCE_TYPE_SUB_FRAME);
bool must_download = MustDownload();
if (!must_download) {
if (net::IsSupportedMimeType(mime_type))
......
......@@ -10,6 +10,7 @@
#include "base/memory/weak_ptr.h"
#include "content/browser/loader/layered_resource_handler.h"
#include "content/common/content_export.h"
#include "content/public/browser/resource_controller.h"
namespace net {
......@@ -21,7 +22,7 @@ class ResourceDispatcherHostImpl;
struct WebPluginInfo;
// Used to buffer a request until enough data has been received.
class BufferedResourceHandler
class CONTENT_EXPORT BufferedResourceHandler
: public LayeredResourceHandler,
public ResourceController {
public:
......
// Copyright 2014 The Chromium 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 "content/browser/loader/buffered_resource_handler.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/common/resource_response.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "net/url_request/url_request_context.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace content {
namespace {
class TestResourceHandler : public ResourceHandler {
public:
TestResourceHandler() : ResourceHandler(nullptr) {}
void SetController(ResourceController* controller) override {}
bool OnUploadProgress(uint64 position, uint64 size) override {
NOTREACHED();
return false;
}
bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
ResourceResponse* response,
bool* defer) override {
NOTREACHED();
return false;
}
bool OnResponseStarted(ResourceResponse* response, bool* defer) override {
return false;
}
bool OnWillStart(const GURL& url, bool* defer) override {
NOTREACHED();
return false;
}
bool OnBeforeNetworkStart(const GURL& url, bool* defer) override {
NOTREACHED();
return false;
}
bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
int* buf_size,
int min_size) override {
NOTREACHED();
return false;
}
bool OnReadCompleted(int bytes_read, bool* defer) override {
NOTREACHED();
return false;
}
void OnResponseCompleted(const net::URLRequestStatus& status,
const std::string& security_info,
bool* defer) override {
}
void OnDataDownloaded(int bytes_downloaded) override {
NOTREACHED();
}
private:
DISALLOW_COPY_AND_ASSIGN(TestResourceHandler);
};
class TestResourceDispatcherHost : public ResourceDispatcherHostImpl {
public:
explicit TestResourceDispatcherHost(bool stream_has_handler)
: stream_has_handler_(stream_has_handler),
intercepted_as_stream_(false) {}
bool intercepted_as_stream() const { return intercepted_as_stream_; }
scoped_ptr<ResourceHandler> CreateResourceHandlerForDownload(
net::URLRequest* request,
bool is_content_initiated,
bool must_download,
uint32 id,
scoped_ptr<DownloadSaveInfo> save_info,
const DownloadUrlParameters::OnStartedCallback& started_cb) override {
return scoped_ptr<ResourceHandler>(new TestResourceHandler).Pass();
}
scoped_ptr<ResourceHandler> MaybeInterceptAsStream(
net::URLRequest* request,
ResourceResponse* response,
std::string* payload) override {
if (stream_has_handler_) {
intercepted_as_stream_ = true;
return scoped_ptr<ResourceHandler>(new TestResourceHandler).Pass();
} else {
return scoped_ptr<ResourceHandler>();
}
}
private:
// Whether the URL request should be intercepted as a stream.
bool stream_has_handler_;
// Whether the URL request has been intercepted as a stream.
bool intercepted_as_stream_;
};
class TestResourceDispatcherHostDelegate
: public ResourceDispatcherHostDelegate {
public:
TestResourceDispatcherHostDelegate(bool must_download)
: must_download_(must_download) {
}
bool ShouldForceDownloadResource(const GURL& url,
const std::string& mime_type) override {
return must_download_;
}
private:
const bool must_download_;
};
class TestResourceController : public ResourceController {
public:
void Cancel() override {}
void CancelAndIgnore() override {
NOTREACHED();
}
void CancelWithError(int error_code) override {
NOTREACHED();
}
void Resume() override {
NOTREACHED();
}
};
class BufferedResourceHandlerTest : public testing::Test {
public:
BufferedResourceHandlerTest() : stream_has_handler_(false) {}
void set_stream_has_handler(bool stream_has_handler) {
stream_has_handler_ = stream_has_handler;
}
bool TestStreamIsIntercepted(bool allow_download,
bool must_download,
ResourceType request_resource_type);
private:
// Whether the URL request should be intercepted as a stream.
bool stream_has_handler_;
TestBrowserThreadBundle thread_bundle_;
};
bool BufferedResourceHandlerTest::TestStreamIsIntercepted(
bool allow_download,
bool must_download,
ResourceType request_resource_type) {
net::URLRequestContext context;
scoped_ptr<net::URLRequest> request(context.CreateRequest(
GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr, nullptr));
bool is_main_frame = request_resource_type == RESOURCE_TYPE_MAIN_FRAME;
ResourceRequestInfo::AllocateForTesting(
request.get(),
request_resource_type,
nullptr, // context
0, // render_process_id
0, // render_view_id
0, // render_frame_id
is_main_frame, // is_main_frame
false, // parent_is_main_frame
allow_download, // allow_download
true); // is_async
TestResourceDispatcherHost host(stream_has_handler_);
TestResourceDispatcherHostDelegate host_delegate(must_download);
host.SetDelegate(&host_delegate);
scoped_ptr<ResourceHandler> buffered_handler(
new BufferedResourceHandler(
scoped_ptr<ResourceHandler>(new TestResourceHandler()).Pass(),
&host, request.get()));
TestResourceController resource_controller;
buffered_handler->SetController(&resource_controller);
scoped_refptr<ResourceResponse> response(new ResourceResponse);
// The MIME type isn't important but it shouldn't be empty.
response->head.mime_type = "application/pdf";
bool defer = false;
buffered_handler->OnResponseStarted(response.get(), &defer);
content::RunAllPendingInMessageLoop();
return host.intercepted_as_stream();
}
// TODO(raymes): Currently fails on Mac due to dependency on plugin
// initialization.
#if defined(OS_MACOSX)
#define MAYBE_StreamHandling DISABLED_StreamHandling
#else
#define MAYBE_StreamHandling StreamHandling
#endif
// Test that stream requests are correctly intercepted under the right
// circumstances.
TEST_F(BufferedResourceHandlerTest, MAYBE_StreamHandling) {
bool allow_download;
bool must_download;
ResourceType resource_type;
// Ensure the stream is handled by MaybeInterceptAsStream in the
// ResourceDispatcherHost.
set_stream_has_handler(true);
// Main frame request with no download allowed. Stream shouldn't be
// intercepted.
allow_download = false;
must_download = false;
resource_type = RESOURCE_TYPE_MAIN_FRAME;
EXPECT_FALSE(
TestStreamIsIntercepted(allow_download, must_download, resource_type));
// Main frame request with download allowed. Stream should be intercepted.
allow_download = true;
must_download = false;
resource_type = RESOURCE_TYPE_MAIN_FRAME;
EXPECT_TRUE(
TestStreamIsIntercepted(allow_download, must_download, resource_type));
// Main frame request with download forced. Stream shouldn't be intercepted.
allow_download = true;
must_download = true;
resource_type = RESOURCE_TYPE_MAIN_FRAME;
EXPECT_FALSE(
TestStreamIsIntercepted(allow_download, must_download, resource_type));
// Sub-resource request with download not allowed. Stream shouldn't be
// intercepted.
allow_download = false;
must_download = false;
resource_type = RESOURCE_TYPE_SUB_RESOURCE;
EXPECT_FALSE(
TestStreamIsIntercepted(allow_download, must_download, resource_type));
// Object request with download not allowed. Stream should be intercepted.
allow_download = false;
must_download = false;
resource_type = RESOURCE_TYPE_OBJECT;
EXPECT_TRUE(
TestStreamIsIntercepted(allow_download, must_download, resource_type));
// Test the cases where the stream isn't handled by MaybeInterceptAsStream
// in the ResourceDispatcherHost.
set_stream_has_handler(false);
allow_download = false;
must_download = false;
resource_type = RESOURCE_TYPE_OBJECT;
EXPECT_FALSE(
TestStreamIsIntercepted(allow_download, must_download, resource_type));
allow_download = true;
must_download = false;
resource_type = RESOURCE_TYPE_MAIN_FRAME;
EXPECT_FALSE(
TestStreamIsIntercepted(allow_download, must_download, resource_type));
}
} // namespace
} // namespace content
......@@ -226,8 +226,8 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// Must be called after the ResourceRequestInfo has been created
// and associated with the request.
// |id| should be |content::DownloadItem::kInvalidId| to request automatic
// assignment.
scoped_ptr<ResourceHandler> CreateResourceHandlerForDownload(
// assignment. This is marked virtual so it can be overriden in testing.
virtual scoped_ptr<ResourceHandler> CreateResourceHandlerForDownload(
net::URLRequest* request,
bool is_content_initiated,
bool must_download,
......@@ -238,8 +238,9 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// Must be called after the ResourceRequestInfo has been created
// and associated with the request. If |payload| is set to a non-empty value,
// the value will be sent to the old resource handler instead of canceling
// it, except on HTTP errors.
scoped_ptr<ResourceHandler> MaybeInterceptAsStream(
// it, except on HTTP errors. This is marked virtual so it can be overriden in
// testing.
virtual scoped_ptr<ResourceHandler> MaybeInterceptAsStream(
net::URLRequest* request,
ResourceResponse* response,
std::string* payload);
......
......@@ -325,6 +325,7 @@ class ResourceLoaderTest : public testing::Test,
MSG_ROUTING_NONE,
true, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
false); // is_async
scoped_ptr<ResourceHandlerStub> resource_handler(
new ResourceHandlerStub(request.get()));
......
......@@ -31,6 +31,7 @@ void ResourceRequestInfo::AllocateForTesting(net::URLRequest* request,
int render_frame_id,
bool is_main_frame,
bool parent_is_main_frame,
bool allow_download,
bool is_async) {
// Make sure both |is_main_frame| and |parent_is_main_frame| aren't set at the
// same time.
......@@ -56,7 +57,7 @@ void ResourceRequestInfo::AllocateForTesting(net::URLRequest* request,
false, // should_replace_current_entry
false, // is_download
false, // is_stream
true, // allow_download
allow_download, // allow_download
false, // has_user_gesture
false, // enable load timing
false, // enable upload progress
......
......@@ -537,6 +537,7 @@
'browser/indexed_db/mock_indexed_db_factory.h',
'browser/indexed_db/leveldb/leveldb_unittest.cc',
'browser/indexed_db/list_set_unittest.cc',
'browser/loader/buffered_resource_handler_unittest.cc',
'browser/loader/navigation_url_loader_unittest.cc',
'browser/loader/resource_buffer_unittest.cc',
'browser/loader/resource_dispatcher_host_unittest.cc',
......
......@@ -38,6 +38,7 @@ class ResourceRequestInfo {
int render_frame_id,
bool is_main_frame,
bool parent_is_main_frame,
bool allow_download,
bool is_async);
// Returns the associated RenderFrame for a given process. Returns false, if
......
......@@ -108,6 +108,7 @@ TEST(WebRequestConditionAttributeTest, ResourceType) {
-1, // render_frame_id
false, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
false); // is_async
EXPECT_TRUE(attribute->IsFulfilled(WebRequestData(url_request_ok.get(),
ON_BEFORE_REQUEST)));
......@@ -123,6 +124,7 @@ TEST(WebRequestConditionAttributeTest, ResourceType) {
-1, // render_frame_id
true, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
false); // is_async
EXPECT_FALSE(attribute->IsFulfilled(WebRequestData(url_request_fail.get(),
ON_BEFORE_REQUEST)));
......
......@@ -95,6 +95,7 @@ TEST(WebRequestConditionTest, CreateCondition) {
-1, // render_frame_id
true, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
false); // is_async
EXPECT_TRUE(result->IsFulfilled(request_data));
......@@ -114,6 +115,7 @@ TEST(WebRequestConditionTest, CreateCondition) {
-1, // render_frame_id
false, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
false); // is_async
EXPECT_FALSE(result->IsFulfilled(request_data));
}
......@@ -162,6 +164,7 @@ TEST(WebRequestConditionTest, CreateConditionFirstPartyForCookies) {
-1, // render_frame_id
true, // is_main_frame
false, // parent_is_main_frame
true, // allow_download
false); // is_async
EXPECT_TRUE(result->IsFulfilled(request_data));
}
......
......@@ -45,11 +45,11 @@ void MimeHandlerViewContainer::Ready() {
options.crossOriginRequestPolicy =
blink::WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
DCHECK(!loader_);
loader_.reset(frame->createAssociatedURLLoader());
loader_.reset(frame->createAssociatedURLLoader(options));
// TODO(raymes): Currently this URL request won't be correctly intercepted as
// a stream.
loader_->loadAsynchronously(blink::WebURLRequest(original_url_), this);
blink::WebURLRequest request(original_url_);
request.setRequestContext(blink::WebURLRequest::RequestContextObject);
loader_->loadAsynchronously(request, this);
}
bool MimeHandlerViewContainer::HandlesMessage(const IPC::Message& message) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment