diff options
author | Brennan Conroy <brecon@microsoft.com> | 2022-08-16 20:16:50 +0300 |
---|---|---|
committer | Brennan Conroy <brecon@microsoft.com> | 2022-08-16 20:16:50 +0300 |
commit | 6ca05392386844740cb268bd197b6dc257a502ef (patch) | |
tree | e1c12d929ea93feb086aba027c3d917d60a975d2 | |
parent | 9fcabf79d5a4f6a8cd5e70cc89f001a5a5dafeeb (diff) |
4 files changed, 16 insertions, 12 deletions
diff --git a/src/SignalR/clients/ts/signalr/src/AccessTokenHttpClient.ts b/src/SignalR/clients/ts/signalr/src/AccessTokenHttpClient.ts index 2c7c4df526..ddeb2e6fa6 100644 --- a/src/SignalR/clients/ts/signalr/src/AccessTokenHttpClient.ts +++ b/src/SignalR/clients/ts/signalr/src/AccessTokenHttpClient.ts @@ -7,7 +7,7 @@ import { HttpClient, HttpRequest, HttpResponse } from "./HttpClient"; /** @private */ export class AccessTokenHttpClient extends HttpClient { private _innerClient: HttpClient; - private _accessToken: string | undefined; + _accessToken: string | undefined; private _accessTokenFactory: (() => string | Promise<string>) | undefined; constructor(innerClient: HttpClient, currentAccessToken: string | undefined, accessTokenFactory: (() => string | Promise<string>) | undefined) { diff --git a/src/SignalR/clients/ts/signalr/src/HttpConnection.ts b/src/SignalR/clients/ts/signalr/src/HttpConnection.ts index d338a602d2..b9956e6eaa 100644 --- a/src/SignalR/clients/ts/signalr/src/HttpConnection.ts +++ b/src/SignalR/clients/ts/signalr/src/HttpConnection.ts @@ -267,7 +267,9 @@ export class HttpConnection implements IConnection { // the returned access token const accessToken = negotiateResponse.accessToken; this._accessTokenFactory = () => accessToken; - this._httpClient.replaceAccessTokenFactory(this._accessTokenFactory); + // set the factory to undefined so the httpClient won't retry with the same token, since we know it won't change until a connection restart + this._httpClient._accessToken = accessToken; + this._httpClient.replaceAccessTokenFactory(undefined); } redirects++; @@ -418,7 +420,7 @@ export class HttpConnection implements IConnection { if (!this._options.EventSource) { throw new Error("'EventSource' is not supported in your environment."); } - return new ServerSentEventsTransport(this._httpClient, this._accessTokenFactory, this._logger, this._options); + return new ServerSentEventsTransport(this._httpClient, this._httpClient._accessToken, this._logger, this._options); case HttpTransportType.LongPolling: return new LongPollingTransport(this._httpClient, this._logger, this._options); default: diff --git a/src/SignalR/clients/ts/signalr/src/ServerSentEventsTransport.ts b/src/SignalR/clients/ts/signalr/src/ServerSentEventsTransport.ts index 530ed55371..e147e16397 100644 --- a/src/SignalR/clients/ts/signalr/src/ServerSentEventsTransport.ts +++ b/src/SignalR/clients/ts/signalr/src/ServerSentEventsTransport.ts @@ -11,7 +11,7 @@ import { IHttpConnectionOptions } from "./IHttpConnectionOptions"; /** @private */ export class ServerSentEventsTransport implements ITransport { private readonly _httpClient: HttpClient; - private readonly _accessTokenFactory: (() => string | Promise<string>) | undefined; + private readonly _accessToken: string | undefined; private readonly _logger: ILogger; private readonly _options: IHttpConnectionOptions; private _eventSource?: EventSource; @@ -20,10 +20,10 @@ export class ServerSentEventsTransport implements ITransport { public onreceive: ((data: string | ArrayBuffer) => void) | null; public onclose: ((error?: Error) => void) | null; - constructor(httpClient: HttpClient, accessTokenFactory: (() => string | Promise<string>) | undefined, logger: ILogger, + constructor(httpClient: HttpClient, accessToken: string | undefined, logger: ILogger, options: IHttpConnectionOptions) { this._httpClient = httpClient; - this._accessTokenFactory = accessTokenFactory; + this._accessToken = accessToken; this._logger = logger; this._options = options; @@ -41,11 +41,8 @@ export class ServerSentEventsTransport implements ITransport { // set url before accessTokenFactory because this._url is only for send and we set the auth header instead of the query string for send this._url = url; - if (this._accessTokenFactory) { - const token = await this._accessTokenFactory(); - if (token) { - url += (url.indexOf("?") < 0 ? "?" : "&") + `access_token=${encodeURIComponent(token)}`; - } + if (this._accessToken) { + url += (url.indexOf("?") < 0 ? "?" : "&") + `access_token=${encodeURIComponent(this._accessToken)}`; } return new Promise<void>((resolve, reject) => { diff --git a/src/SignalR/clients/ts/signalr/tests/ServerSentEventsTransport.test.ts b/src/SignalR/clients/ts/signalr/tests/ServerSentEventsTransport.test.ts index 1e7a4d3c2c..a7b300efbe 100644 --- a/src/SignalR/clients/ts/signalr/tests/ServerSentEventsTransport.test.ts +++ b/src/SignalR/clients/ts/signalr/tests/ServerSentEventsTransport.test.ts @@ -297,7 +297,12 @@ describe("ServerSentEventsTransport", () => { }); async function createAndStartSSE(logger: ILogger, url?: string, accessTokenFactory?: (() => string | Promise<string>), options?: IHttpConnectionOptions): Promise<ServerSentEventsTransport> { - const sse = new ServerSentEventsTransport(options?.httpClient || new TestHttpClient(), accessTokenFactory, logger, + let token; + // SSE assumes (correctly) that negotiate will already create the token we want to use on connection startup, so simulate that here when creating the SSE transport + if (accessTokenFactory) { + token = await accessTokenFactory(); + } + const sse = new ServerSentEventsTransport(options?.httpClient || new TestHttpClient(), token, logger, { logMessageContent: true, EventSource: TestEventSource, withCredentials: true, timeout: 10205, ...options }); const connectPromise = sse.connect(url || "http://example.com", TransferFormat.Text); |