Limit the size of SVGs when viewing them as blobs

This ensures that SVGs greater than 2 megabytes are not scrubbed and
rendered. This in turn prevents requests from timing out due to
reading/scrubbing large SVGs potentially taking a lot of time (and
memory). The use of 2 megabytes is completely arbitrary.

Fixes gitlab-org/gitlab-ce#1435
This commit is contained in:
Yorick Peterse 2016-08-12 17:19:17 +02:00
parent 30f5b9a5b7
commit 8171544b3d
No known key found for this signature in database
GPG key ID: EDD30D2BEB691AC9
4 changed files with 41 additions and 5 deletions

View file

@ -32,6 +32,7 @@ v 8.11.0 (unreleased)
- Add "No one can push" as an option for protected branches. !5081 - Add "No one can push" as an option for protected branches. !5081
- Improve performance of AutolinkFilter#text_parse by using XPath - Improve performance of AutolinkFilter#text_parse by using XPath
- Add experimental Redis Sentinel support !1877 - Add experimental Redis Sentinel support !1877
- Rendering of SVGs as blobs is now limited to SVGs with a size smaller or equal to 2MB
- Fix branches page dropdown sort initial state (ClemMakesApps) - Fix branches page dropdown sort initial state (ClemMakesApps)
- Environments have an url to link to - Environments have an url to link to
- Various redundant database indexes have been removed - Various redundant database indexes have been removed

View file

@ -3,6 +3,9 @@ class Blob < SimpleDelegator
CACHE_TIME = 60 # Cache raw blobs referred to by a (mutable) ref for 1 minute CACHE_TIME = 60 # Cache raw blobs referred to by a (mutable) ref for 1 minute
CACHE_TIME_IMMUTABLE = 3600 # Cache blobs referred to by an immutable reference for 1 hour CACHE_TIME_IMMUTABLE = 3600 # Cache blobs referred to by an immutable reference for 1 hour
# The maximum size of an SVG that can be displayed.
MAXIMUM_SVG_SIZE = 2.megabytes
# Wrap a Gitlab::Git::Blob object, or return nil when given nil # Wrap a Gitlab::Git::Blob object, or return nil when given nil
# #
# This method prevents the decorated object from evaluating to "truthy" when # This method prevents the decorated object from evaluating to "truthy" when
@ -31,6 +34,10 @@ class Blob < SimpleDelegator
text? && language && language.name == 'SVG' text? && language && language.name == 'SVG'
end end
def size_within_svg_limits?
size <= MAXIMUM_SVG_SIZE
end
def video? def video?
UploaderHelper::VIDEO_EXT.include?(extname.downcase.delete('.')) UploaderHelper::VIDEO_EXT.include?(extname.downcase.delete('.'))
end end

View file

@ -1,9 +1,15 @@
.file-content.image_file .file-content.image_file
- if blob.svg? - if blob.svg?
- if blob.size_within_svg_limits?
- # We need to scrub SVG but we cannot do so in the RawController: it would - # We need to scrub SVG but we cannot do so in the RawController: it would
- # be wrong/strange if RawController modified the data. - # be wrong/strange if RawController modified the data.
- blob.load_all_data!(@repository) - blob.load_all_data!(@repository)
- blob = sanitize_svg(blob) - blob = sanitize_svg(blob)
%img{src: "data:#{blob.mime_type};base64,#{Base64.encode64(blob.data)}"} %img{src: "data:#{blob.mime_type};base64,#{Base64.encode64(blob.data)}"}
- else
.nothing-here-block
The SVG could not be displayed as it is too large, you can
#{link_to('view the raw file', namespace_project_raw_path(@project.namespace, @project, @id), target: '_blank')}
instead.
- else - else
%img{src: namespace_project_raw_path(@project.namespace, @project, tree_join(@commit.id, blob.path))} %img{src: namespace_project_raw_path(@project.namespace, @project, tree_join(@commit.id, blob.path))}

View file

@ -94,4 +94,26 @@ describe Blob do
expect(blob.to_partial_path).to eq 'download' expect(blob.to_partial_path).to eq 'download'
end end
end end
describe '#size_within_svg_limits?' do
let(:blob) { described_class.decorate(double(:blob)) }
it 'returns true when the blob size is smaller than the SVG limit' do
expect(blob).to receive(:size).and_return(42)
expect(blob.size_within_svg_limits?).to eq(true)
end
it 'returns true when the blob size is equal to the SVG limit' do
expect(blob).to receive(:size).and_return(Blob::MAXIMUM_SVG_SIZE)
expect(blob.size_within_svg_limits?).to eq(true)
end
it 'returns false when the blob size is larger than the SVG limit' do
expect(blob).to receive(:size).and_return(1.terabyte)
expect(blob.size_within_svg_limits?).to eq(false)
end
end
end end