From 50d6a8ba46228ce840282a09f49926ed4e92c148 Mon Sep 17 00:00:00 2001 From: ujjwalgupta94 Date: Tue, 21 Jan 2025 21:07:56 +0530 Subject: [PATCH] refactor file handler --- src/handlers/file_handler.ts | 73 ++++++++++++++++---------- src/handlers/request_handler.ts | 16 ++++-- src/handlers/request_handler_helper.ts | 10 ++-- src/interfaces/file_result_info.ts | 9 ++-- 4 files changed, 70 insertions(+), 38 deletions(-) diff --git a/src/handlers/file_handler.ts b/src/handlers/file_handler.ts index 06385ae..7eeeed5 100644 --- a/src/handlers/file_handler.ts +++ b/src/handlers/file_handler.ts @@ -1,12 +1,13 @@ -import { HTTP_STATUS_CODE, MIME_TYPE, ETAG_TYPE } from "../enums"; +import { HTTP_STATUS_CODE, MIME_TYPE, ETAG_TYPE, HTTP_RESULT_TYPE } from "../enums"; import * as path from "path"; import { CONTENT_TYPE } from "../constants"; import * as Fs from "fs"; -import { getMimeTypeFromFileType, promise } from "../helpers"; +import { getMimeTypeFromExtension, getMimeTypeFromFileType, promise } from "../helpers"; import * as etag from "etag"; import * as fresh from "fresh"; import { isNullOrEmpty } from "../utils"; import { RequestHandler } from "./request_handler"; +import { IFileResultInfo, IHttpResult } from "../interfaces"; interface IFileInfo { folder: string, @@ -19,6 +20,13 @@ export class FileHandler { } + private returnFileResult_(filePath: string, fileInfo: Fs.Stats) { + return { + filePath: filePath, + fileInfo: fileInfo + } as IFileResultInfo; + }; + private getFileInfoFromUrl_(urlPath: string) { const splittedValue = urlPath.split("/"); const fileInfo = { @@ -53,20 +61,19 @@ export class FileHandler { }); } - handleFileRequestFromAbsolutePath(absolutePath: string, fileType: string) { - return this.getFileStats_(absolutePath).then(fileInfo => { - if (fileInfo != null) { - if (fileInfo.isDirectory() === true) { - return this.handleFileRequestForFolderPath_(absolutePath); - } - else { - return this.sendFile_(absolutePath, fileType, fileInfo); - } + async getFileResultFromAbsolutePath(absolutePath: string) { + const fileInfo = await this.getFileStats_(absolutePath); + if (fileInfo != null) { + if (fileInfo.isDirectory() === true) { + return this.getFileResultForFolderPath_(absolutePath); } else { - return this.requestHandler.onNotFound(); + return this.getFile_(absolutePath, fileInfo); } - }); + } + // else { + // return this.requestHandler.onNotFound(); + // } } private checkForFolderAllowAndReturnPath_(urlPath: string) { @@ -87,15 +94,21 @@ export class FileHandler { return absPath; } - handleFileRequest(urlPath: string) { - const extension = path.parse(urlPath).ext; + async handleFileRequest(urlPath: string) { const absFilePath = this.checkForFolderAllowAndReturnPath_(urlPath); if (absFilePath != null) { - return this.handleFileRequestFromAbsolutePath(absFilePath, extension); - } - else { - return this.requestHandler.onNotFound(); + const filePathInfo = await this.getFileResultFromAbsolutePath(absFilePath); + if (filePathInfo) { + return { + type: HTTP_RESULT_TYPE.File, + responseData: filePathInfo + } as IHttpResult; + } } + // else { + // return null; + // // return this.requestHandler.onNotFound(); + // } } /** @@ -108,13 +121,12 @@ export class FileHandler { * @returns * @memberof FileHandler */ - private handleFileRequestForFolderPath_(absolutePath: string) { + private async getFileResultForFolderPath_(absolutePath: string) { absolutePath = path.join(absolutePath, "index.html"); - return this.getFileStats_(absolutePath).then(fileInfo => { - return fileInfo != null ? - this.sendFile_(absolutePath, MIME_TYPE.Html, fileInfo) : - this.requestHandler.onNotFound(); - }); + const fileInfo = await this.getFileStats_(absolutePath); + return fileInfo != null ? + this.getFile_(absolutePath, fileInfo) : + null; } protected isClientHasFreshFile(lastModified: string, etagValue: string) { @@ -137,20 +149,27 @@ export class FileHandler { }); } - sendFile_(filePath: string, fileType: string, fileInfo: Fs.Stats) { + send(filePathInfo: IFileResultInfo) { + const { fileInfo, filePath } = filePathInfo; const lastModified = fileInfo.mtime.toUTCString(); const eTagValue = etag(fileInfo, { weak: this.requestHandler.config.eTag.type === ETAG_TYPE.Weak }); const response = this.requestHandler.response; response.setHeader('Etag', eTagValue); + const extension = path.parse(filePath).ext; + const mimeType = getMimeTypeFromExtension(extension); if (this.isClientHasFreshFile(lastModified, eTagValue)) { // client has fresh file response.statusCode = HTTP_STATUS_CODE.NotModified; response.end(); } else { response.setHeader('Last-Modified', lastModified); - this.sendFileAsResponse(filePath, getMimeTypeFromFileType(fileType)); + this.sendFileAsResponse(filePath, mimeType); } } + + private getFile_(filePath: string, fileInfo: Fs.Stats) { + return this.returnFileResult_(filePath, fileInfo); + } } diff --git a/src/handlers/request_handler.ts b/src/handlers/request_handler.ts index a36f9b5..22c405c 100644 --- a/src/handlers/request_handler.ts +++ b/src/handlers/request_handler.ts @@ -172,13 +172,19 @@ export class RequestHandler extends RequestHandlerHelper { return this.handleFinalResult_(); } const pathUrl = urlDetail.pathname; - this.routeMatchInfo_ = parseAndMatchRoute(pathUrl, request.method as HTTP_METHOD); + const onNotRouteMatched = async () => { + const fileHandler = new FileHandler(this); + const fileResult = await fileHandler.handleFileRequest(pathUrl); + if (fileResult == null) { + return () => { + return this.onNotFound(); + } + } + return this.onResultFromComponent(fileResult); + }; const finalCallback = await ( - this.routeMatchInfo_ == null ? () => { - const fileHandler = new FileHandler(this); - return fileHandler.handleFileRequest(pathUrl); - } : + this.routeMatchInfo_ == null ? onNotRouteMatched() : this.onRouteMatched_() ); await this.runWallOutgoing_(); diff --git a/src/handlers/request_handler_helper.ts b/src/handlers/request_handler_helper.ts index 5ebcd34..178b14e 100644 --- a/src/handlers/request_handler_helper.ts +++ b/src/handlers/request_handler_helper.ts @@ -181,7 +181,7 @@ export class RequestHandlerHelper { return null; } - private handleFileResult_() { + private async handleFileResult_() { const result = this.controllerResult as IHttpResult; const fileResult = result.responseData as IFileResultInfo; const parsedPath = parse(fileResult.filePath); @@ -193,9 +193,13 @@ export class RequestHandlerHelper { ); } const fileHandler = new FileHandler(this as any); - return fileHandler.handleFileRequestFromAbsolutePath( - fileResult.filePath, parsedPath.ext + const fileResultForSendingResponse = fileResult.fileInfo ? fileResult : await fileHandler.getFileResultFromAbsolutePath( + fileResult.filePath ); + if (fileResultForSendingResponse == null) { + return this.onNotFound(); + } + return fileHandler.send(fileResultForSendingResponse); } protected handleFinalResult_() { diff --git a/src/interfaces/file_result_info.ts b/src/interfaces/file_result_info.ts index 47189d5..154205f 100644 --- a/src/interfaces/file_result_info.ts +++ b/src/interfaces/file_result_info.ts @@ -1,5 +1,8 @@ +import { Stats } from "fs"; + export interface IFileResultInfo { filePath: string; - alias: string; - shouldDownload: boolean; -} \ No newline at end of file + alias?: string; + shouldDownload?: boolean; + fileInfo?: Stats +}