Skip to content

Commit

Permalink
Allow to use relative URLs for fetch
Browse files Browse the repository at this point in the history
  • Loading branch information
bobisjan committed Jul 5, 2022
1 parent 9cb1268 commit 30d6ac7
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function initialize(instance) {
let { request } = instance.lookup('service:fastboot');
fetch.__fastbootRequest = request;
}

export default {
name: 'fastboot:fetch', // `ember-fetch` addon registers as `fetch`
initialize,
};
79 changes: 69 additions & 10 deletions packages/fastboot/src/sandbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const chalk = require('chalk');
const vm = require('vm');
const sourceMapSupport = require('source-map-support');

const httpRegex = /^https?:\/\//;
const protocolRelativeRegex = /^\/\//;

module.exports = class Sandbox {
constructor(globals) {
this.globals = globals;
Expand Down Expand Up @@ -56,27 +59,83 @@ module.exports = class Sandbox {
}

buildFetch() {
let globals;

if (globalThis.fetch) {
return {
globals = {
fetch: globalThis.fetch,
Request: globalThis.Request,
Response: globalThis.Response,
Headers: globalThis.Headers,
AbortController: globalThis.AbortController,
};
} else {
let nodeFetch = require('node-fetch');
let {
AbortController,
abortableFetch,
} = require('abortcontroller-polyfill/dist/cjs-ponyfill');
let { fetch, Request } = abortableFetch({
fetch: nodeFetch,
Request: nodeFetch.Request,
});

globals = {
fetch,
Request,
Response: nodeFetch.Response,
Headers: nodeFetch.Headers,
AbortController,
};
}

let nodeFetch = require('node-fetch');
let { AbortController, abortableFetch } = require('abortcontroller-polyfill/dist/cjs-ponyfill');
let { fetch, Request } = abortableFetch({ fetch: nodeFetch, Request: nodeFetch.Request });
let originalFetch = globals.fetch;

return {
fetch,
Request,
Response: nodeFetch.Response,
Headers: nodeFetch.Headers,
AbortController,
globals.fetch = function __fastbootFetch(input, init) {
if (input && input.href) {
input.url = globals.fetch.__fastbootBuildAbsoluteURL(input.href);
} else if (typeof input === 'string') {
input = globals.fetch.__fastbootBuildAbsoluteURL(input);
}
return originalFetch(input, init);
};

globals.fetch.__fastbootBuildAbsoluteURL = function __fastbootBuildAbsoluteURL(url) {
if (protocolRelativeRegex.test(url)) {
let [host] = globals.fetch.__fastbootParseRequest(fetch.__fastbootRequest);
url = `${host}${url}`;
} else if (!httpRegex.test(url)) {
let [host, protocol] = globals.fetch.__fastbootParseRequest(fetch.__fastbootRequest);
url = `${protocol}//${host}${url}`;
}
return url;
};

globals.fetch.__fastbootParseRequest = function __fastbootParseRequest(request) {
if (!request) {
throw new Error(
"Trying to fetch with relative url but ember-fetch hasn't finished loading FastBootInfo, see details at https://github.com/ember-cli/ember-fetch#relative-url"
);
}
// Old Prember version is not sending protocol
const protocol = request.protocol === 'undefined:' ? 'http:' : request.protocol;
return [request.host, protocol];
};

let OriginalRequest = globals.Request;
globals.Request = class __FastBootRequest extends OriginalRequest {
constructor(input, init) {
if (typeof input === 'string') {
input = globals.fetch.__fastbootBuildAbsoluteURL(input);
} else if (input && input.href) {
// WHATWG URL or Node.js Url Object
input = globals.fetch.__fastbootBuildAbsoluteURL(input.href);
}
super(input, init);
}
};

return globals;
}

runScript(script) {
Expand Down
16 changes: 14 additions & 2 deletions test-packages/basic-app/app/routes/fetch.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Route from '@ember/routing/route';
import { assert } from '@ember/debug';
import { hash } from 'rsvp';

export default class FetchRoute extends Route {
beforeModel() {
Expand All @@ -11,7 +12,18 @@ export default class FetchRoute extends Route {
}

async model() {
let response = await fetch('https://api.github.com/users/tomster');
return response.json();
let [absoluteURL, absoluteRequest, relativeURL, relativeRequest] = await Promise.all([
fetch('http://localhost:45678/absolute-url.json'),
fetch('http://localhost:45678/absolute-request.json'),
fetch('/assets/relative-url.json'),
fetch(new Request('/assets/relative-request.json')),
]);

return hash({
absoluteURL: absoluteURL.json(),
absoluteRequest: absoluteRequest.json(),
relativeURL: relativeURL.json(),
relativeRequest: relativeRequest.json(),
});
}
}
5 changes: 4 additions & 1 deletion test-packages/basic-app/app/templates/fetch.hbs
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
{{@model.login}}
{{@model.absoluteURL.login}}
{{@model.absoluteRequest.login}}
{{@model.relativeURL.login}}
{{@model.relativeRequest.login}}
3 changes: 3 additions & 0 deletions test-packages/basic-app/public/absolute-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"login": "absolute-request"
}
3 changes: 3 additions & 0 deletions test-packages/basic-app/public/absolute-url.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"login": "absolute-url"
}
3 changes: 3 additions & 0 deletions test-packages/basic-app/public/relative-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"login": "relative-request"
}
3 changes: 3 additions & 0 deletions test-packages/basic-app/public/relative-url.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"login": "relative-url"
}
5 changes: 4 additions & 1 deletion test-packages/basic-app/test/fetch-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ describe('fetch', function() {

expect(response.statusCode).to.equal(200);
expect(response.headers['content-type']).to.equalIgnoreCase('text/html; charset=utf-8');
expect(response.body).to.contain('tomster');
expect(response.body).to.contain('absolute-url');
expect(response.body).to.contain('absolute-request');
expect(response.body).to.contain('relative-url');
expect(response.body).to.contain('relative-request');
});
});

0 comments on commit 30d6ac7

Please sign in to comment.