From 856de6473ddd5c2dfd522c94341d943410a32ea9 Mon Sep 17 00:00:00 2001 From: rkodev <43806892+rkodev@users.noreply.github.com> Date: Thu, 16 Jan 2025 04:57:57 +0300 Subject: [PATCH] fix: handles 3xx responses with no header --- .../http/fetch/src/fetchRequestAdapter.ts | 3 +- .../fetch/test/common/fetchRequestAdapter.ts | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/packages/http/fetch/src/fetchRequestAdapter.ts b/packages/http/fetch/src/fetchRequestAdapter.ts index 6209ad587..fe82d214d 100644 --- a/packages/http/fetch/src/fetchRequestAdapter.ts +++ b/packages/http/fetch/src/fetchRequestAdapter.ts @@ -390,10 +390,11 @@ export class FetchRequestAdapter implements RequestAdapter { }; public static readonly errorMappingFoundAttributeName = "com.microsoft.kiota.error.mapping_found"; public static readonly errorBodyFoundAttributeName = "com.microsoft.kiota.error.body_found"; + private static readonly locationHeaderName = "Location"; private readonly throwIfFailedResponse = (response: Response, errorMappings: ErrorMappings | undefined, spanForAttributes: Span): Promise => { return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("throwIfFailedResponse", async (span) => { try { - if (response.ok) return; + if (response.ok || (response.status >= 300 && response.status < 400 && !response.headers.has(FetchRequestAdapter.locationHeaderName))) return; spanForAttributes.setStatus({ code: SpanStatusCode.ERROR, diff --git a/packages/http/fetch/test/common/fetchRequestAdapter.ts b/packages/http/fetch/test/common/fetchRequestAdapter.ts index 80fb063ae..c8a651611 100644 --- a/packages/http/fetch/test/common/fetchRequestAdapter.ts +++ b/packages/http/fetch/test/common/fetchRequestAdapter.ts @@ -208,4 +208,49 @@ describe("FetchRequestAdapter.ts", () => { } }); }); + describe("returns null on 3XX responses without location header", () => { + it("should not throw API error when 3XX response with no Location header", async () => { + const mockHttpClient = new HttpClient(); + mockHttpClient.executeFetch = async (url: string, requestInit: RequestInit, requestOptions?: Record) => { + const response = new Response(null, { + status: 304, + } as ResponseInit); + response.headers.set("Content-Type", "application/json"); + return Promise.resolve(response); + }; + const mockFactory = new MockParseNodeFactory(new MockParseNode({})); + const requestAdapter = new FetchRequestAdapter(new AnonymousAuthenticationProvider(), mockFactory, undefined, mockHttpClient); + const requestInformation = new RequestInformation(); + requestInformation.URL = "https://www.example.com"; + requestInformation.httpMethod = HttpMethod.GET; + try { + const result = await requestAdapter.send(requestInformation, createMockEntityFromDiscriminatorValue, undefined); + assert.isUndefined(result); + } catch (error) { + assert.fail("Should not throw an error"); + } + }); + it("should throw API error when 3XX response with a Location header", async () => { + const mockHttpClient = new HttpClient(); + mockHttpClient.executeFetch = async (url: string, requestInit: RequestInit, requestOptions?: Record) => { + const response = new Response(null, { + status: 304, + } as ResponseInit); + response.headers.set("Content-Type", "application/json"); + response.headers.set("Location", "xxx"); + return Promise.resolve(response); + }; + const mockFactory = new MockParseNodeFactory(new MockParseNode({})); + const requestAdapter = new FetchRequestAdapter(new AnonymousAuthenticationProvider(), mockFactory, undefined, mockHttpClient); + const requestInformation = new RequestInformation(); + requestInformation.URL = "https://www.example.com"; + requestInformation.httpMethod = HttpMethod.GET; + try { + await requestAdapter.sendNoResponseContent(requestInformation, undefined); + assert.fail("Should have thrown an error"); + } catch (error) { + assert.equal(error.responseStatusCode, 304); + } + }); + }); });