fix: allow request aborting
This commit is contained in:
parent
85aa9d78ca
commit
f07af8fe6e
|
@ -5,7 +5,7 @@ import ssr from './ssr';
|
|||
export const hooks = {
|
||||
'@flecks/electron/server.extensions': (installer) => [installer.REACT_DEVELOPER_TOOLS],
|
||||
'@flecks/web/server.stream.html': Flecks.priority(
|
||||
(stream, req, flecks) => (
|
||||
(stream, req, res, flecks) => (
|
||||
flecks.get('@flecks/react.ssr') ? ssr(stream, req, flecks) : stream
|
||||
),
|
||||
{after: '@flecks/web/server'},
|
||||
|
|
|
@ -49,11 +49,19 @@ export const hooks = {
|
|||
},
|
||||
/**
|
||||
* Define composition functions to run over the HTML stream prepared for the client.
|
||||
*
|
||||
* @param {stream.Readable} stream The HTML stream.
|
||||
* @param {http.ClientRequest} req The HTTP request object.
|
||||
* @param {http.ServerResponse} res The HTTP response object.
|
||||
* @returns {stream.Duplex} The stream to pipe to the response.
|
||||
* @invoke ComposedAsync
|
||||
*/
|
||||
'@flecks/web/server.stream.html': (stream, req) => {
|
||||
'@flecks/web/server.stream.html': (stream, req, res) => {
|
||||
// You may call `req.abort()` to abort the request if you e.g. respond to it early:
|
||||
if ('some-redirect-condition') {
|
||||
res.redirect('/somewhere', 301);
|
||||
req.abort();
|
||||
}
|
||||
return stream.pipe(myTransformStream);
|
||||
},
|
||||
/**
|
||||
|
|
1
packages/web/src/server/abort.js
Normal file
1
packages/web/src/server/abort.js
Normal file
|
@ -0,0 +1 @@
|
|||
export class Abort extends Error {}
|
|
@ -56,4 +56,6 @@ class InlineConfig extends Transform {
|
|||
|
||||
}
|
||||
|
||||
export const inlineConfig = (stream, req, flecks) => stream.pipe(new InlineConfig(flecks, req));
|
||||
export const inlineConfig = (stream, req, res, flecks) => (
|
||||
stream.pipe(new InlineConfig(flecks, req))
|
||||
);
|
||||
|
|
|
@ -10,6 +10,8 @@ import compression from 'compression';
|
|||
import express from 'express';
|
||||
import httpProxy from 'http-proxy';
|
||||
|
||||
import {Abort} from './abort';
|
||||
|
||||
const {
|
||||
FLECKS_CORE_ROOT = process.cwd(),
|
||||
FLECKS_WEB_DEV_SERVER,
|
||||
|
@ -19,8 +21,28 @@ const {
|
|||
|
||||
const debug = D('@flecks/web/server/http');
|
||||
|
||||
const deliverHtmlStream = async (stream, flecks, req, res) => {
|
||||
(await flecks.invokeComposedAsync('@flecks/web/server.stream.html', stream, req)).pipe(res);
|
||||
const deliverHtmlStream = async (stream, req, res, flecks) => {
|
||||
req.abort = () => {
|
||||
throw new Abort();
|
||||
};
|
||||
let walk = stream;
|
||||
const implementations = flecks.flecksImplementing('@flecks/web/server.stream.html');
|
||||
for (let i = 0; i < implementations.length; ++i) {
|
||||
const fleck = implementations[i];
|
||||
const implementation = flecks.fleckImplementation(fleck, '@flecks/web/server.stream.html');
|
||||
try {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
walk = await implementation(walk, req, res, flecks);
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof Abort) {
|
||||
res.status(500).end();
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
walk.pipe(res);
|
||||
};
|
||||
|
||||
export const createHttpServer = async (flecks) => {
|
||||
|
@ -169,7 +191,7 @@ export const createHttpServer = async (flecks) => {
|
|||
if (!res.headersSent) {
|
||||
res.setHeader('Content-Type', proxyRes.headers['content-type']);
|
||||
}
|
||||
deliverHtmlStream(proxyRes, flecks, req, res);
|
||||
deliverHtmlStream(proxyRes, req, res, flecks);
|
||||
});
|
||||
}
|
||||
// Any other assets.
|
||||
|
@ -211,7 +233,7 @@ export const createHttpServer = async (flecks) => {
|
|||
if (req.accepts('text/html')) {
|
||||
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
|
||||
const stream = createReadStream(join(FLECKS_CORE_ROOT, 'dist', 'web', 'index.html'));
|
||||
deliverHtmlStream(stream, flecks, req, res);
|
||||
deliverHtmlStream(stream, req, res, flecks);
|
||||
}
|
||||
else {
|
||||
res.status(400).end('Bad Request');
|
||||
|
|
17
packages/web/test/abort-request.js
Normal file
17
packages/web/test/abort-request.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
import {expect} from 'chai';
|
||||
|
||||
import {withWeb} from '@flecks/headless/test/helpers/with-web';
|
||||
|
||||
it('allows request aborting', withWeb(
|
||||
async ({
|
||||
response,
|
||||
}) => {
|
||||
expect(response)
|
||||
.to.not.be.null;
|
||||
expect(response.ok())
|
||||
.to.be.false;
|
||||
},
|
||||
{
|
||||
template: 'templates/abort-request',
|
||||
},
|
||||
));
|
|
@ -0,0 +1 @@
|
|||
export const hooks = {};
|
|
@ -0,0 +1,5 @@
|
|||
export const hooks = {
|
||||
'@flecks/web/server.stream.html': async (stream, req) => {
|
||||
req.abort();
|
||||
},
|
||||
};
|
4
packages/web/test/templates/up/build/flecks.yml
Normal file
4
packages/web/test/templates/up/build/flecks.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
'@flecks/core': {}
|
||||
'@flecks/server': {}
|
||||
'@flecks/web': {}
|
||||
'test:./test': {}
|
1
packages/web/test/templates/up/package.json
Normal file
1
packages/web/test/templates/up/package.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
1
packages/web/test/templates/up/test/package.json
Normal file
1
packages/web/test/templates/up/test/package.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -4,12 +4,6 @@ import {withWeb} from '@flecks/headless/test/helpers/with-web';
|
|||
|
||||
let report;
|
||||
|
||||
const options = {
|
||||
beforeConnect: ({socket}) => {
|
||||
report = socket.waitForAction('report');
|
||||
},
|
||||
};
|
||||
|
||||
it('brings a client up', withWeb(
|
||||
async ({
|
||||
page,
|
||||
|
@ -37,5 +31,10 @@ it('brings a client up', withWeb(
|
|||
expect(request)
|
||||
.to.equal('testing-value-value');
|
||||
},
|
||||
options,
|
||||
{
|
||||
beforeConnect: ({socket}) => {
|
||||
report = socket.waitForAction('report');
|
||||
},
|
||||
template: 'templates/up',
|
||||
},
|
||||
));
|
||||
|
|
Loading…
Reference in New Issue
Block a user