Commit a13cb2a1 authored by Min Qin's avatar Min Qin Committed by Commit Bot

Throttle url download requests from a RenderFrame

RenderFrameImpl::DownloadUrl() can be abused to trigger a large number
of download to overwhelm the browser process.
This CL rate limits the number of download to a maximum of 10 per second.

Bug: 860045
Change-Id: I490ae3a99eb59aef709b9f1e6be5eb0f787354f4
Reviewed-on: https://chromium-review.googlesource.com/1132485
Commit-Queue: Min Qin <qinmin@chromium.org>
Reviewed-by: default avatarJohn Abd-El-Malek <jam@chromium.org>
Cr-Commit-Position: refs/heads/master@{#574078}
parent 217db6fe
......@@ -340,6 +340,9 @@ namespace {
const int kExtraCharsBeforeAndAfterSelection = 100;
// Maximum number of burst download requests allowed.
const int kBurstDownloadLimit = 10;
const PreviewsState kDisabledPreviewsBits =
PREVIEWS_OFF | PREVIEWS_NO_TRANSFORM;
......@@ -3955,6 +3958,9 @@ void RenderFrameImpl::DidAddMessageToConsole(
void RenderFrameImpl::DownloadURL(
const blink::WebURLRequest& request,
mojo::ScopedMessagePipeHandle blob_url_token) {
if (ShouldThrottleDownload())
return;
FrameHostMsg_DownloadUrl_Params params;
params.render_view_id = render_view_->GetRoutingID();
params.render_frame_id = GetRoutingID();
......@@ -7348,4 +7354,23 @@ RenderFrameImpl::CreateWebSocketHandshakeThrottle() {
render_frame_id);
}
bool RenderFrameImpl::ShouldThrottleDownload() {
const auto now = base::TimeTicks::Now();
if (num_burst_download_requests_ == 0) {
burst_download_start_time_ = now;
} else if (num_burst_download_requests_ >= kBurstDownloadLimit) {
static constexpr auto kBurstDownloadLimitResetInterval =
TimeDelta::FromSeconds(1);
if (now - burst_download_start_time_ > kBurstDownloadLimitResetInterval) {
num_burst_download_requests_ = 1;
burst_download_start_time_ = now;
return false;
}
return true;
}
num_burst_download_requests_++;
return false;
}
} // namespace content
......@@ -1320,6 +1320,9 @@ class CONTENT_EXPORT RenderFrameImpl
blink::WebHistoryItem* item_for_history_navigation,
blink::WebFrameLoadType* load_type);
// Whether url download should be throttled.
bool ShouldThrottleDownload();
// Stores the WebLocalFrame we are associated with. This is null from the
// constructor until BindToFrame() is called, and it is null after
// FrameDetached() is called until destruction (which is asynchronous in the
......@@ -1667,6 +1670,10 @@ class CONTENT_EXPORT RenderFrameImpl
std::unique_ptr<WebSocketHandshakeThrottleProvider>
websocket_handshake_throttle_provider_;
// Variable to control burst of download requests.
int num_burst_download_requests_ = 0;
base::TimeTicks burst_download_start_time_;
base::WeakPtrFactory<RenderFrameImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderFrameImpl);
......
......@@ -416,6 +416,35 @@ TEST_F(RenderFrameImplTest, SaveImageFromDataURL) {
EXPECT_FALSE(msg4);
}
// Tests that url download are throttled when reaching the limit.
TEST_F(RenderFrameImplTest, DownloadUrlLimit) {
const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
FrameHostMsg_DownloadUrl::ID);
EXPECT_FALSE(msg1);
render_thread_->sink().ClearMessages();
WebURLRequest request;
request.SetURL(GURL("http://test/test.pdf"));
request.SetRequestorOrigin(
blink::WebSecurityOrigin::Create(GURL("http://test")));
for (int i = 0; i < 10; ++i) {
frame()->DownloadURL(request, mojo::ScopedMessagePipeHandle());
base::RunLoop().RunUntilIdle();
const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching(
FrameHostMsg_DownloadUrl::ID);
EXPECT_TRUE(msg2);
base::RunLoop().RunUntilIdle();
render_thread_->sink().ClearMessages();
}
frame()->DownloadURL(request, mojo::ScopedMessagePipeHandle());
base::RunLoop().RunUntilIdle();
const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching(
FrameHostMsg_DownloadUrl::ID);
EXPECT_FALSE(msg3);
}
TEST_F(RenderFrameImplTest, ZoomLimit) {
const double kMinZoomLevel = ZoomFactorToZoomLevel(kMinimumZoomFactor);
const double kMaxZoomLevel = ZoomFactorToZoomLevel(kMaximumZoomFactor);
......
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