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 7, 2022
1 parent 9cb1268 commit 88fbb08
Show file tree
Hide file tree
Showing 11 changed files with 132 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,
};
78 changes: 68 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,82 @@ 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;
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);
};

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

globals.fetch.__fastbootParseRequest = function __fastbootParseRequest(url, request) {
if (!request) {
throw new Error(
`Using fetch with relative URL ${url}, but application instance has not been initialized yet.`
);
}
// 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
27 changes: 25 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,29 @@ export default class FetchRoute extends Route {
}

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

return hash({
absoluteURL: absoluteURL.json(),
absoluteRequest: absoluteRequest.json(),
protocolURL: protocolURL.json(),
protocolRequest: protocolRequest.json(),
relativeURL: relativeURL.json(),
relativeRequest: relativeRequest.json(),
});
}
}
7 changes: 6 additions & 1 deletion test-packages/basic-app/app/templates/fetch.hbs
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
{{@model.login}}
{{@model.absoluteURL.response}}
{{@model.absoluteRequest.response}}
{{@model.protocolURL.response}}
{{@model.protocolRequest.response}}
{{@model.relativeURL.response}}
{{@model.relativeRequest.response}}
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 @@
{
"response": "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 @@
{
"response": "absolute-url"
}
3 changes: 3 additions & 0 deletions test-packages/basic-app/public/protocol-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"response": "protocol-request"
}
3 changes: 3 additions & 0 deletions test-packages/basic-app/public/protocol-url.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"response": "protocol-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 @@
{
"response": "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 @@
{
"response": "relative-url"
}
7 changes: 6 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,11 @@ 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('protocol-url');
expect(response.body).to.contain('protocol-request');
expect(response.body).to.contain('relative-url');
expect(response.body).to.contain('relative-request');
});
});

0 comments on commit 88fbb08

Please sign in to comment.