@microsoft/kiota-http-fetchlibrary
Version:
Kiota request adapter implementation with fetch
195 lines • 8.18 kB
JavaScript
/**
* -------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
* See License in the project root for license information.
* -------------------------------------------------------------------------------------------
*/
/**
* @module RedirectHandler
*/
import { HttpMethod } from "@microsoft/kiota-abstractions";
import { trace } from "@opentelemetry/api";
import { getObservabilityOptionsFromRequest } from "../observabilityOptions.js";
import { RedirectHandlerOptionKey, RedirectHandlerOptions } from "./options/redirectHandlerOptions.js";
/**
*
* Class
* Middleware
* Class representing RedirectHandler
*/
export class RedirectHandler {
/**
*
*
* To create an instance of RedirectHandler
* @param [options] - The redirect handler options instance
* @returns An instance of RedirectHandler
*/
constructor(options = new RedirectHandlerOptions()) {
this.options = options;
if (!options) {
throw new Error("The options parameter is required.");
}
}
/**
*
* To check whether the response has the redirect status code or not
* @param response - The response object
* @returns A boolean representing whether the response contains the redirect status code or not
*/
isRedirect(response) {
return RedirectHandler.REDIRECT_STATUS_CODES.has(response.status);
}
/**
*
* To check whether the response has location header or not
* @param response - The response object
* @returns A boolean representing the whether the response has location header or not
*/
hasLocationHeader(response) {
return response.headers.has(RedirectHandler.LOCATION_HEADER);
}
/**
*
* To get the redirect url from location header in response object
* @param response - The response object
* @returns A redirect url from location header
*/
getLocationHeader(response) {
return response.headers.get(RedirectHandler.LOCATION_HEADER);
}
/**
*
* To check whether the given url is a relative url or not
* @param url - The url string value
* @returns A boolean representing whether the given url is a relative url or not
*/
isRelativeURL(url) {
return !url.includes("://");
}
/**
*
* To check whether the authorization header in the request should be dropped for consequent redirected requests
* @param requestUrl - The request url value
* @param redirectUrl - The redirect url value
* @returns A boolean representing whether the authorization header in the request should be dropped for consequent redirected requests
*/
shouldDropAuthorizationHeader(requestUrl, redirectUrl) {
const schemeHostRegex = /^[A-Za-z].+?:\/\/.+?(?=\/|$)/;
const requestMatches = schemeHostRegex.exec(requestUrl);
let requestAuthority;
let redirectAuthority;
if (requestMatches !== null) {
requestAuthority = requestMatches[0];
}
const redirectMatches = schemeHostRegex.exec(redirectUrl);
if (redirectMatches !== null) {
redirectAuthority = redirectMatches[0];
}
return typeof requestAuthority !== "undefined" && typeof redirectAuthority !== "undefined" && requestAuthority !== redirectAuthority;
}
/**
* To execute the next middleware and to handle in case of redirect response returned by the server
* @param url - The url string value
* @param fetchRequestInit - The Fetch RequestInit object
* @param redirectCount - The redirect count value
* @param currentOptions - The redirect handler options instance
* @param requestOptions - The request options
* @param tracerName - The name to use for the tracer
* @returns A promise that resolves to nothing
*/
async executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions, tracerName) {
var _a;
const response = await ((_a = this.next) === null || _a === void 0 ? void 0 : _a.execute(url, fetchRequestInit, requestOptions));
if (!response) {
throw new Error("Response is undefined");
}
if (redirectCount < currentOptions.maxRedirects && this.isRedirect(response) && this.hasLocationHeader(response) && currentOptions.shouldRedirect(response)) {
++redirectCount;
if (response.status === RedirectHandler.STATUS_CODE_SEE_OTHER) {
fetchRequestInit.method = HttpMethod.GET;
delete fetchRequestInit.body;
}
else {
const redirectUrl = this.getLocationHeader(response);
if (redirectUrl) {
if (fetchRequestInit.headers && !this.isRelativeURL(redirectUrl) && this.shouldDropAuthorizationHeader(url, redirectUrl)) {
delete fetchRequestInit.headers[RedirectHandler.AUTHORIZATION_HEADER];
}
url = redirectUrl;
}
}
if (tracerName) {
return trace.getTracer(tracerName).startActiveSpan(`redirectHandler - redirect ${redirectCount}`, (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.redirect.count", redirectCount);
span.setAttribute("http.response.status_code", response.status);
return this.executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions);
}
finally {
span.end();
}
});
}
return await this.executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions);
}
else {
return response;
}
}
/**
* Executes the request and returns a promise resolving the response.
* @param url - The url for the request
* @param requestInit - The Fetch RequestInit object.
* @param requestOptions - The request options.
* @returns A Promise that resolves to the response.
*/
execute(url, requestInit, requestOptions) {
const redirectCount = 0;
let currentOptions = this.options;
if (requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions[RedirectHandlerOptionKey]) {
currentOptions = requestOptions[RedirectHandlerOptionKey];
}
requestInit.redirect = RedirectHandler.MANUAL_REDIRECT;
const obsOptions = getObservabilityOptionsFromRequest(requestOptions);
if (obsOptions) {
return trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("redirectHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.redirect.enable", true);
return this.executeWithRedirect(url, requestInit, redirectCount, currentOptions, requestOptions, obsOptions.getTracerInstrumentationName());
}
finally {
span.end();
}
});
}
return this.executeWithRedirect(url, requestInit, redirectCount, currentOptions, requestOptions);
}
}
/**
* A member holding the array of redirect status codes
*/
RedirectHandler.REDIRECT_STATUS_CODES = new Set([
301, // Moved Permanently
302, // Found
303, // See Other
307, // Temporary Permanently
308, // Moved Permanently
]);
/**
* A member holding SeeOther status code
*/
RedirectHandler.STATUS_CODE_SEE_OTHER = 303;
/**
* A member holding the name of the location header
*/
RedirectHandler.LOCATION_HEADER = "Location";
/**
* A member representing the authorization header name
*/
RedirectHandler.AUTHORIZATION_HEADER = "Authorization";
/**
* A member holding the manual redirect value
*/
RedirectHandler.MANUAL_REDIRECT = "manual";
//# sourceMappingURL=redirectHandler.js.map