This commit is contained in:
parent
4203540cb0
commit
2625b389b8
|
|
@ -58,12 +58,12 @@ namespace FunctionalTests
|
|||
{
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
var signalRTokenHeader = context.Request.Query["signalRTokenHeader"];
|
||||
var signalRTokenHeader = context.Request.Query["access_token"];
|
||||
|
||||
if (!string.IsNullOrEmpty(signalRTokenHeader) &&
|
||||
(context.HttpContext.WebSockets.IsWebSocketRequest || context.Request.Headers["Accept"] == "text/event-stream"))
|
||||
{
|
||||
context.Token = context.Request.Query["signalRTokenHeader"];
|
||||
context.Token = context.Request.Query["access_token"];
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ describe('hubConnection', function () {
|
|||
hubConnection = new HubConnection('/authorizedhub', {
|
||||
transport: transportType,
|
||||
logger: LogLevel.Trace,
|
||||
accessToken: () => jwtToken
|
||||
accessTokenFactory: () => jwtToken
|
||||
});
|
||||
hubConnection.onclose(function (error) {
|
||||
expect(error).toBe(undefined);
|
||||
|
|
|
|||
|
|
@ -9,25 +9,29 @@ import { ITransport, TransportType, TransferMode } from "../src/Transports"
|
|||
import { eachTransport, eachEndpointUrl } from "./Common";
|
||||
import { HttpResponse } from "../src/index";
|
||||
|
||||
const commonOptions: IHttpConnectionOptions = {
|
||||
logger: null
|
||||
};
|
||||
|
||||
describe("HttpConnection", () => {
|
||||
it("cannot be created with relative url if document object is not present", () => {
|
||||
expect(() => new HttpConnection("/test"))
|
||||
expect(() => new HttpConnection("/test", commonOptions))
|
||||
.toThrow(new Error("Cannot resolve '/test'."));
|
||||
});
|
||||
|
||||
it("cannot be created with relative url if window object is not present", () => {
|
||||
(<any>global).window = {};
|
||||
expect(() => new HttpConnection("/test"))
|
||||
expect(() => new HttpConnection("/test", commonOptions))
|
||||
.toThrow(new Error("Cannot resolve '/test'."));
|
||||
delete (<any>global).window;
|
||||
});
|
||||
|
||||
it("starting connection fails if getting id fails", async (done) => {
|
||||
let options: IHttpConnectionOptions = {
|
||||
...commonOptions,
|
||||
httpClient: new TestHttpClient()
|
||||
.on("POST", r => Promise.reject("error"))
|
||||
.on("GET", r => ""),
|
||||
logger: null
|
||||
} as IHttpConnectionOptions;
|
||||
|
||||
let connection = new HttpConnection("http://tempuri.org", options);
|
||||
|
|
@ -45,6 +49,7 @@ describe("HttpConnection", () => {
|
|||
|
||||
it("cannot start a running connection", async (done) => {
|
||||
let options: IHttpConnectionOptions = {
|
||||
...commonOptions,
|
||||
httpClient: new TestHttpClient()
|
||||
.on("POST", r => {
|
||||
connection.start()
|
||||
|
|
@ -58,7 +63,6 @@ describe("HttpConnection", () => {
|
|||
});
|
||||
return Promise.reject("error");
|
||||
}),
|
||||
logger: null
|
||||
} as IHttpConnectionOptions;
|
||||
|
||||
let connection = new HttpConnection("http://tempuri.org", options);
|
||||
|
|
@ -75,13 +79,13 @@ describe("HttpConnection", () => {
|
|||
it("can start a stopped connection", async (done) => {
|
||||
let negotiateCalls = 0;
|
||||
let options: IHttpConnectionOptions = {
|
||||
...commonOptions,
|
||||
httpClient: new TestHttpClient()
|
||||
.on("POST", r => {
|
||||
negotiateCalls += 1;
|
||||
return Promise.reject("reached negotiate");
|
||||
})
|
||||
.on("GET", r => ""),
|
||||
logger: null
|
||||
} as IHttpConnectionOptions;
|
||||
|
||||
let connection = new HttpConnection("http://tempuri.org", options);
|
||||
|
|
@ -103,6 +107,7 @@ describe("HttpConnection", () => {
|
|||
|
||||
it("can stop a starting connection", async (done) => {
|
||||
let options: IHttpConnectionOptions = {
|
||||
...commonOptions,
|
||||
httpClient: new TestHttpClient()
|
||||
.on("POST", r => {
|
||||
connection.stop();
|
||||
|
|
@ -112,7 +117,6 @@ describe("HttpConnection", () => {
|
|||
connection.stop();
|
||||
return "";
|
||||
}),
|
||||
logger: null
|
||||
} as IHttpConnectionOptions;
|
||||
|
||||
let connection = new HttpConnection("http://tempuri.org", options);
|
||||
|
|
@ -128,7 +132,7 @@ describe("HttpConnection", () => {
|
|||
});
|
||||
|
||||
it("can stop a non-started connection", async (done) => {
|
||||
let connection = new HttpConnection("http://tempuri.org");
|
||||
let connection = new HttpConnection("http://tempuri.org", commonOptions);
|
||||
await connection.stop();
|
||||
done();
|
||||
});
|
||||
|
|
@ -151,11 +155,11 @@ describe("HttpConnection", () => {
|
|||
}
|
||||
|
||||
let options: IHttpConnectionOptions = {
|
||||
...commonOptions,
|
||||
httpClient: new TestHttpClient()
|
||||
.on("POST", r => "{ \"connectionId\": \"42\" }")
|
||||
.on("GET", r => ""),
|
||||
transport: fakeTransport,
|
||||
logger: null,
|
||||
} as IHttpConnectionOptions;
|
||||
|
||||
|
||||
|
|
@ -178,6 +182,7 @@ describe("HttpConnection", () => {
|
|||
let negotiateUrl: string;
|
||||
let connection: HttpConnection;
|
||||
let options: IHttpConnectionOptions = {
|
||||
...commonOptions,
|
||||
httpClient: new TestHttpClient()
|
||||
.on("POST", r => {
|
||||
negotiateUrl = r.url;
|
||||
|
|
@ -188,7 +193,6 @@ describe("HttpConnection", () => {
|
|||
connection.stop();
|
||||
return "";
|
||||
}),
|
||||
logger: null
|
||||
} as IHttpConnectionOptions;
|
||||
|
||||
connection = new HttpConnection(givenUrl, options);
|
||||
|
|
@ -212,11 +216,11 @@ describe("HttpConnection", () => {
|
|||
}
|
||||
it(`cannot be started if requested ${TransportType[requestedTransport]} transport not available on server`, async done => {
|
||||
let options: IHttpConnectionOptions = {
|
||||
...commonOptions,
|
||||
httpClient: new TestHttpClient()
|
||||
.on("POST", r => "{ \"connectionId\": \"42\", \"availableTransports\": [] }")
|
||||
.on("GET", r => ""),
|
||||
transport: requestedTransport,
|
||||
logger: null
|
||||
} as IHttpConnectionOptions;
|
||||
|
||||
let connection = new HttpConnection("http://tempuri.org", options);
|
||||
|
|
@ -234,10 +238,10 @@ describe("HttpConnection", () => {
|
|||
|
||||
it("cannot be started if no transport available on server and no transport requested", async done => {
|
||||
let options: IHttpConnectionOptions = {
|
||||
...commonOptions,
|
||||
httpClient: new TestHttpClient()
|
||||
.on("POST", r => "{ \"connectionId\": \"42\", \"availableTransports\": [] }")
|
||||
.on("GET", r => ""),
|
||||
logger: null
|
||||
} as IHttpConnectionOptions;
|
||||
|
||||
let connection = new HttpConnection("http://tempuri.org", options);
|
||||
|
|
@ -254,9 +258,9 @@ describe("HttpConnection", () => {
|
|||
|
||||
it('does not send negotiate request if WebSockets transport requested explicitly', async done => {
|
||||
let options: IHttpConnectionOptions = {
|
||||
...commonOptions,
|
||||
httpClient: new TestHttpClient(),
|
||||
transport: TransportType.WebSockets,
|
||||
logger: null
|
||||
} as IHttpConnectionOptions;
|
||||
|
||||
let connection = new HttpConnection("http://tempuri.org", options);
|
||||
|
|
@ -291,11 +295,11 @@ describe("HttpConnection", () => {
|
|||
} as ITransport;
|
||||
|
||||
let options: IHttpConnectionOptions = {
|
||||
...commonOptions,
|
||||
httpClient: new TestHttpClient()
|
||||
.on("POST", r => "{ \"connectionId\": \"42\", \"availableTransports\": [] }")
|
||||
.on("GET", r => ""),
|
||||
transport: fakeTransport,
|
||||
logger: null
|
||||
} as IHttpConnectionOptions;
|
||||
|
||||
let connection = new HttpConnection("https://tempuri.org", options);
|
||||
|
|
|
|||
|
|
@ -13,12 +13,16 @@ import { MessageType } from "../src/IHubProtocol"
|
|||
import { asyncit as it, captureException, delay, PromiseSource } from './Utils';
|
||||
import { IHubConnectionOptions } from "../src/HubConnection";
|
||||
|
||||
const commonOptions: IHubConnectionOptions = {
|
||||
logger: null,
|
||||
}
|
||||
|
||||
describe("HubConnection", () => {
|
||||
|
||||
describe("start", () => {
|
||||
it("sends negotiation message", async () => {
|
||||
let connection = new TestConnection();
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
await hubConnection.start();
|
||||
expect(connection.sentData.length).toBe(1)
|
||||
expect(JSON.parse(connection.sentData[0])).toEqual({
|
||||
|
|
@ -32,7 +36,7 @@ describe("HubConnection", () => {
|
|||
it("sends a non blocking invocation", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let invokePromise = hubConnection.send("testMethod", "arg", 42)
|
||||
.catch((_) => { }); // Suppress exception and unhandled promise rejection warning.
|
||||
|
||||
|
|
@ -56,7 +60,7 @@ describe("HubConnection", () => {
|
|||
it("sends an invocation", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let invokePromise = hubConnection.invoke("testMethod", "arg", 42)
|
||||
.catch((_) => { }); // Suppress exception and unhandled promise rejection warning.
|
||||
|
||||
|
|
@ -79,7 +83,7 @@ describe("HubConnection", () => {
|
|||
it("rejects the promise when an error is received", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let invokePromise = hubConnection.invoke("testMethod", "arg", 42);
|
||||
|
||||
connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId, error: "foo" });
|
||||
|
|
@ -91,7 +95,7 @@ describe("HubConnection", () => {
|
|||
it("resolves the promise when a result is received", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let invokePromise = hubConnection.invoke("testMethod", "arg", 42);
|
||||
|
||||
connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId, result: "foo" });
|
||||
|
|
@ -102,7 +106,7 @@ describe("HubConnection", () => {
|
|||
it("completes pending invocations when stopped", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let invokePromise = hubConnection.invoke("testMethod");
|
||||
hubConnection.stop();
|
||||
|
||||
|
|
@ -113,7 +117,7 @@ describe("HubConnection", () => {
|
|||
it("completes pending invocations when connection is lost", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let invokePromise = hubConnection.invoke("testMethod");
|
||||
// Typically this would be called by the transport
|
||||
connection.onclose(new Error("Connection lost"));
|
||||
|
|
@ -149,7 +153,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("callback invoked when servers invokes a method on the client", async () => {
|
||||
let connection = new TestConnection();
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let value = "";
|
||||
hubConnection.on("message", v => value = v);
|
||||
|
||||
|
|
@ -166,7 +170,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("can have multiple callbacks", async () => {
|
||||
let connection = new TestConnection();
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let numInvocations1 = 0;
|
||||
let numInvocations2 = 0;
|
||||
hubConnection.on("message", () => numInvocations1++);
|
||||
|
|
@ -186,7 +190,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("can unsubscribe from on", async () => {
|
||||
let connection = new TestConnection();
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
|
||||
var numInvocations = 0;
|
||||
var callback = () => numInvocations++;
|
||||
|
|
@ -215,7 +219,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("unsubscribing from non-existing callbacks no-ops", async () => {
|
||||
let connection = new TestConnection();
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
|
||||
hubConnection.off("_", () => { });
|
||||
hubConnection.on("message", t => { });
|
||||
|
|
@ -267,7 +271,7 @@ describe("HubConnection", () => {
|
|||
it("sends an invocation", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let invokePromise = hubConnection.stream("testStream", "arg", 42);
|
||||
|
||||
// Verify the message is sent
|
||||
|
|
@ -289,7 +293,7 @@ describe("HubConnection", () => {
|
|||
it("completes with an error when an error is yielded", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let observer = new TestObserver();
|
||||
hubConnection.stream<any>("testMethod", "arg", 42)
|
||||
.subscribe(observer);
|
||||
|
|
@ -303,7 +307,7 @@ describe("HubConnection", () => {
|
|||
it("completes the observer when a completion is received", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let observer = new TestObserver();
|
||||
hubConnection.stream<any>("testMethod", "arg", 42)
|
||||
.subscribe(observer);
|
||||
|
|
@ -316,7 +320,7 @@ describe("HubConnection", () => {
|
|||
it("completes pending streams when stopped", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let observer = new TestObserver();
|
||||
hubConnection.stream<any>("testMethod")
|
||||
.subscribe(observer);
|
||||
|
|
@ -329,7 +333,7 @@ describe("HubConnection", () => {
|
|||
it("completes pending streams when connection is lost", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let observer = new TestObserver();
|
||||
hubConnection.stream<any>("testMethod")
|
||||
.subscribe(observer);
|
||||
|
|
@ -344,7 +348,7 @@ describe("HubConnection", () => {
|
|||
it("yields items as they arrive", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let observer = new TestObserver();
|
||||
hubConnection.stream<any>("testMethod")
|
||||
.subscribe(observer);
|
||||
|
|
@ -365,7 +369,7 @@ describe("HubConnection", () => {
|
|||
it("does not require error function registered", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let observer = hubConnection.stream("testMethod").subscribe({
|
||||
next: val => { }
|
||||
});
|
||||
|
|
@ -378,7 +382,7 @@ describe("HubConnection", () => {
|
|||
it("does not require complete function registered", async () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let observer = hubConnection.stream("testMethod").subscribe({
|
||||
next: val => { }
|
||||
});
|
||||
|
|
@ -391,7 +395,7 @@ describe("HubConnection", () => {
|
|||
it("can be canceled", () => {
|
||||
let connection = new TestConnection();
|
||||
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let observer = new TestObserver();
|
||||
let subscription = hubConnection.stream("testMethod")
|
||||
.subscribe(observer);
|
||||
|
|
@ -417,7 +421,7 @@ describe("HubConnection", () => {
|
|||
describe("onClose", () => {
|
||||
it("can have multiple callbacks", async () => {
|
||||
let connection = new TestConnection();
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let invocations = 0;
|
||||
hubConnection.onclose(e => invocations++);
|
||||
hubConnection.onclose(e => invocations++);
|
||||
|
|
@ -428,7 +432,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("callbacks receive error", async () => {
|
||||
let connection = new TestConnection();
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let error: Error;
|
||||
hubConnection.onclose(e => error = e);
|
||||
|
||||
|
|
@ -439,7 +443,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("ignores null callbacks", async () => {
|
||||
let connection = new TestConnection();
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
hubConnection.onclose(null);
|
||||
hubConnection.onclose(undefined);
|
||||
// Typically this would be called by the transport
|
||||
|
|
@ -453,7 +457,7 @@ describe("HubConnection", () => {
|
|||
// Receive the ping mid-invocation so we can see that the rest of the flow works fine
|
||||
|
||||
let connection = new TestConnection();
|
||||
let hubConnection = new HubConnection(connection, { logger: null });
|
||||
let hubConnection = new HubConnection(connection, commonOptions);
|
||||
let invokePromise = hubConnection.invoke("testMethod", "arg", 42);
|
||||
|
||||
connection.receive({ type: MessageType.Ping });
|
||||
|
|
@ -464,7 +468,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("does not terminate if messages are received", async () => {
|
||||
let connection = new TestConnection();
|
||||
let hubConnection = new HubConnection(connection, { timeoutInMilliseconds: 100, logger: null });
|
||||
let hubConnection = new HubConnection(connection, { ...commonOptions, timeoutInMilliseconds: 100 });
|
||||
|
||||
let p = new PromiseSource<Error>();
|
||||
hubConnection.onclose(error => p.resolve(error));
|
||||
|
|
@ -489,7 +493,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("terminates if no messages received within timeout interval", async () => {
|
||||
let connection = new TestConnection();
|
||||
let hubConnection = new HubConnection(connection, { timeoutInMilliseconds: 100, logger: null });
|
||||
let hubConnection = new HubConnection(connection, { ...commonOptions, timeoutInMilliseconds: 100 });
|
||||
|
||||
let p = new PromiseSource<Error>();
|
||||
hubConnection.onclose(error => p.resolve(error));
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export interface IHttpConnectionOptions {
|
|||
httpClient?: HttpClient;
|
||||
transport?: TransportType | ITransport;
|
||||
logger?: ILogger | LogLevel;
|
||||
accessToken?: () => string;
|
||||
accessTokenFactory?: () => string;
|
||||
}
|
||||
|
||||
const enum ConnectionState {
|
||||
|
|
@ -42,7 +42,10 @@ export class HttpConnection implements IConnection {
|
|||
constructor(url: string, options: IHttpConnectionOptions = {}) {
|
||||
this.logger = LoggerFactory.createLogger(options.logger);
|
||||
this.baseUrl = this.resolveUrl(url);
|
||||
|
||||
options = options || {};
|
||||
options.accessTokenFactory = options.accessTokenFactory || (() => null);
|
||||
|
||||
this.httpClient = options.httpClient || new DefaultHttpClient();
|
||||
this.connectionState = ConnectionState.Disconnected;
|
||||
this.options = options;
|
||||
|
|
@ -68,9 +71,10 @@ export class HttpConnection implements IConnection {
|
|||
}
|
||||
else {
|
||||
let headers;
|
||||
if (this.options.accessToken) {
|
||||
let token = this.options.accessTokenFactory();
|
||||
if (token) {
|
||||
headers = new Map<string, string>();
|
||||
headers.set("Authorization", `Bearer ${this.options.accessToken()}`);
|
||||
headers.set("Authorization", `Bearer ${token}`);
|
||||
}
|
||||
|
||||
let negotiatePayload = await this.httpClient.post(this.resolveNegotiateUrl(this.baseUrl), {
|
||||
|
|
@ -119,13 +123,13 @@ export class HttpConnection implements IConnection {
|
|||
transport = TransportType[availableTransports[0]];
|
||||
}
|
||||
if (transport === TransportType.WebSockets && availableTransports.indexOf(TransportType[transport]) >= 0) {
|
||||
return new WebSocketTransport(this.options.accessToken, this.logger);
|
||||
return new WebSocketTransport(this.options.accessTokenFactory, this.logger);
|
||||
}
|
||||
if (transport === TransportType.ServerSentEvents && availableTransports.indexOf(TransportType[transport]) >= 0) {
|
||||
return new ServerSentEventsTransport(this.httpClient, this.options.accessToken, this.logger);
|
||||
return new ServerSentEventsTransport(this.httpClient, this.options.accessTokenFactory, this.logger);
|
||||
}
|
||||
if (transport === TransportType.LongPolling && availableTransports.indexOf(TransportType[transport]) >= 0) {
|
||||
return new LongPollingTransport(this.httpClient, this.options.accessToken, this.logger);
|
||||
return new LongPollingTransport(this.httpClient, this.options.accessTokenFactory, this.logger);
|
||||
}
|
||||
|
||||
if (this.isITransport(transport)) {
|
||||
|
|
|
|||
|
|
@ -29,21 +29,21 @@ export interface ITransport {
|
|||
|
||||
export class WebSocketTransport implements ITransport {
|
||||
private readonly logger: ILogger;
|
||||
private readonly accessToken: () => string;
|
||||
private readonly accessTokenFactory: () => string;
|
||||
private webSocket: WebSocket;
|
||||
|
||||
constructor(accessToken: () => string, logger: ILogger) {
|
||||
constructor(accessTokenFactory: () => string, logger: ILogger) {
|
||||
this.logger = logger;
|
||||
this.accessToken = accessToken;
|
||||
this.accessTokenFactory = accessTokenFactory || (() => null);
|
||||
}
|
||||
|
||||
connect(url: string, requestedTransferMode: TransferMode, connection: IConnection): Promise<TransferMode> {
|
||||
|
||||
return new Promise<TransferMode>((resolve, reject) => {
|
||||
url = url.replace(/^http/, "ws");
|
||||
if (this.accessToken) {
|
||||
let token = this.accessToken();
|
||||
url += (url.indexOf("?") < 0 ? "?" : "&") + `signalRTokenHeader=${token}`;
|
||||
let token = this.accessTokenFactory();
|
||||
if (token) {
|
||||
url += (url.indexOf("?") < 0 ? "?" : "&") + `access_token=${encodeURIComponent(token)}`;
|
||||
}
|
||||
|
||||
let webSocket = new WebSocket(url);
|
||||
|
|
@ -105,14 +105,14 @@ export class WebSocketTransport implements ITransport {
|
|||
|
||||
export class ServerSentEventsTransport implements ITransport {
|
||||
private readonly httpClient: HttpClient;
|
||||
private readonly accessToken: () => string;
|
||||
private readonly accessTokenFactory: () => string;
|
||||
private readonly logger: ILogger;
|
||||
private eventSource: EventSource;
|
||||
private url: string;
|
||||
|
||||
constructor(httpClient: HttpClient, accessToken: () => string, logger: ILogger) {
|
||||
constructor(httpClient: HttpClient, accessTokenFactory: () => string, logger: ILogger) {
|
||||
this.httpClient = httpClient;
|
||||
this.accessToken = accessToken;
|
||||
this.accessTokenFactory = accessTokenFactory || (() => null);
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
|
|
@ -123,9 +123,9 @@ export class ServerSentEventsTransport implements ITransport {
|
|||
|
||||
this.url = url;
|
||||
return new Promise<TransferMode>((resolve, reject) => {
|
||||
if (this.accessToken) {
|
||||
let token = this.accessToken();
|
||||
url += (url.indexOf("?") < 0 ? "?" : "&") + `signalRTokenHeader=${token}`;
|
||||
let token = this.accessTokenFactory();
|
||||
if (token) {
|
||||
url += (url.indexOf("?") < 0 ? "?" : "&") + `access_token=${encodeURIComponent(token)}`;
|
||||
}
|
||||
|
||||
let eventSource = new EventSource(url);
|
||||
|
|
@ -145,7 +145,7 @@ export class ServerSentEventsTransport implements ITransport {
|
|||
}
|
||||
};
|
||||
|
||||
eventSource.onerror = (e: ErrorEvent) => {
|
||||
eventSource.onerror = (e: any) => {
|
||||
reject();
|
||||
|
||||
// don't report an error if the transport did not start successfully
|
||||
|
|
@ -168,7 +168,7 @@ export class ServerSentEventsTransport implements ITransport {
|
|||
}
|
||||
|
||||
async send(data: any): Promise<void> {
|
||||
return send(this.httpClient, this.url, this.accessToken, data);
|
||||
return send(this.httpClient, this.url, this.accessTokenFactory, data);
|
||||
}
|
||||
|
||||
stop(): Promise<void> {
|
||||
|
|
@ -185,16 +185,16 @@ export class ServerSentEventsTransport implements ITransport {
|
|||
|
||||
export class LongPollingTransport implements ITransport {
|
||||
private readonly httpClient: HttpClient;
|
||||
private readonly accessToken: () => string;
|
||||
private readonly accessTokenFactory: () => string;
|
||||
private readonly logger: ILogger;
|
||||
|
||||
private url: string;
|
||||
private pollXhr: XMLHttpRequest;
|
||||
private pollAbort: AbortController;
|
||||
|
||||
constructor(httpClient: HttpClient, accessToken: () => string, logger: ILogger) {
|
||||
constructor(httpClient: HttpClient, accessTokenFactory: () => string, logger: ILogger) {
|
||||
this.httpClient = httpClient;
|
||||
this.accessToken = accessToken;
|
||||
this.accessTokenFactory = accessTokenFactory || (() => null);
|
||||
this.logger = logger;
|
||||
this.pollAbort = new AbortController();
|
||||
}
|
||||
|
|
@ -225,8 +225,9 @@ export class LongPollingTransport implements ITransport {
|
|||
pollOptions.responseType = "arraybuffer";
|
||||
}
|
||||
|
||||
if (this.accessToken) {
|
||||
pollOptions.headers.set("Authorization", `Bearer ${this.accessToken()}`);
|
||||
let token = this.accessTokenFactory();
|
||||
if (token) {
|
||||
pollOptions.headers.set("Authorization", `Bearer ${token}`);
|
||||
}
|
||||
|
||||
while (!this.pollAbort.signal.aborted) {
|
||||
|
|
@ -281,7 +282,7 @@ export class LongPollingTransport implements ITransport {
|
|||
}
|
||||
|
||||
async send(data: any): Promise<void> {
|
||||
return send(this.httpClient, this.url, this.accessToken, data);
|
||||
return send(this.httpClient, this.url, this.accessTokenFactory, data);
|
||||
}
|
||||
|
||||
stop(): Promise<void> {
|
||||
|
|
@ -293,11 +294,12 @@ export class LongPollingTransport implements ITransport {
|
|||
onclose: TransportClosed;
|
||||
}
|
||||
|
||||
async function send(httpClient: HttpClient, url: string, accessToken: () => string, content: string | ArrayBuffer): Promise<void> {
|
||||
async function send(httpClient: HttpClient, url: string, accessTokenFactory: () => string, content: string | ArrayBuffer): Promise<void> {
|
||||
let headers;
|
||||
if (accessToken) {
|
||||
let token = accessTokenFactory();
|
||||
if (token) {
|
||||
headers = new Map<string, string>();
|
||||
headers.set("Authorization", `Bearer ${accessToken()}`)
|
||||
headers.set("Authorization", `Bearer ${accessTokenFactory()}`)
|
||||
}
|
||||
|
||||
await httpClient.post(url, {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
|
@ -50,12 +50,12 @@ namespace JwtSample
|
|||
{
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
var signalRTokenHeader = context.Request.Query["signalRTokenHeader"];
|
||||
var accessToken = context.Request.Query["access_token"];
|
||||
|
||||
if (!string.IsNullOrEmpty(signalRTokenHeader) &&
|
||||
if (!string.IsNullOrEmpty(accessToken) &&
|
||||
(context.HttpContext.WebSockets.IsWebSocketRequest || context.Request.Headers["Accept"] == "text/event-stream"))
|
||||
{
|
||||
context.Token = context.Request.Query["signalRTokenHeader"];
|
||||
context.Token = context.Request.Query["access_token"];
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
.then(function () {
|
||||
var options = {
|
||||
transport: transportType,
|
||||
accessToken: function () { return tokens[clientId]; }
|
||||
accessTokenFactory: function () { return tokens[clientId]; }
|
||||
};
|
||||
|
||||
connection = new signalR.HubConnection('/broadcast', options);
|
||||
|
|
|
|||
Loading…
Reference in New Issue