UNPKG

10.6 kBJavaScriptView Raw
1"use strict";
2/**
3 * -------------------------------------------------------------------------------------------
4 * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
5 * See License in the project root for license information.
6 * -------------------------------------------------------------------------------------------
7 */
8Object.defineProperty(exports, "__esModule", { value: true });
9exports.RedirectHandler = void 0;
10var tslib_1 = require("tslib");
11var RequestMethod_1 = require("../RequestMethod");
12var MiddlewareControl_1 = require("./MiddlewareControl");
13var MiddlewareUtil_1 = require("./MiddlewareUtil");
14var RedirectHandlerOptions_1 = require("./options/RedirectHandlerOptions");
15var TelemetryHandlerOptions_1 = require("./options/TelemetryHandlerOptions");
16/**
17 * @class
18 * Class
19 * @implements Middleware
20 * Class representing RedirectHandler
21 */
22var RedirectHandler = /** @class */ (function () {
23 /**
24 * @public
25 * @constructor
26 * To create an instance of RedirectHandler
27 * @param {RedirectHandlerOptions} [options = new RedirectHandlerOptions()] - The redirect handler options instance
28 * @returns An instance of RedirectHandler
29 */
30 function RedirectHandler(options) {
31 if (options === void 0) { options = new RedirectHandlerOptions_1.RedirectHandlerOptions(); }
32 this.options = options;
33 }
34 /**
35 * @private
36 * To check whether the response has the redirect status code or not
37 * @param {Response} response - The response object
38 * @returns A boolean representing whether the response contains the redirect status code or not
39 */
40 RedirectHandler.prototype.isRedirect = function (response) {
41 return RedirectHandler.REDIRECT_STATUS_CODES.indexOf(response.status) !== -1;
42 };
43 /**
44 * @private
45 * To check whether the response has location header or not
46 * @param {Response} response - The response object
47 * @returns A boolean representing the whether the response has location header or not
48 */
49 RedirectHandler.prototype.hasLocationHeader = function (response) {
50 return response.headers.has(RedirectHandler.LOCATION_HEADER);
51 };
52 /**
53 * @private
54 * To get the redirect url from location header in response object
55 * @param {Response} response - The response object
56 * @returns A redirect url from location header
57 */
58 RedirectHandler.prototype.getLocationHeader = function (response) {
59 return response.headers.get(RedirectHandler.LOCATION_HEADER);
60 };
61 /**
62 * @private
63 * To check whether the given url is a relative url or not
64 * @param {string} url - The url string value
65 * @returns A boolean representing whether the given url is a relative url or not
66 */
67 RedirectHandler.prototype.isRelativeURL = function (url) {
68 return url.indexOf("://") === -1;
69 };
70 /**
71 * @private
72 * To check whether the authorization header in the request should be dropped for consequent redirected requests
73 * @param {string} requestUrl - The request url value
74 * @param {string} redirectUrl - The redirect url value
75 * @returns A boolean representing whether the authorization header in the request should be dropped for consequent redirected requests
76 */
77 RedirectHandler.prototype.shouldDropAuthorizationHeader = function (requestUrl, redirectUrl) {
78 var schemeHostRegex = /^[A-Za-z].+?:\/\/.+?(?=\/|$)/;
79 var requestMatches = schemeHostRegex.exec(requestUrl);
80 var requestAuthority;
81 var redirectAuthority;
82 if (requestMatches !== null) {
83 requestAuthority = requestMatches[0];
84 }
85 var redirectMatches = schemeHostRegex.exec(redirectUrl);
86 if (redirectMatches !== null) {
87 redirectAuthority = redirectMatches[0];
88 }
89 return typeof requestAuthority !== "undefined" && typeof redirectAuthority !== "undefined" && requestAuthority !== redirectAuthority;
90 };
91 /**
92 * @private
93 * @async
94 * To update a request url with the redirect url
95 * @param {string} redirectUrl - The redirect url value
96 * @param {Context} context - The context object value
97 * @returns Nothing
98 */
99 RedirectHandler.prototype.updateRequestUrl = function (redirectUrl, context) {
100 return tslib_1.__awaiter(this, void 0, void 0, function () {
101 var _a, _b;
102 return tslib_1.__generator(this, function (_c) {
103 switch (_c.label) {
104 case 0:
105 _a = context;
106 if (!(typeof context.request === "string")) return [3 /*break*/, 1];
107 _b = redirectUrl;
108 return [3 /*break*/, 3];
109 case 1: return [4 /*yield*/, (0, MiddlewareUtil_1.cloneRequestWithNewUrl)(redirectUrl, context.request)];
110 case 2:
111 _b = _c.sent();
112 _c.label = 3;
113 case 3:
114 _a.request = _b;
115 return [2 /*return*/];
116 }
117 });
118 });
119 };
120 /**
121 * @private
122 * To get the options for execution of the middleware
123 * @param {Context} context - The context object
124 * @returns A options for middleware execution
125 */
126 RedirectHandler.prototype.getOptions = function (context) {
127 var options;
128 if (context.middlewareControl instanceof MiddlewareControl_1.MiddlewareControl) {
129 options = context.middlewareControl.getMiddlewareOptions(RedirectHandlerOptions_1.RedirectHandlerOptions);
130 }
131 if (typeof options === "undefined") {
132 options = Object.assign(new RedirectHandlerOptions_1.RedirectHandlerOptions(), this.options);
133 }
134 return options;
135 };
136 /**
137 * @private
138 * @async
139 * To execute the next middleware and to handle in case of redirect response returned by the server
140 * @param {Context} context - The context object
141 * @param {number} redirectCount - The redirect count value
142 * @param {RedirectHandlerOptions} options - The redirect handler options instance
143 * @returns A promise that resolves to nothing
144 */
145 RedirectHandler.prototype.executeWithRedirect = function (context, redirectCount, options) {
146 return tslib_1.__awaiter(this, void 0, void 0, function () {
147 var response, redirectUrl;
148 return tslib_1.__generator(this, function (_a) {
149 switch (_a.label) {
150 case 0: return [4 /*yield*/, this.nextMiddleware.execute(context)];
151 case 1:
152 _a.sent();
153 response = context.response;
154 if (!(redirectCount < options.maxRedirects && this.isRedirect(response) && this.hasLocationHeader(response) && options.shouldRedirect(response))) return [3 /*break*/, 6];
155 ++redirectCount;
156 if (!(response.status === RedirectHandler.STATUS_CODE_SEE_OTHER)) return [3 /*break*/, 2];
157 context.options.method = RequestMethod_1.RequestMethod.GET;
158 delete context.options.body;
159 return [3 /*break*/, 4];
160 case 2:
161 redirectUrl = this.getLocationHeader(response);
162 if (!this.isRelativeURL(redirectUrl) && this.shouldDropAuthorizationHeader(response.url, redirectUrl)) {
163 delete context.options.headers[RedirectHandler.AUTHORIZATION_HEADER];
164 }
165 return [4 /*yield*/, this.updateRequestUrl(redirectUrl, context)];
166 case 3:
167 _a.sent();
168 _a.label = 4;
169 case 4: return [4 /*yield*/, this.executeWithRedirect(context, redirectCount, options)];
170 case 5:
171 _a.sent();
172 return [3 /*break*/, 7];
173 case 6: return [2 /*return*/];
174 case 7: return [2 /*return*/];
175 }
176 });
177 });
178 };
179 /**
180 * @public
181 * @async
182 * To execute the current middleware
183 * @param {Context} context - The context object of the request
184 * @returns A Promise that resolves to nothing
185 */
186 RedirectHandler.prototype.execute = function (context) {
187 return tslib_1.__awaiter(this, void 0, void 0, function () {
188 var redirectCount, options;
189 return tslib_1.__generator(this, function (_a) {
190 switch (_a.label) {
191 case 0:
192 redirectCount = 0;
193 options = this.getOptions(context);
194 context.options.redirect = RedirectHandler.MANUAL_REDIRECT;
195 TelemetryHandlerOptions_1.TelemetryHandlerOptions.updateFeatureUsageFlag(context, TelemetryHandlerOptions_1.FeatureUsageFlag.REDIRECT_HANDLER_ENABLED);
196 return [4 /*yield*/, this.executeWithRedirect(context, redirectCount, options)];
197 case 1: return [2 /*return*/, _a.sent()];
198 }
199 });
200 });
201 };
202 /**
203 * @public
204 * To set the next middleware in the chain
205 * @param {Middleware} next - The middleware instance
206 * @returns Nothing
207 */
208 RedirectHandler.prototype.setNext = function (next) {
209 this.nextMiddleware = next;
210 };
211 /**
212 * @private
213 * @static
214 * A member holding the array of redirect status codes
215 */
216 RedirectHandler.REDIRECT_STATUS_CODES = [
217 301,
218 302,
219 303,
220 307,
221 308, // Moved Permanently
222 ];
223 /**
224 * @private
225 * @static
226 * A member holding SeeOther status code
227 */
228 RedirectHandler.STATUS_CODE_SEE_OTHER = 303;
229 /**
230 * @private
231 * @static
232 * A member holding the name of the location header
233 */
234 RedirectHandler.LOCATION_HEADER = "Location";
235 /**
236 * @private
237 * @static
238 * A member representing the authorization header name
239 */
240 RedirectHandler.AUTHORIZATION_HEADER = "Authorization";
241 /**
242 * @private
243 * @static
244 * A member holding the manual redirect value
245 */
246 RedirectHandler.MANUAL_REDIRECT = "manual";
247 return RedirectHandler;
248}());
249exports.RedirectHandler = RedirectHandler;
250//# sourceMappingURL=RedirectHandler.js.map
\No newline at end of file