diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index f0fb0ed5ea9..67f3f771dde 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to experimental packages in this project will be documented * allows for experimental usage of this instrumentation with non-browser runtimes * fix(instrumentation-http): memory leak when responses are not resumed * fix(instrumentation-fetch): compatibility with Map types for fetch headers +* fix(instrumentation-http): Do not mutate given headers object for outgoing http requests. Fixes aws-sdk signing error on retries. [#4346](https://github.com/open-telemetry/opentelemetry-js/pull/4346) ## 0.45.1 diff --git a/experimental/packages/opentelemetry-instrumentation-http/src/http.ts b/experimental/packages/opentelemetry-instrumentation-http/src/http.ts index 81e08ac860b..337d058033d 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/src/http.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/src/http.ts @@ -675,6 +675,10 @@ export class HttpInstrumentation extends InstrumentationBase { if (!optionsParsed.headers) { optionsParsed.headers = {}; + } else { + // Make a copy of the headers object to avoid mutating an object the + // caller might have a reference to. + optionsParsed.headers = Object.assign({}, optionsParsed.headers); } propagation.inject(requestContext, optionsParsed.headers); diff --git a/experimental/packages/opentelemetry-instrumentation-http/test/integrations/http-enable.test.ts b/experimental/packages/opentelemetry-instrumentation-http/test/integrations/http-enable.test.ts index 625b8b65499..a04027a2c95 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/test/integrations/http-enable.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/test/integrations/http-enable.test.ts @@ -269,6 +269,20 @@ describe('HttpInstrumentation Integration tests', () => { assertSpan(span, SpanKind.CLIENT, validations); }); + it('should not mutate given headers object when adding propagation headers', async () => { + const spans = memoryExporter.getFinishedSpans(); + assert.strictEqual(spans.length, 0); + + const headers = { 'x-foo': 'foo' }; + const result = await httpRequest.get( + new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`), + { headers } + ); + assert.deepStrictEqual(headers, { 'x-foo': 'foo' }); + assert.ok(result.reqHeaders[DummyPropagation.TRACE_CONTEXT_KEY]); + assert.ok(result.reqHeaders[DummyPropagation.SPAN_CONTEXT_KEY]); + }); + it('should create a span for GET requests and add propagation headers with Expect headers', async () => { let spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 0);