Commit 9aa68b87 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'svg-render-size-limit' into 'master'

Limit the size of SVGs when viewing them as blobs

## What does this MR do?

This MR prevents rendering of SVG blobs larger than 2 MB.

## Are there points in the code the reviewer needs to double check?

I couldn't figure out how to properly test the view for this as this requires a large SVG (inflating the repository size) _or_ stubbing, the latter doesn't really seem possible using Spinach and all the stuff potentially involved.

## Why was this MR needed?

When rendering large SVG blobs (e.g. 20 MB files) a request may time out and consume a lot of memory.

## What are the relevant issue numbers?

#1435

## Screenshots (if relevant)

![svg_notice](/uploads/c8de32522eda95a41a24555c3f85bfc1/svg_notice.jpg)

## Does this MR meet the acceptance criteria?

- [x] [CHANGELOG](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CHANGELOG) entry added
- [x] ~~[Documentation created/updated](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/doc_styleguide.md)~~
- [x] ~~API support added~~
- Tests
  - [x] Added for this feature/bug
  - [ ] All builds are passing
- [ ] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#style-guides)
- [ ] Branch has no merge conflicts with `master` (if you do - rebase it please)
- [x] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)

cc @jschatz1 @annabeldunstone (there are some UI changes, see the above screenshot).

See merge request !5794
parents 6af598fc 8171544b
...@@ -33,6 +33,7 @@ v 8.11.0 (unreleased) ...@@ -33,6 +33,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
......
...@@ -3,6 +3,9 @@ class Blob < SimpleDelegator ...@@ -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 ...@@ -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
......
.file-content.image_file .file-content.image_file
- if blob.svg? - if blob.svg?
- # We need to scrub SVG but we cannot do so in the RawController: it would - if blob.size_within_svg_limits?
- # be wrong/strange if RawController modified the data. - # We need to scrub SVG but we cannot do so in the RawController: it would
- blob.load_all_data!(@repository) - # be wrong/strange if RawController modified the data.
- blob = sanitize_svg(blob) - blob.load_all_data!(@repository)
%img{src: "data:#{blob.mime_type};base64,#{Base64.encode64(blob.data)}"} - blob = sanitize_svg(blob)
%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))}
...@@ -94,4 +94,26 @@ describe Blob do ...@@ -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
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