History

Add <base> support

Thibaut Courouble committed 9 years ago

Commit 4e41ed91 parent 6f0214e6 files · +99 −3Browse files

Unified · Split

6 files
  1. lib/docs/core/filter.rb +3 −1
  2. lib/docs/core/scraper.rb +1 −1
  3. lib/docs/core/scrapers/url_scraper.rb +1 −1
  4. lib/docs/filters/core/apply_base_url.rb +21 −0
  5. test/lib/docs/core/filter_test.rb +4 −0
  6. test/lib/docs/filters/core/apply_base_url_test.rb +69 −0
lib/docs/core/filter.rb+3−1
@@ -1,3 +1,5 @@
1# frozen_string_literal: true
2
1module Docs3module Docs
2 class Filter < ::HTML::Pipeline::Filter4 class Filter < ::HTML::Pipeline::Filter
3 def css(*args)5 def css(*args)
@@ -73,7 +75,7 @@ module Docs · 69 unmodified lines
73 end75 end
74 76
75 def relative_url_string?(str)77 def relative_url_string?(str)
76 !fragment_url_string?(str) && str !~ SCHEME_RGX78 str !~ SCHEME_RGX && !fragment_url_string?(str) && !data_url_string?(str)
77 end79 end
78 80
79 def absolute_url_string?(str)81 def absolute_url_string?(str)
lib/docs/core/scraper.rb+1−1
@@ -41,7 +41,7 @@ module Docs · 40 unmodified lines
41 self.html_filters = FilterStack.new41 self.html_filters = FilterStack.new
42 self.text_filters = FilterStack.new42 self.text_filters = FilterStack.new
43 43
44 html_filters.push 'container', 'clean_html', 'normalize_urls', 'internal_urls', 'normalize_paths'44 html_filters.push 'apply_base_url', 'container', 'clean_html', 'normalize_urls', 'internal_urls', 'normalize_paths'
45 text_filters.push 'inner_html', 'clean_text', 'attribution'45 text_filters.push 'inner_html', 'clean_text', 'attribution'
46 46
47 def initialize47 def initialize
lib/docs/core/scrapers/url_scraper.rb+1−1
@@ -129,7 +129,7 @@ module Docs · 128 unmodified lines
129 129
130 def fetch_redirections130 def fetch_redirections
131 result = {}131 result = {}
132 with_filters 'container', 'normalize_urls', 'internal_urls' do132 with_filters 'apply_base_url', 'container', 'normalize_urls', 'internal_urls' do
133 build_pages do |page|133 build_pages do |page|
134 next if page[:response_effective_path] == page[:response_path]134 next if page[:response_effective_path] == page[:response_path]
135 result[page[:response_path].downcase] = page[:response_effective_path]135 result[page[:response_path].downcase] = page[:response_effective_path]
lib/docs/filters/core/apply_base_url.rb+21−0
@@ -0,0 +1,21 @@
1module Docs
2 class ApplyBaseUrlFilter < Filter
3 URL_ATTRIBUTES = { 'a': 'href', 'img': 'src', 'iframe': 'src' }
4 SCHEME_RGX = /\A[^:\/?#]+:/
5
6 def call
7 base_url = at_css('base').try(:[], 'href')
8 return doc unless base_url
9
10 URL_ATTRIBUTES.each_pair do |tag, attribute|
11 css(tag).each do |node|
12 next unless value = node[attribute]
13 next if !relative_url_string?(value) || value[0] == '/'.freeze
14 node[attribute] = "#{base_url}#{node[attribute]}"
15 end
16 end
17
18 doc
19 end
20 end
21end
test/lib/docs/core/filter_test.rb+4−0
@@ -149,6 +149,10 @@ class DocsFilterTest < MiniTest::Spec · 148 unmodified lines
149 it "returns false with 'mailto:test@example.com'" do149 it "returns false with 'mailto:test@example.com'" do
150 refute filter.relative_url_string?('mailto:test@example.com')150 refute filter.relative_url_string?('mailto:test@example.com')
151 end151 end
152
153 it "returns false with 'data:image/gif;base64,foo'" do
154 refute filter.relative_url_string?('data:image/gif;base64,foo')
155 end
152 end156 end
153 157
154 describe "#absolute_url_string?" do158 describe "#absolute_url_string?" do
test/lib/docs/filters/core/apply_base_url_test.rb+69−0
@@ -0,0 +1,69 @@
1require 'test_helper'
2require 'docs'
3
4class ApplyBaseUrlFilterTest < MiniTest::Spec
5 include FilterTestHelper
6 self.filter_class = Docs::ApplyBaseUrlFilter
7 self.filter_type = 'html'
8
9 context "when there is no <base>" do
10 it "does nothing" do
11 @body = make_body nil, link_to('test')
12 assert_equal link_to('test'), filter_output.at_css('body').inner_html
13 end
14 end
15
16 context "when <base> is '/base/'" do
17 it "rewrites relative urls" do
18 @body = make_body '/base/', link_to('path#frag')
19 assert_equal link_to('/base/path#frag'), filter_output.at_css('body').inner_html
20 end
21
22 it "rewrites relative image urls" do
23 @body = make_body '/base/', '<img src="../img.png">'
24 assert_equal '<img src="/base/../img.png">', filter_output.at_css('body').inner_html
25 end
26
27 it "rewrites relative iframe urls" do
28 @body = make_body '/base/', '<iframe src="./test"></iframe>'
29 assert_equal '<iframe src="/base/./test"></iframe>', filter_output.at_css('body').inner_html
30 end
31
32 it "doesn't rewrite absolute urls" do
33 @body = make_body '/base/', link_to('http://example.com')
34 assert_equal link_to('http://example.com'), filter_output.at_css('body').inner_html
35 end
36
37 it "doesn't rewrite protocol-less urls" do
38 @body = make_body '/base/', link_to('//example.com')
39 assert_equal link_to('//example.com'), filter_output.at_css('body').inner_html
40 end
41
42 it "doesn't rewrite root-relative urls" do
43 @body = make_body '/base/', link_to('/path')
44 assert_equal link_to('/path'), filter_output.at_css('body').inner_html
45 end
46
47 it "doesn't rewrite fragment-only urls" do
48 @body = make_body '/base/', link_to('#test')
49 assert_equal link_to('#test'), filter_output.at_css('body').inner_html
50 end
51
52 it "doesn't rewrite email urls" do
53 @body = make_body '/base/', link_to('mailto:test@example.com')
54 assert_equal link_to('mailto:test@example.com'), filter_output.at_css('body').inner_html
55 end
56
57 it "doesn't rewrite data urls" do
58 @body = make_body '/base/', '<img src="data:image/gif;base64,aaaa">'
59 assert_equal '<img src="data:image/gif;base64,aaaa">', filter_output.at_css('body').inner_html
60 end
61 end
62
63 private
64
65 def make_body(base, body)
66 base = %(<base href="#{base}">) if base
67 "<html><meta charset=utf-8><title></title>#{base}#{body}</html>"
68 end
69end