diff --git a/src/configuration.ts b/src/configuration.ts index 1dbd4de8..f891b8a6 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -1,12 +1,15 @@ import type * as http from 'node:http'; -import { ERRORS } from './errors.js'; +import { HttpProxyMiddlewareError } from './errors.js'; import type { Options } from './types.js'; export function verifyConfig( options: Options, ): void { if (!options.target && !options.router) { - throw new Error(ERRORS.ERR_CONFIG_FACTORY_TARGET_MISSING); + throw new HttpProxyMiddlewareError( + '[HPM] Missing "target" option. Example: {target: "http://www.example.org"}', + 'ERR_CONFIG_FACTORY_TARGET_MISSING', + ); } } diff --git a/src/errors.ts b/src/errors.ts index c9e337d0..4bc60863 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -1,10 +1,3 @@ -export enum ERRORS { - ERR_CONFIG_FACTORY_TARGET_MISSING = '[HPM] Missing "target" option. Example: {target: "http://www.example.org"}', - ERR_CONTEXT_MATCHER_GENERIC = '[HPM] Invalid pathFilter. Expecting something like: "/api" or ["/api", "/ajax"]', - ERR_CONTEXT_MATCHER_INVALID_ARRAY = '[HPM] Invalid pathFilter. Plain paths (e.g. "/api") can not be mixed with globs (e.g. "/api/**"). Expecting something like: ["/api", "/ajax"] or ["/api/**", "!**.html"].', - ERR_PATH_REWRITER_CONFIG = '[HPM] Invalid pathRewrite config. Expecting object with pathRewrite config or a rewrite function', -} - export class HttpProxyMiddlewareError extends Error { code: string; diff --git a/src/handlers/fix-request-body-utils/stringify-form-data.ts b/src/handlers/fix-request-body-utils/stringify-form-data.ts index 58689901..09fca347 100644 --- a/src/handlers/fix-request-body-utils/stringify-form-data.ts +++ b/src/handlers/fix-request-body-utils/stringify-form-data.ts @@ -1,7 +1,12 @@ import { HttpProxyMiddlewareError } from '../../errors.js'; const CR_OR_LF = /[\r\n]/; -const ERROR_CODE_PREFIX = 'HPM_ERR_INVALID_MULTIPART'; + +/** + * HPM_ERR_INVALID_MULTIPART prefixed error code will be used in + * [status-code.ts]({@link ../../status-code.ts}) to return status code 400. + */ +export const HPM_ERR_INVALID_MULTIPART = 'HPM_ERR_INVALID_MULTIPART'; /** * stringify FormData data @@ -35,7 +40,7 @@ function getMultipartBoundary(contentType: string): string { if (!boundary || CR_OR_LF.test(boundary)) { throw new HttpProxyMiddlewareError( '[HPM] invalid multipart boundary detected.', - `${ERROR_CODE_PREFIX}_BOUNDARY`, + `${HPM_ERR_INVALID_MULTIPART}_BOUNDARY`, ); } @@ -48,14 +53,14 @@ function validateMultipartField(fieldName: string, fieldValue: string, boundary: if (CR_OR_LF.test(fieldName)) { throw new HttpProxyMiddlewareError( `[HPM] invalid multipart field name "${fieldName}" detected.`, - `${ERROR_CODE_PREFIX}_FIELD_NAME`, + `${HPM_ERR_INVALID_MULTIPART}_FIELD_NAME`, ); } if (CR_OR_LF.test(fieldValue) || fieldValue.includes(boundaryDelimiter)) { throw new HttpProxyMiddlewareError( `[HPM] invalid multipart field value for "${fieldName}" detected.`, - `${ERROR_CODE_PREFIX}_FIELD_VALUE`, + `${HPM_ERR_INVALID_MULTIPART}_FIELD_VALUE`, ); } } diff --git a/src/path-filter.ts b/src/path-filter.ts index 9790336b..d5ed2e6f 100644 --- a/src/path-filter.ts +++ b/src/path-filter.ts @@ -3,7 +3,7 @@ import type * as http from 'node:http'; import isGlob from 'is-glob'; import micromatch from 'micromatch'; -import { ERRORS } from './errors.js'; +import { HttpProxyMiddlewareError } from './errors.js'; import type { Filter } from './types.js'; export function matchPathFilter( @@ -30,7 +30,10 @@ export function matchPathFilter { describe('verifyConfig()', () => { @@ -14,7 +15,8 @@ describe('configFactory', () => { }); it('should throw an error when target and router option are missing', () => { - expect(fn).toThrow(Error); + expect(fn).toThrow(HttpProxyMiddlewareError); + expect(fn).toThrow(expect.objectContaining({ code: 'ERR_CONFIG_FACTORY_TARGET_MISSING' })); }); }); diff --git a/test/unit/path-filter.spec.ts b/test/unit/path-filter.spec.ts index fbab8e40..2c813458 100644 --- a/test/unit/path-filter.spec.ts +++ b/test/unit/path-filter.spec.ts @@ -1,5 +1,6 @@ import { beforeEach, describe, expect, it } from 'vitest'; +import { HttpProxyMiddlewareError } from '../../src/errors.js'; import { matchPathFilter } from '../../src/path-filter.js'; import { createMockRequest } from '../test-utils.js'; @@ -215,19 +216,31 @@ describe('Path Filter', () => { describe('Throw error', () => { it('should throw error with null', () => { - expect(testPathFilter(null)).toThrow(Error); + expect(testPathFilter(null)).toThrow(HttpProxyMiddlewareError); + expect(testPathFilter(null)).toThrow( + expect.objectContaining({ code: 'HPM_INVALID_PATH_FILTER_CONFIG' }), + ); }); it('should throw error with object literal', () => { - expect(testPathFilter(mockReq)).toThrow(Error); + expect(testPathFilter(mockReq)).toThrow(HttpProxyMiddlewareError); + expect(testPathFilter(mockReq)).toThrow( + expect.objectContaining({ code: 'HPM_INVALID_PATH_FILTER_CONFIG' }), + ); }); it('should throw error with integers', () => { - expect(testPathFilter(123)).toThrow(Error); + expect(testPathFilter(123)).toThrow(HttpProxyMiddlewareError); + expect(testPathFilter(123)).toThrow( + expect.objectContaining({ code: 'HPM_INVALID_PATH_FILTER_CONFIG' }), + ); }); it('should throw error with mixed string and glob pattern', () => { - expect(testPathFilter(['/api', '!*.html'])).toThrow(Error); + expect(testPathFilter(['/api', '!*.html'])).toThrow(HttpProxyMiddlewareError); + expect(testPathFilter(['/api', '!*.html'])).toThrow( + expect.objectContaining({ code: 'HPM_INVALID_PATH_FILTER_ARRAY_CONFIG' }), + ); }); }); diff --git a/test/unit/path-rewriter.spec.ts b/test/unit/path-rewriter.spec.ts index bc5ff68e..49219334 100644 --- a/test/unit/path-rewriter.spec.ts +++ b/test/unit/path-rewriter.spec.ts @@ -1,5 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { HttpProxyMiddlewareError } from '../../src/errors.js'; import { createPathRewriter } from '../../src/path-rewriter.js'; import type { Options } from '../../src/types.js'; import type { PathRewriteConfig } from '../../src/types.js'; @@ -150,10 +151,14 @@ describe('Path rewriting', () => { }); it('should throw when bad config is provided', () => { - expect(badFn(123 as unknown as PathRewriteConfig)).toThrow(Error); - expect(badFn('abc' as unknown as PathRewriteConfig)).toThrow(Error); - expect(badFn([] as unknown as PathRewriteConfig)).toThrow(Error); - expect(badFn([1, 2, 3] as unknown as PathRewriteConfig)).toThrow(Error); + expect(badFn(123 as unknown as PathRewriteConfig)).toThrow(HttpProxyMiddlewareError); + expect(badFn('abc' as unknown as PathRewriteConfig)).toThrow( + expect.objectContaining({ code: 'HPM_INVALID_PATH_REWRITER_CONFIG' }), + ); + expect(badFn([] as unknown as PathRewriteConfig)).toThrow(HttpProxyMiddlewareError); + expect(badFn([1, 2, 3] as unknown as PathRewriteConfig)).toThrow( + expect.objectContaining({ code: 'HPM_INVALID_PATH_REWRITER_CONFIG' }), + ); }); it('should not throw when empty Object config is provided', () => {