1 | ;
|
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 | */
|
8 | Object.defineProperty(exports, "__esModule", { value: true });
|
9 | exports.RedirectHandler = void 0;
|
10 | var tslib_1 = require("tslib");
|
11 | var RequestMethod_1 = require("../RequestMethod");
|
12 | var MiddlewareControl_1 = require("./MiddlewareControl");
|
13 | var MiddlewareUtil_1 = require("./MiddlewareUtil");
|
14 | var RedirectHandlerOptions_1 = require("./options/RedirectHandlerOptions");
|
15 | var TelemetryHandlerOptions_1 = require("./options/TelemetryHandlerOptions");
|
16 | /**
|
17 | * @class
|
18 | * Class
|
19 | * @implements Middleware
|
20 | * Class representing RedirectHandler
|
21 | */
|
22 | var 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 | }());
|
249 | exports.RedirectHandler = RedirectHandler;
|
250 | //# sourceMappingURL=RedirectHandler.js.map |
\ | No newline at end of file |