|
| 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 | +} |
0 commit comments