1 |
|
2 |
|
3 | import { HttpOperationResponse } from "../httpOperationResponse";
|
4 | import * as utils from "../util/utils";
|
5 | import { WebResourceLike } from "../webResource";
|
6 | import {
|
7 | BaseRequestPolicy,
|
8 | RequestPolicy,
|
9 | RequestPolicyFactory,
|
10 | RequestPolicyOptionsLike,
|
11 | } from "./requestPolicy";
|
12 |
|
13 | export function rpRegistrationPolicy(retryTimeout = 30): RequestPolicyFactory {
|
14 | return {
|
15 | create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
|
16 | return new RPRegistrationPolicy(nextPolicy, options, retryTimeout);
|
17 | },
|
18 | };
|
19 | }
|
20 |
|
21 | export class RPRegistrationPolicy extends BaseRequestPolicy {
|
22 | constructor(
|
23 | nextPolicy: RequestPolicy,
|
24 | options: RequestPolicyOptionsLike,
|
25 | readonly _retryTimeout = 30
|
26 | ) {
|
27 | super(nextPolicy, options);
|
28 | }
|
29 |
|
30 | public sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
|
31 | return this._nextPolicy
|
32 | .sendRequest(request.clone())
|
33 | .then((response) => registerIfNeeded(this, request, response));
|
34 | }
|
35 | }
|
36 |
|
37 | function registerIfNeeded(
|
38 | policy: RPRegistrationPolicy,
|
39 | request: WebResourceLike,
|
40 | response: HttpOperationResponse
|
41 | ): Promise<HttpOperationResponse> {
|
42 | if (response.status === 409) {
|
43 | const rpName = checkRPNotRegisteredError(response.bodyAsText as string);
|
44 | if (rpName) {
|
45 | const urlPrefix = extractSubscriptionUrl(request.url);
|
46 | return (
|
47 | registerRP(policy, urlPrefix, rpName, request)
|
48 |
|
49 |
|
50 |
|
51 | .catch(() => false)
|
52 | .then((registrationStatus) => {
|
53 | if (registrationStatus) {
|
54 |
|
55 |
|
56 | request.headers.set("x-ms-client-request-id", utils.generateUuid());
|
57 | return policy._nextPolicy.sendRequest(request.clone());
|
58 | }
|
59 | return response;
|
60 | })
|
61 | );
|
62 | }
|
63 | }
|
64 |
|
65 | return Promise.resolve(response);
|
66 | }
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 | function getRequestEssentials(
|
75 | originalRequest: WebResourceLike,
|
76 | reuseUrlToo = false
|
77 | ): WebResourceLike {
|
78 | const reqOptions: WebResourceLike = originalRequest.clone();
|
79 | if (reuseUrlToo) {
|
80 | reqOptions.url = originalRequest.url;
|
81 | }
|
82 |
|
83 |
|
84 |
|
85 | reqOptions.headers.set("x-ms-client-request-id", utils.generateUuid());
|
86 |
|
87 |
|
88 | reqOptions.headers.set("Content-Type", "application/json; charset=utf-8");
|
89 |
|
90 | return reqOptions;
|
91 | }
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 | function checkRPNotRegisteredError(body: string): string {
|
100 | let result, responseBody;
|
101 | if (body) {
|
102 | try {
|
103 | responseBody = JSON.parse(body);
|
104 | } catch (err) {
|
105 |
|
106 | }
|
107 | if (
|
108 | responseBody &&
|
109 | responseBody.error &&
|
110 | responseBody.error.message &&
|
111 | responseBody.error.code &&
|
112 | responseBody.error.code === "MissingSubscriptionRegistration"
|
113 | ) {
|
114 | const matchRes = responseBody.error.message.match(/.*'(.*)'/i);
|
115 | if (matchRes) {
|
116 | result = matchRes.pop();
|
117 | }
|
118 | }
|
119 | }
|
120 | return result;
|
121 | }
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 | function extractSubscriptionUrl(url: string): string {
|
130 | let result;
|
131 | const matchRes = url.match(/.*\/subscriptions\/[a-f0-9-]+\//gi);
|
132 | if (matchRes && matchRes[0]) {
|
133 | result = matchRes[0];
|
134 | } else {
|
135 | throw new Error(`Unable to extract subscriptionId from the given url - ${url}.`);
|
136 | }
|
137 | return result;
|
138 | }
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 | function registerRP(
|
150 | policy: RPRegistrationPolicy,
|
151 | urlPrefix: string,
|
152 | provider: string,
|
153 | originalRequest: WebResourceLike
|
154 | ): Promise<boolean> {
|
155 | const postUrl = `${urlPrefix}providers/${provider}/register?api-version=2016-02-01`;
|
156 | const getUrl = `${urlPrefix}providers/${provider}?api-version=2016-02-01`;
|
157 | const reqOptions = getRequestEssentials(originalRequest);
|
158 | reqOptions.method = "POST";
|
159 | reqOptions.url = postUrl;
|
160 |
|
161 | return policy._nextPolicy.sendRequest(reqOptions).then((response) => {
|
162 | if (response.status !== 200) {
|
163 | throw new Error(`Autoregistration of ${provider} failed. Please try registering manually.`);
|
164 | }
|
165 | return getRegistrationStatus(policy, getUrl, originalRequest);
|
166 | });
|
167 | }
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 | function getRegistrationStatus(
|
179 | policy: RPRegistrationPolicy,
|
180 | url: string,
|
181 | originalRequest: WebResourceLike
|
182 | ): Promise<boolean> {
|
183 | const reqOptions: any = getRequestEssentials(originalRequest);
|
184 | reqOptions.url = url;
|
185 | reqOptions.method = "GET";
|
186 |
|
187 | return policy._nextPolicy.sendRequest(reqOptions).then((res) => {
|
188 | const obj = res.parsedBody as any;
|
189 | if (res.parsedBody && obj.registrationState && obj.registrationState === "Registered") {
|
190 | return true;
|
191 | } else {
|
192 | return utils
|
193 | .delay(policy._retryTimeout * 1000)
|
194 | .then(() => getRegistrationStatus(policy, url, originalRequest));
|
195 | }
|
196 | });
|
197 | }
|