diff --git a/core/server/api/oembed.js b/core/server/api/oembed.js index 0f9deab03d..a5f4132fe8 100644 --- a/core/server/api/oembed.js +++ b/core/server/api/oembed.js @@ -2,6 +2,7 @@ const common = require('../lib/common'); const {extract, hasProvider} = require('oembed-parser'); const Promise = require('bluebird'); const request = require('../lib/request'); +const cheerio = require('cheerio'); const findUrlWithProvider = function findUrlWithProvider(url) { let provider; @@ -27,6 +28,10 @@ const findUrlWithProvider = function findUrlWithProvider(url) { return {url, provider}; }; +const getOembedUrlFromHTML = function getOembedUrlFromHTML(html) { + return cheerio('link[type="application/json+oembed"]', html).attr('href'); +}; + let oembed = { read(options) { let {url} = options; @@ -60,7 +65,7 @@ let oembed = { // see if the URL is a redirect to cater for shortened urls return request(url, { - method: 'HEAD', + method: 'GET', timeout: 2 * 1000, followRedirect: true }).then((response) => { @@ -69,7 +74,18 @@ let oembed = { return provider ? knownProvider(url) : unknownProvider(); } - return unknownProvider(); + const oembedUrl = getOembedUrlFromHTML(response.body); + + if (!oembedUrl) { + return unknownProvider(); + } + + return request(oembedUrl, { + method: 'GET', + json: true + }).then((response) => { + return response.body; + }); }).catch(() => { return unknownProvider(); }); diff --git a/core/test/unit/api/oembed_spec.js b/core/test/unit/api/oembed_spec.js index 4ef3c1a942..7694703c24 100644 --- a/core/test/unit/api/oembed_spec.js +++ b/core/test/unit/api/oembed_spec.js @@ -41,14 +41,14 @@ describe('API: oembed', function () { it('follows redirects to get base url', function (done) { let redirectMock = nock('https://youtu.be') - .intercept('/yHohwmrxrto', 'HEAD') + .intercept('/yHohwmrxrto', 'GET') .reply(302, undefined, { // eslint-disable-next-line 'Location': 'https://www.youtube.com/watch?v=yHohwmrxrto&feature=youtu.be' }); let videoMock = nock('https://www.youtube.com') - .intercept('/watch', 'HEAD') + .intercept('/watch', 'GET') .query({v: 'yHohwmrxrto', feature: 'youtu.be'}) .reply(200); @@ -83,7 +83,7 @@ describe('API: oembed', function () { it('returns error for unsupported provider', function (done) { nock('http://example.com') - .intercept('/unknown', 'HEAD') + .intercept('/unknown', 'GET') .reply(200); OembedAPI.read({url: 'http://example.com/unknown'}) @@ -95,6 +95,35 @@ describe('API: oembed', function () { }); }); + it('returns match for unsupported provider but with oembed link tag', function (done) { + nock('https://host.tld') + .intercept('/page', 'GET') + .reply(200, ` + + + + + + `); + + const requestMock = nock('https://host.tld') + .intercept('/oembed', 'GET') + .query(true) + .reply(200, { + html: 'test' + }); + + OembedAPI.read({url: 'https://host.tld/page'}) + .then((results) => { + requestMock.isDone().should.be.true; + should.exist(results); + should.exist(results.html); + results.html.should.eql('test'); + done(); + }).catch(done); + }); + it('returns error for fetch failure', function (done) { let requestMock = nock('https://www.youtube.com') .get('/oembed')