Skip to content

Commit e47ad1c

Browse files
committed
Allow to use relative URLs for fetch
1 parent 9cb1268 commit e47ad1c

File tree

11 files changed

+136
-14
lines changed

11 files changed

+136
-14
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function initialize(instance) {
2+
let { request } = instance.lookup('service:fastboot');
3+
fetch.__fastbootRequest = request;
4+
}
5+
6+
export default {
7+
name: 'fastboot:fetch', // `ember-fetch` addon registers as `fetch`
8+
initialize,
9+
};

packages/fastboot/src/sandbox.js

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ const chalk = require('chalk');
44
const vm = require('vm');
55
const sourceMapSupport = require('source-map-support');
66

7+
const httpRegex = /^https?:\/\//;
8+
const protocolRelativeRegex = /^\/\//;
9+
710
module.exports = class Sandbox {
811
constructor(globals) {
912
this.globals = globals;
@@ -56,27 +59,86 @@ module.exports = class Sandbox {
5659
}
5760

5861
buildFetch() {
62+
let globals;
63+
5964
if (globalThis.fetch) {
60-
return {
65+
globals = {
6166
fetch: globalThis.fetch,
6267
Request: globalThis.Request,
6368
Response: globalThis.Response,
6469
Headers: globalThis.Headers,
6570
AbortController: globalThis.AbortController,
6671
};
72+
} else {
73+
let nodeFetch = require('node-fetch');
74+
let {
75+
AbortController,
76+
abortableFetch,
77+
} = require('abortcontroller-polyfill/dist/cjs-ponyfill');
78+
let { fetch, Request } = abortableFetch({
79+
fetch: nodeFetch,
80+
Request: nodeFetch.Request,
81+
});
82+
83+
globals = {
84+
fetch,
85+
Request,
86+
Response: nodeFetch.Response,
87+
Headers: nodeFetch.Headers,
88+
AbortController,
89+
};
6790
}
6891

69-
let nodeFetch = require('node-fetch');
70-
let { AbortController, abortableFetch } = require('abortcontroller-polyfill/dist/cjs-ponyfill');
71-
let { fetch, Request } = abortableFetch({ fetch: nodeFetch, Request: nodeFetch.Request });
92+
let originalFetch = globals.fetch;
93+
globals.fetch = function __fastbootFetch(input, init) {
94+
input = globals.fetch.__fastbootBuildAbsoluteURL(input);
95+
return originalFetch(input, init);
96+
};
7297

73-
return {
74-
fetch,
75-
Request,
76-
Response: nodeFetch.Response,
77-
Headers: nodeFetch.Headers,
78-
AbortController,
98+
globals.fetch.__fastbootBuildAbsoluteURL = function __fastbootBuildAbsoluteURL(input) {
99+
if (input && input.href) {
100+
// WHATWG URL or Node.js Url Object
101+
input = input.href;
102+
}
103+
104+
if (typeof input !== 'string') {
105+
return input;
106+
}
107+
108+
if (protocolRelativeRegex.test(input)) {
109+
let request = globals.fetch.__fastbootRequest;
110+
let [protocol] = globals.fetch.__fastbootParseRequest(input, request);
111+
input = `${protocol}//${input}`;
112+
} else if (!httpRegex.test(input)) {
113+
let request = globals.fetch.__fastbootRequest;
114+
let [protocol, host] = globals.fetch.__fastbootParseRequest(input, request);
115+
input = `${protocol}//${host}${input}`;
116+
}
117+
118+
return input;
79119
};
120+
121+
globals.fetch.__fastbootParseRequest = function __fastbootParseRequest(url, request) {
122+
if (!request) {
123+
throw new Error(
124+
`Using fetch with relative URL ${url}, but application instance has not been initialized yet.`
125+
);
126+
}
127+
128+
// Old Prember version is not sending protocol
129+
const protocol = request.protocol === 'undefined:' ? 'http:' : request.protocol;
130+
return [protocol, request.host];
131+
};
132+
133+
let OriginalRequest = globals.Request;
134+
globals.Request = class __FastBootRequest extends OriginalRequest {
135+
constructor(input, init) {
136+
input = globals.fetch.__fastbootBuildAbsoluteURL(input);
137+
super(input, init);
138+
}
139+
};
140+
141+
return globals;
80142
}
81143

82144
runScript(script) {

test-packages/basic-app/app/routes/fetch.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Route from '@ember/routing/route';
22
import { assert } from '@ember/debug';
3+
import { hash } from 'rsvp';
34

45
export default class FetchRoute extends Route {
56
beforeModel() {
@@ -11,7 +12,29 @@ export default class FetchRoute extends Route {
1112
}
1213

1314
async model() {
14-
let response = await fetch('https://api.github.com/users/tomster');
15-
return response.json();
15+
let [
16+
absoluteURL,
17+
absoluteRequest,
18+
protocolRelativeURL,
19+
protocolRelativeRequest,
20+
pathRelativeURL,
21+
pathRelativeRequest,
22+
] = await Promise.all([
23+
fetch('http://localhost:45678/absolute-url.json'),
24+
fetch(new Request('http://localhost:45678/absolute-request.json')),
25+
fetch('//localhost:45678/protocol-relative-url.json'),
26+
fetch(new Request('//localhost:45678/protocol-relative-request.json')),
27+
fetch('/path-relative-url.json'),
28+
fetch(new Request('/path-relative-request.json')),
29+
]);
30+
31+
return hash({
32+
absoluteURL: absoluteURL.json(),
33+
absoluteRequest: absoluteRequest.json(),
34+
protocolRelativeURL: protocolRelativeURL.json(),
35+
protocolRelativeRequest: protocolRelativeRequest.json(),
36+
pathRelativeURL: pathRelativeURL.json(),
37+
pathRelativeRequest: pathRelativeRequest.json(),
38+
});
1639
}
1740
}
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
{{@model.login}}
1+
{{@model.absoluteURL.response}}
2+
{{@model.absoluteRequest.response}}
3+
{{@model.protocolRelativeURL.response}}
4+
{{@model.protocolRelativeRequest.response}}
5+
{{@model.pathRelativeURL.response}}
6+
{{@model.pathRelativeRequest.response}}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"response": "absolute-request"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"response": "absolute-url"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"response": "path-relative-request"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"response": "path-relative-url"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"response": "protocol-relative-request"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"response": "protocol-relative-url"
3+
}

0 commit comments

Comments
 (0)