FIX: Convert URLs embedded topics to absolute form (#14975)

FIX: Convert URLs embedded topics to absolute form (#14975)

Sometimes the expanded post contained broken relative URLs because they were not converted to their absolute form.

diff --git a/app/models/topic_embed.rb b/app/models/topic_embed.rb
index 2273913..010676c 100644
--- a/app/models/topic_embed.rb
+++ b/app/models/topic_embed.rb
@@ -161,12 +161,8 @@ class TopicEmbed < ActiveRecord::Base
       src = node[url_param]
       unless (src.nil? || src.empty?)
         begin
-          uri = URI.parse(UrlHelper.escape_uri(src))
-          unless uri.host
-            uri.scheme = original_uri.scheme
-            uri.host = original_uri.host
-            node[url_param] = uri.to_s
-          end
+          # convert URL to absolute form
+          node[url_param] = URI.join(url, UrlHelper.escape_uri(src)).to_s
         rescue URI::Error, Addressable::URI::InvalidURIError
           # If there is a mistyped URL, just do nothing
         end
@@ -211,15 +207,13 @@ class TopicEmbed < ActiveRecord::Base
 
     fragment = Nokogiri::HTML5.fragment("<div>#{contents}</div>")
     fragment.css('a').each do |a|
-      href = a['href']
-      if href.present? && href.start_with?('/')
-        a['href'] = "#{prefix}/#{href.sub(/^\/+/, '')}"
+      if a['href'].present?
+        a['href'] = URI.join(prefix, a['href']).to_s
       end
     end
     fragment.css('img').each do |a|
-      src = a['src']
-      if src.present? && src.start_with?('/')
-        a['src'] = "#{prefix}/#{src.sub(/^\/+/, '')}"
+      if a['src'].present?
+        a['src'] = URI.join(prefix, a['src']).to_s
       end
     end
     fragment.at('div').inner_html
diff --git a/spec/models/topic_embed_spec.rb b/spec/models/topic_embed_spec.rb
index 4ce37dc..8913e9b 100644
--- a/spec/models/topic_embed_spec.rb
+++ b/spec/models/topic_embed_spec.rb
@@ -14,7 +14,7 @@ describe TopicEmbed do
     fab!(:user) { Fabricate(:user) }
     let(:title) { "How to turn a fish from good to evil in 30 seconds" }
     let(:url) { 'http://eviltrout.com/123' }
-    let(:contents) { "<p>hello world new post <a href='/hello'>hello</a> <img src='/images/wat.jpg'></p>" }
+    let(:contents) { "<p>hello world new post <a href='/hello'>hello</a> <img src='images/wat.jpg'></p>" }
     fab!(:embeddable_host) { Fabricate(:embeddable_host) }
     fab!(:category) { Fabricate(:category) }
     fab!(:tag) { Fabricate(:tag) }
@@ -39,6 +39,10 @@ describe TopicEmbed do
         expect(post.cooked).to have_tag('a', with: { href: 'http://eviltrout.com/hello' })
         expect(post.cooked).to have_tag('img', with: { src: 'http://eviltrout.com/images/wat.jpg' })
 
+        # It converts relative URLs to absolute when expanded
+        stub_request(:get, url).to_return(status: 200, body: contents)
+        expect(TopicEmbed.expanded_for(post)).to have_tag('img', with: { src: 'http://eviltrout.com/images/wat.jpg' })
+
         expect(post.topic.has_topic_embed?).to eq(true)
         expect(TopicEmbed.where(topic_id: post.topic_id)).to be_present
 
@@ -335,7 +339,7 @@ describe TopicEmbed do
       it "handles mailto links" do
         response = TopicEmbed.find_remote(url)
 
-        expect(response.body).to have_tag('a', with: { href: 'mailto:foo%40example.com' })
+        expect(response.body).to have_tag('a', with: { href: 'mailto:foo@example.com' })
         expect(response.body).to have_tag('a', with: { href: 'mailto:bar@example.com' })
       end
     end

GitHub sha: cc1b45f58b3ecb8eeeeea5b9169006f332db187e

This commit appears in #14975 which was approved by eviltrout. It was merged by SamSaffron.