diff --git a/src/cli.ts b/src/cli.ts index 0046ee92..f913c0f3 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -24,6 +24,10 @@ async function main(argv: string[]) { "Request headers to redact", commaSeparatedList ) + .option( + "--no-drop-conditional-request-headers", + "When running in record mode, by default, `If-*` headers from outgoing requests are dropped in an attempt to prevent the suite of conditional responses being returned (e.g. 304). Supplying this flag disables this default behaviour" + ) .parse(argv); const initialMode: string = (program.mode || "").toLowerCase(); @@ -32,6 +36,7 @@ async function main(argv: string[]) { const host: string = program.host; const port = parseInt(program.port, 10); const redactHeaders: string[] = program.redactHeaders; + const preventConditionalRequests: boolean = !!program.dropConditionalRequestHeaders; switch (initialMode) { case "record": @@ -55,6 +60,12 @@ async function main(argv: string[]) { ); } + if (preventConditionalRequests && initialMode === "record") { + console.info( + "The prevent conditional requests flag is enabled in record mode. All received `If-*` headers will not be forwarded on upstream and will not be recorded in tapes." + ); + } + // Expect a host unless we're in replay mode. if (initialMode !== "replay") { if (!host) { @@ -72,6 +83,7 @@ async function main(argv: string[]) { defaultTapeName, enableLogging: true, redactHeaders, + preventConditionalRequests, }); await server.start(port); console.log(chalk.green(`Proxying in ${initialMode} mode on port ${port}.`)); diff --git a/src/server.ts b/src/server.ts index 8c68216a..1875d905 100644 --- a/src/server.ts +++ b/src/server.ts @@ -23,6 +23,7 @@ export class RecordReplayServer { private loggingEnabled: boolean; private defaultTape: string; private replayedTapes: Set = new Set(); + private preventConditionalRequests?: boolean; constructor(options: { initialMode: Mode; @@ -32,6 +33,7 @@ export class RecordReplayServer { timeout?: number; enableLogging?: boolean; redactHeaders?: string[]; + preventConditionalRequests?: boolean; }) { this.currentTapeRecords = []; this.mode = options.initialMode; @@ -41,6 +43,7 @@ export class RecordReplayServer { const redactHeaders = options.redactHeaders || []; this.persistence = new Persistence(options.tapeDir, redactHeaders); this.defaultTape = options.defaultTapeName; + this.preventConditionalRequests = options.preventConditionalRequests; this.loadTape(this.defaultTape); this.server = http.createServer(async (req, res) => { @@ -57,6 +60,15 @@ export class RecordReplayServer { return; } + if ( + this.preventConditionalRequests && + (req.method === "GET" || req.method === "HEAD") + ) { + // Headers are always coming in as lowercase. + delete req.headers["if-modified-since"]; + delete req.headers["if-none-match"]; + } + try { const request: Request = { method: req.method,