diff --git a/core/server/data/xml/rss/index.js b/core/server/data/xml/rss/index.js
index 85728d549f..cc07469a56 100644
--- a/core/server/data/xml/rss/index.js
+++ b/core/server/data/xml/rss/index.js
@@ -1,15 +1,14 @@
-var _ = require('lodash'),
- cheerio = require('cheerio'),
- crypto = require('crypto'),
- downsize = require('downsize'),
- RSS = require('rss'),
- url = require('url'),
- config = require('../../../config'),
- errors = require('../../../errors'),
- filters = require('../../../filters'),
+var _ = require('lodash'),
+ crypto = require('crypto'),
+ downsize = require('downsize'),
+ RSS = require('rss'),
+ config = require('../../../config'),
+ errors = require('../../../errors'),
+ filters = require('../../../filters'),
+ processUrls = require('../../../utils/make-absolute-urls'),
// Really ugly temporary hack for location of things
- fetchData = require('../../../controllers/frontend/fetch-data'),
+ fetchData = require('../../../controllers/frontend/fetch-data'),
generate,
generateFeed,
@@ -65,48 +64,6 @@ function getBaseUrl(req, slugParam) {
return baseUrl;
}
-function processUrls(html, siteUrl, itemUrl) {
- var htmlContent = cheerio.load(html, {decodeEntities: false});
- // convert relative resource urls to absolute
- ['href', 'src'].forEach(function forEach(attributeName) {
- htmlContent('[' + attributeName + ']').each(function each(ix, el) {
- var baseUrl,
- attributeValue,
- parsed;
-
- el = htmlContent(el);
-
- attributeValue = el.attr(attributeName);
-
- // if URL is absolute move on to the next element
- try {
- parsed = url.parse(attributeValue);
-
- if (parsed.protocol) {
- return;
- }
-
- // Do not convert protocol relative URLs
- if (attributeValue.lastIndexOf('//', 0) === 0) {
- return;
- }
- } catch (e) {
- return;
- }
-
- // compose an absolute URL
-
- // if the relative URL begins with a '/' use the blog URL (including sub-directory)
- // as the base URL, otherwise use the post's URL.
- baseUrl = attributeValue[0] === '/' ? siteUrl : itemUrl;
- attributeValue = config.urlJoin(baseUrl, attributeValue);
- el.attr(attributeName, attributeValue);
- });
- });
-
- return htmlContent;
-}
-
getFeedXml = function getFeedXml(path, data) {
var dataHash = crypto.createHash('md5').update(JSON.stringify(data)).digest('hex');
if (!feedCache[path] || feedCache[path].hash !== dataHash) {
diff --git a/core/server/utils/make-absolute-urls.js b/core/server/utils/make-absolute-urls.js
new file mode 100644
index 0000000000..2519ffc874
--- /dev/null
+++ b/core/server/utils/make-absolute-urls.js
@@ -0,0 +1,57 @@
+var cheerio = require('cheerio'),
+ url = require('url'),
+ config = require('../config');
+
+/**
+ * Make absolute URLs
+ * @param {string} html
+ * @param {string} siteUrl (blog URL)
+ * @param {string} itemUrl (URL of current context)
+ * @returns {object} htmlContent
+ * @description Takes html, blog url and item url and converts relative url into
+ * absolute urls. Returns an object. The html string can be accessed by calling `html()` on
+ * the variable that takes the result of this function
+ */
+function makeAbsoluteUrls(html, siteUrl, itemUrl) {
+ var htmlContent = cheerio.load(html, {decodeEntities: false});
+ // convert relative resource urls to absolute
+ ['href', 'src'].forEach(function forEach(attributeName) {
+ htmlContent('[' + attributeName + ']').each(function each(ix, el) {
+ var baseUrl,
+ attributeValue,
+ parsed;
+
+ el = htmlContent(el);
+
+ attributeValue = el.attr(attributeName);
+
+ // if URL is absolute move on to the next element
+ try {
+ parsed = url.parse(attributeValue);
+
+ if (parsed.protocol) {
+ return;
+ }
+
+ // Do not convert protocol relative URLs
+ if (attributeValue.lastIndexOf('//', 0) === 0) {
+ return;
+ }
+ } catch (e) {
+ return;
+ }
+
+ // compose an absolute URL
+
+ // if the relative URL begins with a '/' use the blog URL (including sub-directory)
+ // as the base URL, otherwise use the post's URL.
+ baseUrl = attributeValue[0] === '/' ? siteUrl : itemUrl;
+ attributeValue = config.urlJoin(baseUrl, attributeValue);
+ el.attr(attributeName, attributeValue);
+ });
+ });
+
+ return htmlContent;
+}
+
+module.exports = makeAbsoluteUrls;
diff --git a/core/test/unit/utils/make-absolute-urls_spec.js b/core/test/unit/utils/make-absolute-urls_spec.js
new file mode 100644
index 0000000000..5a04afa05c
--- /dev/null
+++ b/core/test/unit/utils/make-absolute-urls_spec.js
@@ -0,0 +1,39 @@
+var makeAbsoluteUrls = require('../../../server/utils/make-absolute-urls'),
+ configUtils = require('../../utils/configUtils');
+
+describe('Make absolute URLs ', function () {
+ var siteUrl = 'http://my-ghost-blog.com',
+ itemUrl = 'my-awesome-post';
+ beforeEach(function () {
+ configUtils.set({url: 'http://my-ghost-blog.com'});
+ });
+
+ afterEach(function () {
+ configUtils.restore();
+ });
+
+ it('does not convert absolute URLs', function () {
+ var html = '',
+ result = makeAbsoluteUrls(html, siteUrl, itemUrl).html();
+
+ result.should.match(//);
+ });
+ it('does not convert protocol relative `//` URLs', function () {
+ var html = '',
+ result = makeAbsoluteUrls(html, siteUrl, itemUrl).html();
+
+ result.should.match(//);
+ });
+ it('succesfully converts a relative URL', function () {
+ var html = '',
+ result = makeAbsoluteUrls(html, siteUrl, itemUrl).html();
+
+ result.should.match(//);
+ });
+ it('succesfully converts a relative URL including subdirectories', function () {
+ var html = '',
+ result = makeAbsoluteUrls(html, 'http://my-ghost-blog.com/blog', itemUrl).html();
+
+ result.should.match(//);
+ });
+});