Skip to content

Commit 6961d14

Browse files
committed
apply changes from nestjs#523
1 parent 46fd90f commit 6961d14

File tree

5 files changed

+103
-28
lines changed

5 files changed

+103
-28
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import * as fs from 'fs';
2+
import { validatePath } from '../utils/validate-path.util';
3+
import {
4+
ArgumentsHost,
5+
Catch,
6+
HttpException,
7+
NotFoundException
8+
} from '@nestjs/common';
9+
import { ServeStaticModuleOptions } from '../interfaces/serve-static-options.interface';
10+
import { AbstractLoader } from '../loaders/abstract.loader';
11+
import {
12+
DEFAULT_RENDER_PATH,
13+
DEFAULT_ROOT_PATH
14+
} from '../serve-static.constants';
15+
import { BaseExceptionFilter, HttpAdapterHost } from '@nestjs/core';
16+
import { wildcardToRegExp } from '../utils/wilcard-to-reg-exp.util';
17+
18+
@Catch(NotFoundException)
19+
export class NotFoundExceptionFilter extends BaseExceptionFilter {
20+
constructor(
21+
protected httpAdapterHost: HttpAdapterHost,
22+
private loader: AbstractLoader,
23+
private optionsArr: ServeStaticModuleOptions[]
24+
) {
25+
super(httpAdapterHost.httpAdapter);
26+
}
27+
28+
catch(exception: HttpException, host: ArgumentsHost) {
29+
const ctx = host.switchToHttp();
30+
const response = ctx.getResponse();
31+
const request = ctx.getRequest();
32+
33+
const opts = this.isRenderPath(request);
34+
35+
if( opts === undefined ){
36+
return super.catch(exception, host);
37+
}
38+
39+
opts.renderPath = opts.renderPath || DEFAULT_RENDER_PATH;
40+
const clientPath = opts.rootPath || DEFAULT_ROOT_PATH;
41+
const indexFilePath = this.loader.getIndexFilePath(clientPath);
42+
43+
const stream = fs.createReadStream(indexFilePath);
44+
if (opts.serveStaticOptions && opts.serveStaticOptions.setHeaders) {
45+
const stat = fs.statSync(indexFilePath);
46+
opts.serveStaticOptions.setHeaders(response, indexFilePath, stat);
47+
}
48+
response.type('text/html').send(stream);
49+
}
50+
51+
private isRenderPath(request): ServeStaticModuleOptions | undefined {
52+
return this.optionsArr.find( opts => {
53+
let renderPath: string | RegExp = opts.renderPath || DEFAULT_RENDER_PATH;
54+
55+
if( opts.serveRoot ) {
56+
renderPath =
57+
typeof opts.serveRoot === 'string'
58+
? opts.serveRoot + validatePath(renderPath as string)
59+
: opts.serveRoot;
60+
}
61+
62+
const re = renderPath instanceof RegExp ? renderPath : wildcardToRegExp(renderPath);
63+
const queryParamsIndex = request.url.indexOf('?');
64+
const pathname =
65+
queryParamsIndex >= 0
66+
? request.url.slice(0, queryParamsIndex)
67+
: request.url;
68+
69+
return re.exec(pathname) ? true : false;
70+
});
71+
}
72+
}

lib/loaders/fastify.loader.ts

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,43 +27,19 @@ export class FastifyLoader extends AbstractLoader {
2727
options.renderPath = options.renderPath || DEFAULT_RENDER_PATH;
2828

2929
const clientPath = options.rootPath || DEFAULT_ROOT_PATH;
30-
const indexFilePath = this.getIndexFilePath(clientPath);
3130

3231
if (options.serveRoot) {
3332
app.register(fastifyStatic, {
3433
root: clientPath,
3534
...(options.serveStaticOptions || {}),
36-
wildcard: false,
3735
prefix: options.serveRoot
3836
});
39-
40-
const renderPath =
41-
typeof options.serveRoot === 'string'
42-
? options.serveRoot + validatePath(options.renderPath as string)
43-
: options.serveRoot;
44-
45-
app.get(renderPath, (req: any, res: any) => {
46-
const stream = fs.createReadStream(indexFilePath);
47-
res.type('text/html').send(stream);
48-
});
4937
} else {
5038
app.register(fastifyStatic, {
5139
root: clientPath,
52-
...(options.serveStaticOptions || {}),
53-
wildcard: false
54-
});
55-
app.get(options.renderPath, (req: any, res: any) => {
56-
const stream = fs.createReadStream(indexFilePath);
57-
if (
58-
options.serveStaticOptions &&
59-
options.serveStaticOptions.setHeaders
60-
) {
61-
const stat = fs.statSync(indexFilePath);
62-
options.serveStaticOptions.setHeaders(res, indexFilePath, stat);
63-
}
64-
res.type('text/html').send(stream);
40+
...(options.serveStaticOptions || {})
6541
});
6642
}
6743
});
6844
}
69-
}
45+
}

lib/serve-static.providers.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import { Provider } from '@nestjs/common';
2-
import { HttpAdapterHost } from '@nestjs/core';
2+
import { APP_FILTER, HttpAdapterHost } from '@nestjs/core';
3+
import { NotFoundExceptionFilter } from './filters/not-found-excepion.filter';
4+
import { ServeStaticModuleOptions } from './interfaces/serve-static-options.interface';
35
import { AbstractLoader } from './loaders/abstract.loader';
46
import { ExpressLoader } from './loaders/express.loader';
57
import { FastifyLoader } from './loaders/fastify.loader';
68
import { NoopLoader } from './loaders/noop.loader';
9+
import { SERVE_STATIC_MODULE_OPTIONS } from './serve-static.constants';
710

811
export const serveStaticProviders: Provider[] = [
912
{
@@ -23,5 +26,13 @@ export const serveStaticProviders: Provider[] = [
2326
return new ExpressLoader();
2427
},
2528
inject: [HttpAdapterHost]
29+
},
30+
{
31+
provide: APP_FILTER,
32+
useFactory: (httpAdapterHost: HttpAdapterHost, loader: AbstractLoader, opts: ServeStaticModuleOptions[]) => {
33+
if( loader instanceof FastifyLoader )
34+
return new NotFoundExceptionFilter(httpAdapterHost, loader, opts);
35+
},
36+
inject: [HttpAdapterHost, AbstractLoader, SERVE_STATIC_MODULE_OPTIONS]
2637
}
27-
];
38+
];

lib/utils/reg-escape.util.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* Escapes all characters in the given string
3+
*/
4+
export const regExpEscape = (s: string) =>
5+
s.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { regExpEscape } from "./reg-escape.util";
2+
3+
/**
4+
* Creates a RegExp from the given string, allowing wildcards.
5+
*
6+
* "*" will be converted to ".*"
7+
* "?" will be converted to "."
8+
*
9+
* Escapes the rest of the characters
10+
*/
11+
export const wildcardToRegExp = (s: string) => new RegExp('^' + s.split(/\*+/).map(regExpEscape).join('.*').replace(/\\\?/g, '.') + '$');

0 commit comments

Comments
 (0)