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 e47ad1c
Show file tree
Hide file tree
Showing 11 changed files with 136 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,
};
82 changes: 72 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,86 @@ 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) {
input = globals.fetch.__fastbootBuildAbsoluteURL(input);
return originalFetch(input, init);
};

return {
fetch,
Request,
Response: nodeFetch.Response,
Headers: nodeFetch.Headers,
AbortController,
globals.fetch.__fastbootBuildAbsoluteURL = function __fastbootBuildAbsoluteURL(input) {
if (input && input.href) {
// WHATWG URL or Node.js Url Object
input = input.href;
}

if (typeof input !== 'string') {
return input;
}

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

return input;
};

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 [protocol, request.host];
};

let OriginalRequest = globals.Request;
globals.Request = class __FastBootRequest extends OriginalRequest {
constructor(input, init) {
input = globals.fetch.__fastbootBuildAbsoluteURL(input);
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,
protocolRelativeURL,
protocolRelativeRequest,
pathRelativeURL,
pathRelativeRequest,
] = await Promise.all([
fetch('http://localhost:45678/absolute-url.json'),
fetch(new Request('http://localhost:45678/absolute-request.json')),
fetch('//localhost:45678/protocol-relative-url.json'),
fetch(new Request('//localhost:45678/protocol-relative-request.json')),
fetch('/path-relative-url.json'),
fetch(new Request('/path-relative-request.json')),
]);

return hash({
absoluteURL: absoluteURL.json(),
absoluteRequest: absoluteRequest.json(),
protocolRelativeURL: protocolRelativeURL.json(),
protocolRelativeRequest: protocolRelativeRequest.json(),
pathRelativeURL: pathRelativeURL.json(),
pathRelativeRequest: pathRelativeRequest.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.protocolRelativeURL.response}}
{{@model.protocolRelativeRequest.response}}
{{@model.pathRelativeURL.response}}
{{@model.pathRelativeRequest.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/path-relative-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"response": "path-relative-request"
}
3 changes: 3 additions & 0 deletions test-packages/basic-app/public/path-relative-url.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"response": "path-relative-url"
}
3 changes: 3 additions & 0 deletions test-packages/basic-app/public/protocol-relative-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"response": "protocol-relative-request"
}
3 changes: 3 additions & 0 deletions test-packages/basic-app/public/protocol-relative-url.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"response": "protocol-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-relative-url');
expect(response.body).to.contain('protocol-relative-request');
expect(response.body).to.contain('path-relative-url');
expect(response.body).to.contain('path-relative-request');
});
});

0 comments on commit e47ad1c

Please sign in to comment.