mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-18 05:25:08 +00:00
implement this.fetch (#178)
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
"cheerio": "^1.0.0-rc.2",
|
"cheerio": "^1.0.0-rc.2",
|
||||||
"chokidar": "^2.0.2",
|
"chokidar": "^2.0.2",
|
||||||
"clorox": "^1.0.3",
|
"clorox": "^1.0.3",
|
||||||
|
"cookie": "^0.3.1",
|
||||||
"devalue": "^1.0.1",
|
"devalue": "^1.0.1",
|
||||||
"glob": "^7.1.2",
|
"glob": "^7.1.2",
|
||||||
"html-minifier": "^3.5.11",
|
"html-minifier": "^3.5.11",
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { resolve } from 'url';
|
import { resolve, URL } from 'url';
|
||||||
import { ClientRequest, ServerResponse } from 'http';
|
import { ClientRequest, ServerResponse } from 'http';
|
||||||
|
import cookie from 'cookie';
|
||||||
import mkdirp from 'mkdirp';
|
import mkdirp from 'mkdirp';
|
||||||
import rimraf from 'rimraf';
|
import rimraf from 'rimraf';
|
||||||
import devalue from 'devalue';
|
import devalue from 'devalue';
|
||||||
|
import fetch from 'node-fetch';
|
||||||
import { lookup } from './middleware/mime';
|
import { lookup } from './middleware/mime';
|
||||||
import { create_routes, create_compilers } from './core';
|
import { create_routes, create_compilers } from './core';
|
||||||
import { locations, dev } from './config';
|
import { locations, dev } from './config';
|
||||||
@@ -42,6 +44,7 @@ interface Req extends ClientRequest {
|
|||||||
method: string;
|
method: string;
|
||||||
path: string;
|
path: string;
|
||||||
params: Record<string, string>;
|
params: Record<string, string>;
|
||||||
|
headers: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function middleware({ routes, store }: {
|
export default function middleware({ routes, store }: {
|
||||||
@@ -163,6 +166,41 @@ function get_route_handler(chunks: Record<string, string>, routes: RouteObject[]
|
|||||||
error: (statusCode: number, message: Error | string) => {
|
error: (statusCode: number, message: Error | string) => {
|
||||||
error = { statusCode, message };
|
error = { statusCode, message };
|
||||||
},
|
},
|
||||||
|
fetch: (url: string, opts?: any) => {
|
||||||
|
const parsed = new URL(url, `http://127.0.0.1:${process.env.PORT}${req.baseUrl}${req.path}`);
|
||||||
|
|
||||||
|
if (opts) {
|
||||||
|
opts = Object.assign({}, opts);
|
||||||
|
|
||||||
|
const include_cookies = (
|
||||||
|
opts.credentials === 'include' ||
|
||||||
|
opts.credentials === 'same-origin' && parsed.origin === `http://127.0.0.1:${process.env.PORT}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (include_cookies) {
|
||||||
|
const cookies: Record<string, string> = {};
|
||||||
|
if (!opts.headers) opts.headers = {};
|
||||||
|
|
||||||
|
const str = []
|
||||||
|
.concat(
|
||||||
|
cookie.parse(req.headers.cookie || ''),
|
||||||
|
cookie.parse(opts.headers.cookie || ''),
|
||||||
|
cookie.parse(res.getHeader('Set-Cookie') || '')
|
||||||
|
)
|
||||||
|
.map(cookie => {
|
||||||
|
return Object.keys(cookie)
|
||||||
|
.map(name => `${name}=${encodeURIComponent(cookie[name])}`)
|
||||||
|
.join('; ');
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(', ');
|
||||||
|
|
||||||
|
opts.headers.cookie = str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(parsed.href, opts);
|
||||||
|
},
|
||||||
store
|
store
|
||||||
}, req) : {}
|
}, req) : {}
|
||||||
).catch(err => {
|
).catch(err => {
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ function prepare_route(Component: ComponentConstructor, data: RouteData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve(Component.preload.call({
|
return Promise.resolve(Component.preload.call({
|
||||||
|
store,
|
||||||
|
fetch: (url: string, opts?: any) => window.fetch(url, opts),
|
||||||
redirect: (statusCode: number, location: string) => {
|
redirect: (statusCode: number, location: string) => {
|
||||||
redirect = { statusCode, location };
|
redirect = { statusCode, location };
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -43,6 +43,13 @@ global.fetch = (url, opts) => {
|
|||||||
const middlewares = [
|
const middlewares = [
|
||||||
serve('assets'),
|
serve('assets'),
|
||||||
|
|
||||||
|
// set test cookie
|
||||||
|
(req, res, next) => {
|
||||||
|
res.setHeader('Set-Cookie', 'test=woohoo!; Max-Age=3600');
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
|
||||||
|
// emit messages so we can capture requests
|
||||||
(req, res, next) => {
|
(req, res, next) => {
|
||||||
if (!pending) return next();
|
if (!pending) return next();
|
||||||
|
|
||||||
|
|||||||
12
test/app/routes/credentials/index.html
Normal file
12
test/app/routes/credentials/index.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<h1>{{message}}</h1>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
preload({ query }) {
|
||||||
|
console.log(`here ${this.fetch}`);
|
||||||
|
return this.fetch(`credentials/test.json`, {
|
||||||
|
credentials: query.creds
|
||||||
|
}).then(r => r.json());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
28
test/app/routes/credentials/test.json.js
Normal file
28
test/app/routes/credentials/test.json.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
export function get(req, res) {
|
||||||
|
const cookies = req.headers.cookie
|
||||||
|
? req.headers.cookie.split(/,\s+/).reduce((cookies, cookie) => {
|
||||||
|
const [pair] = cookie.split('; ');
|
||||||
|
const [name, value] = pair.split('=');
|
||||||
|
cookies[name] = value;
|
||||||
|
return cookies;
|
||||||
|
}, {})
|
||||||
|
: {};
|
||||||
|
|
||||||
|
if (cookies.test) {
|
||||||
|
res.writeHead(200, {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
});
|
||||||
|
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
message: cookies.test
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
res.writeHead(403, {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
});
|
||||||
|
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
message: 'unauthorized'
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
<a href='redirect-from'>redirect</a>
|
<a href='redirect-from'>redirect</a>
|
||||||
<a href='blog/nope'>broken link</a>
|
<a href='blog/nope'>broken link</a>
|
||||||
<a href='blog/throw-an-error'>error link</a>
|
<a href='blog/throw-an-error'>error link</a>
|
||||||
|
<a href='credentials?creds=include'>credentials</a>
|
||||||
<a rel=prefetch class='{{page === "blog" ? "selected" : ""}}' href='blog'>blog</a>
|
<a rel=prefetch class='{{page === "blog" ? "selected" : ""}}' href='blog'>blog</a>
|
||||||
|
|
||||||
<div class='hydrate-test'></div>
|
<div class='hydrate-test'></div>
|
||||||
|
|||||||
@@ -533,6 +533,32 @@ function run({ mode, basepath = '' }) {
|
|||||||
assert.equal(title, 'Stored title');
|
assert.equal(title, 'Stored title');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sends cookies when using this.fetch with credentials: "include"', () => {
|
||||||
|
return nightmare.goto(`${base}/credentials?creds=include`)
|
||||||
|
.page.title()
|
||||||
|
.then(title => {
|
||||||
|
assert.equal(title, 'woohoo!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not send cookies when using this.fetch without credentials', () => {
|
||||||
|
return nightmare.goto(`${base}/credentials`)
|
||||||
|
.page.title()
|
||||||
|
.then(title => {
|
||||||
|
assert.equal(title, 'unauthorized');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('delegates to fetch on the client', () => {
|
||||||
|
return nightmare.goto(base).init()
|
||||||
|
.click('[href="credentials?creds=include"]')
|
||||||
|
.wait(100)
|
||||||
|
.page.title()
|
||||||
|
.then(title => {
|
||||||
|
assert.equal(title, 'woohoo!');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('headers', () => {
|
describe('headers', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user