diff options
author | Nick Thomas <nick@gitlab.com> | 2017-12-05 18:47:54 +0000 |
---|---|---|
committer | Nick Thomas <nick@gitlab.com> | 2017-12-21 19:53:38 +0000 |
commit | bc2bc477e6f6e22fbd16c8378d9eb8cbf5f87676 (patch) | |
tree | bde9cc12ffd866bab90d42d47fd9acd89f8dacfe | |
parent | 4eb5c3a2447409bc5e81349d93f3138bd49f62ae (diff) | |
download | gitlab-ce-38893-banzai-upload-filter-relative-urls.tar.gz |
Use relative URLs when linking to uploaded files38893-banzai-upload-filter-relative-urls
-rw-r--r-- | app/models/concerns/cache_markdown_field.rb | 2 | ||||
-rw-r--r-- | lib/banzai/filter/relative_link_filter.rb | 35 | ||||
-rw-r--r-- | lib/banzai/filter/upload_link_filter.rb | 60 | ||||
-rw-r--r-- | lib/banzai/pipeline/gfm_pipeline.rb | 1 | ||||
-rw-r--r-- | spec/lib/banzai/filter/upload_link_filter_spec.rb | 106 |
5 files changed, 122 insertions, 82 deletions
diff --git a/app/models/concerns/cache_markdown_field.rb b/app/models/concerns/cache_markdown_field.rb index 90ad644ce34..4ae5dd8c677 100644 --- a/app/models/concerns/cache_markdown_field.rb +++ b/app/models/concerns/cache_markdown_field.rb @@ -11,7 +11,7 @@ module CacheMarkdownField extend ActiveSupport::Concern # Increment this number every time the renderer changes its output - CACHE_VERSION = 2 + CACHE_VERSION = 3 # changes to these attributes cause the cache to be invalidates INVALIDATED_BY = %w[author project].freeze diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb index 758f15c8a67..34952369ef8 100644 --- a/lib/banzai/filter/relative_link_filter.rb +++ b/lib/banzai/filter/relative_link_filter.rb @@ -2,18 +2,18 @@ require 'uri' module Banzai module Filter - # HTML filter that "fixes" relative links to files in a repository. + # HTML filter that "fixes" relative links to uploads or files in a repository. # # Context options: # :commit + # :group # :project # :project_wiki # :ref # :requested_path + # :only_path class RelativeLinkFilter < HTML::Pipeline::Filter def call - return doc unless linkable_files? - @uri_types = {} doc.search('a:not(.gfm)').each do |el| @@ -31,13 +31,40 @@ module Banzai protected def linkable_files? - context[:project_wiki].nil? && repository.try(:exists?) && !repository.empty? + strong_memoize(:linkable_files) do + context[:project_wiki].nil? && repository.try(:exists?) && !repository.empty? + end end def process_link_attr(html_attr) return if html_attr.blank? return if html_attr.value.start_with?('//') + if html_attr.value.start_with?('/uploads/') + process_link_to_upload_attr(html_attr) + else + process_link_to_repository_attr(html_attr) + end + end + + def process_link_to_upload_attr(html_attr) + base_path = + if context[:only_path] + Gitlab.config.gitlab.relative_url_root.to_s + else + Gitlab.config.gitlab.url.to_s + end + + uri = html_attr.value + + if context[:group] + html_attr.value = File.join(base_path, 'groups', context[:group].full_path, '-', uri) + elsif context[:project] + html_attr.value = File.join(base_path, context[:project].full_path, uri) + end + end + + def process_link_to_repository_attr(html_attr) uri = URI(html_attr.value) if uri.relative? && uri.path.present? html_attr.value = rebuild_relative_uri(uri).to_s diff --git a/lib/banzai/filter/upload_link_filter.rb b/lib/banzai/filter/upload_link_filter.rb deleted file mode 100644 index d64f9ac4eb6..00000000000 --- a/lib/banzai/filter/upload_link_filter.rb +++ /dev/null @@ -1,60 +0,0 @@ -require 'uri' - -module Banzai - module Filter - # HTML filter that "fixes" relative upload links to files. - # Context options: - # :project (required) - Current project - # - class UploadLinkFilter < HTML::Pipeline::Filter - def call - return doc unless project || group - - doc.xpath('descendant-or-self::a[starts-with(@href, "/uploads/")]').each do |el| - process_link_attr el.attribute('href') - end - - doc.xpath('descendant-or-self::img[starts-with(@src, "/uploads/")]').each do |el| - process_link_attr el.attribute('src') - end - - doc - end - - protected - - def process_link_attr(html_attr) - html_attr.value = build_url(html_attr.value).to_s - end - - def build_url(uri) - base_path = Gitlab.config.gitlab.url - - if group - urls = Gitlab::Routing.url_helpers - # we need to get last 2 parts of the uri which are secret and filename - uri_parts = uri.split(File::SEPARATOR) - file_path = urls.show_group_uploads_path(group, uri_parts[-2], uri_parts[-1]) - File.join(base_path, file_path) - else - File.join(base_path, project.full_path, uri) - end - end - - def project - context[:project] - end - - def group - context[:group] - end - - # Ensure that a :project key exists in context - # - # Note that while the key might exist, its value could be nil! - def validate - needs :project - end - end - end -end diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb index 55874ad50a3..c746f6f64e9 100644 --- a/lib/banzai/pipeline/gfm_pipeline.rb +++ b/lib/banzai/pipeline/gfm_pipeline.rb @@ -15,7 +15,6 @@ module Banzai Filter::MathFilter, Filter::MermaidFilter, - Filter::UploadLinkFilter, Filter::VideoLinkFilter, Filter::ImageLazyLoadFilter, Filter::ImageLinkFilter, diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb index 76bc0c36ab7..95c862f9551 100644 --- a/spec/lib/banzai/filter/upload_link_filter_spec.rb +++ b/spec/lib/banzai/filter/upload_link_filter_spec.rb @@ -1,6 +1,15 @@ require 'spec_helper' describe Banzai::Filter::UploadLinkFilter do + def relative_filter(doc, contexts = {}) + contexts.reverse_merge!({ + project: project, + only_path: true + }) + + filter(doc, contexts) + end + def filter(doc, contexts = {}) contexts.reverse_merge!({ project: project @@ -50,27 +59,27 @@ describe Banzai::Filter::UploadLinkFilter do context 'with a valid repository' do it 'rebuilds relative URL for a link' do - doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) + doc = relative_filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) expect(doc.at_css('a')['href']) - .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" - doc = filter(nested_link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) + doc = relative_filter(nested_link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) expect(doc.at_css('a')['href']) - .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" end it 'rebuilds relative URL for an image' do - doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) + doc = relative_filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) expect(doc.at_css('img')['src']) - .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" - doc = filter(nested_image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) + doc = relative_filter(nested_image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) expect(doc.at_css('img')['src']) - .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" end it 'does not modify absolute URL' do - doc = filter(link('http://example.com')) + doc = relative_filter(link('http://example.com')) expect(doc.at_css('a')['href']).to eq 'http://example.com' end @@ -85,29 +94,29 @@ describe Banzai::Filter::UploadLinkFilter do .to receive(:image?).with(path).and_return(true) doc = filter(image(escaped)) - expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/%ED%95%9C%EA%B8%80.png" + expect(doc.at_css('img')['src']).to match "/#{project.full_path}/uploads/%ED%95%9C%EA%B8%80.png" end end context 'in group context' do let(:upload_link) { link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg') } let(:group) { create(:group) } - let(:filter_context) { { project: nil, group: group } } - let(:relative_path) { "groups/#{group.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" } + let(:filter_context) { { project: nil, group: group, only_path: true } } + let(:relative_path) { "/groups/#{group.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" } it 'rewrites the link correctly' do doc = raw_filter(upload_link, filter_context) - expect(doc.at_css('a')['href']).to eq("#{Gitlab.config.gitlab.url}/#{relative_path}") + expect(doc.at_css('a')['href']).to eq(relative_path) end it 'rewrites the link correctly for subgroup' do subgroup = create(:group, parent: group) - relative_path = "groups/#{subgroup.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + relative_path = "/groups/#{subgroup.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" - doc = raw_filter(upload_link, { project: nil, group: subgroup }) + doc = raw_filter(upload_link, { project: nil, group: subgroup, only_path: true }) - expect(doc.at_css('a')['href']).to eq("#{Gitlab.config.gitlab.url}/#{relative_path}") + expect(doc.at_css('a')['href']).to eq(relative_path) end it 'does not modify absolute URL' do @@ -130,4 +139,69 @@ describe Banzai::Filter::UploadLinkFilter do expect(doc.to_html).to eq upload_link end end + + context 'GitLab relative URL root' do + let(:path) { '/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg' } + + where(:relative_url_root, :expected_prefix) do + [ + [nil, '/'], + ['', '/'], + ['/', '/'], + ['/foo', '/foo/'], + ['/foo/', '/foo/'], + ['/foo/bar/', '/foo/bar/'] + ] + end + + with_them do + context 'relative' do + let(:expected_url) { [expected_prefix, project.full_path, path].join('') } + + before do + stub_config_setting(relative_url_root: relative_url_root) + end + + context 'image' do + let(:doc) { relative_filter(image(path)) } + + subject { doc.at_css('img')['src'] } + + it { is_expected.to eq(expected_url) } + end + + context 'link' do + let(:doc) { relative_filter(link(path)) } + + subject { doc.at_css('a')['href'] } + + it { is_expected.to eq(expected_url) } + end + end + + context 'absolute' do + let(:expected_url) { [Gitlab.config.gitlab.base_url, expected_prefix, project.full_path, path].join('') } + + before do + stub_config_setting(url: Gitlab.config.gitlab.url + relative_url_root.to_s) + end + + context 'image' do + let(:doc) { filter(image(path)) } + + subject { doc.at_css('img')['src'] } + + it { is_expected.to eq(expected_url) } + end + + context 'link' do + let(:doc) { filter(link(path)) } + + subject { doc.at_css('a')['href'] } + + it { is_expected.to eq(expected_url) } + end + end + end + end end |