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(//); + }); +});