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