fix #1155 by renaming signalRTokenHeader to access_token (#1343) (#1359)

This commit is contained in:
Andrew Stanton-Nurse 2018-01-28 14:52:28 -08:00 committed by GitHub
parent 4203540cb0
commit 2625b389b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 90 additions and 76 deletions

View File

@ -58,12 +58,12 @@ namespace FunctionalTests
{ {
OnMessageReceived = context => OnMessageReceived = context =>
{ {
var signalRTokenHeader = context.Request.Query["signalRTokenHeader"]; var signalRTokenHeader = context.Request.Query["access_token"];
if (!string.IsNullOrEmpty(signalRTokenHeader) && if (!string.IsNullOrEmpty(signalRTokenHeader) &&
(context.HttpContext.WebSockets.IsWebSocketRequest || context.Request.Headers["Accept"] == "text/event-stream")) (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; return Task.CompletedTask;
} }

View File

@ -476,7 +476,7 @@ describe('hubConnection', function () {
hubConnection = new HubConnection('/authorizedhub', { hubConnection = new HubConnection('/authorizedhub', {
transport: transportType, transport: transportType,
logger: LogLevel.Trace, logger: LogLevel.Trace,
accessToken: () => jwtToken accessTokenFactory: () => jwtToken
}); });
hubConnection.onclose(function (error) { hubConnection.onclose(function (error) {
expect(error).toBe(undefined); expect(error).toBe(undefined);

View File

@ -9,25 +9,29 @@ import { ITransport, TransportType, TransferMode } from "../src/Transports"
import { eachTransport, eachEndpointUrl } from "./Common"; import { eachTransport, eachEndpointUrl } from "./Common";
import { HttpResponse } from "../src/index"; import { HttpResponse } from "../src/index";
const commonOptions: IHttpConnectionOptions = {
logger: null
};
describe("HttpConnection", () => { describe("HttpConnection", () => {
it("cannot be created with relative url if document object is not present", () => { 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'.")); .toThrow(new Error("Cannot resolve '/test'."));
}); });
it("cannot be created with relative url if window object is not present", () => { it("cannot be created with relative url if window object is not present", () => {
(<any>global).window = {}; (<any>global).window = {};
expect(() => new HttpConnection("/test")) expect(() => new HttpConnection("/test", commonOptions))
.toThrow(new Error("Cannot resolve '/test'.")); .toThrow(new Error("Cannot resolve '/test'."));
delete (<any>global).window; delete (<any>global).window;
}); });
it("starting connection fails if getting id fails", async (done) => { it("starting connection fails if getting id fails", async (done) => {
let options: IHttpConnectionOptions = { let options: IHttpConnectionOptions = {
...commonOptions,
httpClient: new TestHttpClient() httpClient: new TestHttpClient()
.on("POST", r => Promise.reject("error")) .on("POST", r => Promise.reject("error"))
.on("GET", r => ""), .on("GET", r => ""),
logger: null
} as IHttpConnectionOptions; } as IHttpConnectionOptions;
let connection = new HttpConnection("http://tempuri.org", options); let connection = new HttpConnection("http://tempuri.org", options);
@ -45,6 +49,7 @@ describe("HttpConnection", () => {
it("cannot start a running connection", async (done) => { it("cannot start a running connection", async (done) => {
let options: IHttpConnectionOptions = { let options: IHttpConnectionOptions = {
...commonOptions,
httpClient: new TestHttpClient() httpClient: new TestHttpClient()
.on("POST", r => { .on("POST", r => {
connection.start() connection.start()
@ -58,7 +63,6 @@ describe("HttpConnection", () => {
}); });
return Promise.reject("error"); return Promise.reject("error");
}), }),
logger: null
} as IHttpConnectionOptions; } as IHttpConnectionOptions;
let connection = new HttpConnection("http://tempuri.org", options); let connection = new HttpConnection("http://tempuri.org", options);
@ -75,13 +79,13 @@ describe("HttpConnection", () => {
it("can start a stopped connection", async (done) => { it("can start a stopped connection", async (done) => {
let negotiateCalls = 0; let negotiateCalls = 0;
let options: IHttpConnectionOptions = { let options: IHttpConnectionOptions = {
...commonOptions,
httpClient: new TestHttpClient() httpClient: new TestHttpClient()
.on("POST", r => { .on("POST", r => {
negotiateCalls += 1; negotiateCalls += 1;
return Promise.reject("reached negotiate"); return Promise.reject("reached negotiate");
}) })
.on("GET", r => ""), .on("GET", r => ""),
logger: null
} as IHttpConnectionOptions; } as IHttpConnectionOptions;
let connection = new HttpConnection("http://tempuri.org", options); let connection = new HttpConnection("http://tempuri.org", options);
@ -103,6 +107,7 @@ describe("HttpConnection", () => {
it("can stop a starting connection", async (done) => { it("can stop a starting connection", async (done) => {
let options: IHttpConnectionOptions = { let options: IHttpConnectionOptions = {
...commonOptions,
httpClient: new TestHttpClient() httpClient: new TestHttpClient()
.on("POST", r => { .on("POST", r => {
connection.stop(); connection.stop();
@ -112,7 +117,6 @@ describe("HttpConnection", () => {
connection.stop(); connection.stop();
return ""; return "";
}), }),
logger: null
} as IHttpConnectionOptions; } as IHttpConnectionOptions;
let connection = new HttpConnection("http://tempuri.org", options); let connection = new HttpConnection("http://tempuri.org", options);
@ -128,7 +132,7 @@ describe("HttpConnection", () => {
}); });
it("can stop a non-started connection", async (done) => { 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(); await connection.stop();
done(); done();
}); });
@ -151,11 +155,11 @@ describe("HttpConnection", () => {
} }
let options: IHttpConnectionOptions = { let options: IHttpConnectionOptions = {
...commonOptions,
httpClient: new TestHttpClient() httpClient: new TestHttpClient()
.on("POST", r => "{ \"connectionId\": \"42\" }") .on("POST", r => "{ \"connectionId\": \"42\" }")
.on("GET", r => ""), .on("GET", r => ""),
transport: fakeTransport, transport: fakeTransport,
logger: null,
} as IHttpConnectionOptions; } as IHttpConnectionOptions;
@ -178,6 +182,7 @@ describe("HttpConnection", () => {
let negotiateUrl: string; let negotiateUrl: string;
let connection: HttpConnection; let connection: HttpConnection;
let options: IHttpConnectionOptions = { let options: IHttpConnectionOptions = {
...commonOptions,
httpClient: new TestHttpClient() httpClient: new TestHttpClient()
.on("POST", r => { .on("POST", r => {
negotiateUrl = r.url; negotiateUrl = r.url;
@ -188,7 +193,6 @@ describe("HttpConnection", () => {
connection.stop(); connection.stop();
return ""; return "";
}), }),
logger: null
} as IHttpConnectionOptions; } as IHttpConnectionOptions;
connection = new HttpConnection(givenUrl, options); 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 => { it(`cannot be started if requested ${TransportType[requestedTransport]} transport not available on server`, async done => {
let options: IHttpConnectionOptions = { let options: IHttpConnectionOptions = {
...commonOptions,
httpClient: new TestHttpClient() httpClient: new TestHttpClient()
.on("POST", r => "{ \"connectionId\": \"42\", \"availableTransports\": [] }") .on("POST", r => "{ \"connectionId\": \"42\", \"availableTransports\": [] }")
.on("GET", r => ""), .on("GET", r => ""),
transport: requestedTransport, transport: requestedTransport,
logger: null
} as IHttpConnectionOptions; } as IHttpConnectionOptions;
let connection = new HttpConnection("http://tempuri.org", options); 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 => { it("cannot be started if no transport available on server and no transport requested", async done => {
let options: IHttpConnectionOptions = { let options: IHttpConnectionOptions = {
...commonOptions,
httpClient: new TestHttpClient() httpClient: new TestHttpClient()
.on("POST", r => "{ \"connectionId\": \"42\", \"availableTransports\": [] }") .on("POST", r => "{ \"connectionId\": \"42\", \"availableTransports\": [] }")
.on("GET", r => ""), .on("GET", r => ""),
logger: null
} as IHttpConnectionOptions; } as IHttpConnectionOptions;
let connection = new HttpConnection("http://tempuri.org", options); 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 => { it('does not send negotiate request if WebSockets transport requested explicitly', async done => {
let options: IHttpConnectionOptions = { let options: IHttpConnectionOptions = {
...commonOptions,
httpClient: new TestHttpClient(), httpClient: new TestHttpClient(),
transport: TransportType.WebSockets, transport: TransportType.WebSockets,
logger: null
} as IHttpConnectionOptions; } as IHttpConnectionOptions;
let connection = new HttpConnection("http://tempuri.org", options); let connection = new HttpConnection("http://tempuri.org", options);
@ -291,11 +295,11 @@ describe("HttpConnection", () => {
} as ITransport; } as ITransport;
let options: IHttpConnectionOptions = { let options: IHttpConnectionOptions = {
...commonOptions,
httpClient: new TestHttpClient() httpClient: new TestHttpClient()
.on("POST", r => "{ \"connectionId\": \"42\", \"availableTransports\": [] }") .on("POST", r => "{ \"connectionId\": \"42\", \"availableTransports\": [] }")
.on("GET", r => ""), .on("GET", r => ""),
transport: fakeTransport, transport: fakeTransport,
logger: null
} as IHttpConnectionOptions; } as IHttpConnectionOptions;
let connection = new HttpConnection("https://tempuri.org", options); let connection = new HttpConnection("https://tempuri.org", options);

View File

@ -13,12 +13,16 @@ import { MessageType } from "../src/IHubProtocol"
import { asyncit as it, captureException, delay, PromiseSource } from './Utils'; import { asyncit as it, captureException, delay, PromiseSource } from './Utils';
import { IHubConnectionOptions } from "../src/HubConnection"; import { IHubConnectionOptions } from "../src/HubConnection";
const commonOptions: IHubConnectionOptions = {
logger: null,
}
describe("HubConnection", () => { describe("HubConnection", () => {
describe("start", () => { describe("start", () => {
it("sends negotiation message", async () => { it("sends negotiation message", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
await hubConnection.start(); await hubConnection.start();
expect(connection.sentData.length).toBe(1) expect(connection.sentData.length).toBe(1)
expect(JSON.parse(connection.sentData[0])).toEqual({ expect(JSON.parse(connection.sentData[0])).toEqual({
@ -32,7 +36,7 @@ describe("HubConnection", () => {
it("sends a non blocking invocation", async () => { it("sends a non blocking invocation", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let invokePromise = hubConnection.send("testMethod", "arg", 42) let invokePromise = hubConnection.send("testMethod", "arg", 42)
.catch((_) => { }); // Suppress exception and unhandled promise rejection warning. .catch((_) => { }); // Suppress exception and unhandled promise rejection warning.
@ -56,7 +60,7 @@ describe("HubConnection", () => {
it("sends an invocation", async () => { it("sends an invocation", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let invokePromise = hubConnection.invoke("testMethod", "arg", 42) let invokePromise = hubConnection.invoke("testMethod", "arg", 42)
.catch((_) => { }); // Suppress exception and unhandled promise rejection warning. .catch((_) => { }); // Suppress exception and unhandled promise rejection warning.
@ -79,7 +83,7 @@ describe("HubConnection", () => {
it("rejects the promise when an error is received", async () => { it("rejects the promise when an error is received", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let invokePromise = hubConnection.invoke("testMethod", "arg", 42); let invokePromise = hubConnection.invoke("testMethod", "arg", 42);
connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId, error: "foo" }); 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 () => { it("resolves the promise when a result is received", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let invokePromise = hubConnection.invoke("testMethod", "arg", 42); let invokePromise = hubConnection.invoke("testMethod", "arg", 42);
connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId, result: "foo" }); connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId, result: "foo" });
@ -102,7 +106,7 @@ describe("HubConnection", () => {
it("completes pending invocations when stopped", async () => { it("completes pending invocations when stopped", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let invokePromise = hubConnection.invoke("testMethod"); let invokePromise = hubConnection.invoke("testMethod");
hubConnection.stop(); hubConnection.stop();
@ -113,7 +117,7 @@ describe("HubConnection", () => {
it("completes pending invocations when connection is lost", async () => { it("completes pending invocations when connection is lost", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let invokePromise = hubConnection.invoke("testMethod"); let invokePromise = hubConnection.invoke("testMethod");
// Typically this would be called by the transport // Typically this would be called by the transport
connection.onclose(new Error("Connection lost")); connection.onclose(new Error("Connection lost"));
@ -149,7 +153,7 @@ describe("HubConnection", () => {
it("callback invoked when servers invokes a method on the client", async () => { it("callback invoked when servers invokes a method on the client", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let value = ""; let value = "";
hubConnection.on("message", v => value = v); hubConnection.on("message", v => value = v);
@ -166,7 +170,7 @@ describe("HubConnection", () => {
it("can have multiple callbacks", async () => { it("can have multiple callbacks", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let numInvocations1 = 0; let numInvocations1 = 0;
let numInvocations2 = 0; let numInvocations2 = 0;
hubConnection.on("message", () => numInvocations1++); hubConnection.on("message", () => numInvocations1++);
@ -186,7 +190,7 @@ describe("HubConnection", () => {
it("can unsubscribe from on", async () => { it("can unsubscribe from on", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
var numInvocations = 0; var numInvocations = 0;
var callback = () => numInvocations++; var callback = () => numInvocations++;
@ -215,7 +219,7 @@ describe("HubConnection", () => {
it("unsubscribing from non-existing callbacks no-ops", async () => { it("unsubscribing from non-existing callbacks no-ops", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
hubConnection.off("_", () => { }); hubConnection.off("_", () => { });
hubConnection.on("message", t => { }); hubConnection.on("message", t => { });
@ -267,7 +271,7 @@ describe("HubConnection", () => {
it("sends an invocation", async () => { it("sends an invocation", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let invokePromise = hubConnection.stream("testStream", "arg", 42); let invokePromise = hubConnection.stream("testStream", "arg", 42);
// Verify the message is sent // Verify the message is sent
@ -289,7 +293,7 @@ describe("HubConnection", () => {
it("completes with an error when an error is yielded", async () => { it("completes with an error when an error is yielded", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let observer = new TestObserver(); let observer = new TestObserver();
hubConnection.stream<any>("testMethod", "arg", 42) hubConnection.stream<any>("testMethod", "arg", 42)
.subscribe(observer); .subscribe(observer);
@ -303,7 +307,7 @@ describe("HubConnection", () => {
it("completes the observer when a completion is received", async () => { it("completes the observer when a completion is received", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let observer = new TestObserver(); let observer = new TestObserver();
hubConnection.stream<any>("testMethod", "arg", 42) hubConnection.stream<any>("testMethod", "arg", 42)
.subscribe(observer); .subscribe(observer);
@ -316,7 +320,7 @@ describe("HubConnection", () => {
it("completes pending streams when stopped", async () => { it("completes pending streams when stopped", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let observer = new TestObserver(); let observer = new TestObserver();
hubConnection.stream<any>("testMethod") hubConnection.stream<any>("testMethod")
.subscribe(observer); .subscribe(observer);
@ -329,7 +333,7 @@ describe("HubConnection", () => {
it("completes pending streams when connection is lost", async () => { it("completes pending streams when connection is lost", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let observer = new TestObserver(); let observer = new TestObserver();
hubConnection.stream<any>("testMethod") hubConnection.stream<any>("testMethod")
.subscribe(observer); .subscribe(observer);
@ -344,7 +348,7 @@ describe("HubConnection", () => {
it("yields items as they arrive", async () => { it("yields items as they arrive", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let observer = new TestObserver(); let observer = new TestObserver();
hubConnection.stream<any>("testMethod") hubConnection.stream<any>("testMethod")
.subscribe(observer); .subscribe(observer);
@ -365,7 +369,7 @@ describe("HubConnection", () => {
it("does not require error function registered", async () => { it("does not require error function registered", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let observer = hubConnection.stream("testMethod").subscribe({ let observer = hubConnection.stream("testMethod").subscribe({
next: val => { } next: val => { }
}); });
@ -378,7 +382,7 @@ describe("HubConnection", () => {
it("does not require complete function registered", async () => { it("does not require complete function registered", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let observer = hubConnection.stream("testMethod").subscribe({ let observer = hubConnection.stream("testMethod").subscribe({
next: val => { } next: val => { }
}); });
@ -391,7 +395,7 @@ describe("HubConnection", () => {
it("can be canceled", () => { it("can be canceled", () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let observer = new TestObserver(); let observer = new TestObserver();
let subscription = hubConnection.stream("testMethod") let subscription = hubConnection.stream("testMethod")
.subscribe(observer); .subscribe(observer);
@ -417,7 +421,7 @@ describe("HubConnection", () => {
describe("onClose", () => { describe("onClose", () => {
it("can have multiple callbacks", async () => { it("can have multiple callbacks", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let invocations = 0; let invocations = 0;
hubConnection.onclose(e => invocations++); hubConnection.onclose(e => invocations++);
hubConnection.onclose(e => invocations++); hubConnection.onclose(e => invocations++);
@ -428,7 +432,7 @@ describe("HubConnection", () => {
it("callbacks receive error", async () => { it("callbacks receive error", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let error: Error; let error: Error;
hubConnection.onclose(e => error = e); hubConnection.onclose(e => error = e);
@ -439,7 +443,7 @@ describe("HubConnection", () => {
it("ignores null callbacks", async () => { it("ignores null callbacks", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
hubConnection.onclose(null); hubConnection.onclose(null);
hubConnection.onclose(undefined); hubConnection.onclose(undefined);
// Typically this would be called by the transport // 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 // Receive the ping mid-invocation so we can see that the rest of the flow works fine
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection, { logger: null }); let hubConnection = new HubConnection(connection, commonOptions);
let invokePromise = hubConnection.invoke("testMethod", "arg", 42); let invokePromise = hubConnection.invoke("testMethod", "arg", 42);
connection.receive({ type: MessageType.Ping }); connection.receive({ type: MessageType.Ping });
@ -464,7 +468,7 @@ describe("HubConnection", () => {
it("does not terminate if messages are received", async () => { it("does not terminate if messages are received", async () => {
let connection = new TestConnection(); 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>(); let p = new PromiseSource<Error>();
hubConnection.onclose(error => p.resolve(error)); hubConnection.onclose(error => p.resolve(error));
@ -489,7 +493,7 @@ describe("HubConnection", () => {
it("terminates if no messages received within timeout interval", async () => { it("terminates if no messages received within timeout interval", async () => {
let connection = new TestConnection(); 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>(); let p = new PromiseSource<Error>();
hubConnection.onclose(error => p.resolve(error)); hubConnection.onclose(error => p.resolve(error));

View File

@ -12,7 +12,7 @@ export interface IHttpConnectionOptions {
httpClient?: HttpClient; httpClient?: HttpClient;
transport?: TransportType | ITransport; transport?: TransportType | ITransport;
logger?: ILogger | LogLevel; logger?: ILogger | LogLevel;
accessToken?: () => string; accessTokenFactory?: () => string;
} }
const enum ConnectionState { const enum ConnectionState {
@ -42,7 +42,10 @@ export class HttpConnection implements IConnection {
constructor(url: string, options: IHttpConnectionOptions = {}) { constructor(url: string, options: IHttpConnectionOptions = {}) {
this.logger = LoggerFactory.createLogger(options.logger); this.logger = LoggerFactory.createLogger(options.logger);
this.baseUrl = this.resolveUrl(url); this.baseUrl = this.resolveUrl(url);
options = options || {}; options = options || {};
options.accessTokenFactory = options.accessTokenFactory || (() => null);
this.httpClient = options.httpClient || new DefaultHttpClient(); this.httpClient = options.httpClient || new DefaultHttpClient();
this.connectionState = ConnectionState.Disconnected; this.connectionState = ConnectionState.Disconnected;
this.options = options; this.options = options;
@ -68,9 +71,10 @@ export class HttpConnection implements IConnection {
} }
else { else {
let headers; let headers;
if (this.options.accessToken) { let token = this.options.accessTokenFactory();
if (token) {
headers = new Map<string, string>(); 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), { let negotiatePayload = await this.httpClient.post(this.resolveNegotiateUrl(this.baseUrl), {
@ -119,13 +123,13 @@ export class HttpConnection implements IConnection {
transport = TransportType[availableTransports[0]]; transport = TransportType[availableTransports[0]];
} }
if (transport === TransportType.WebSockets && availableTransports.indexOf(TransportType[transport]) >= 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) { 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) { 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)) { if (this.isITransport(transport)) {

View File

@ -29,21 +29,21 @@ export interface ITransport {
export class WebSocketTransport implements ITransport { export class WebSocketTransport implements ITransport {
private readonly logger: ILogger; private readonly logger: ILogger;
private readonly accessToken: () => string; private readonly accessTokenFactory: () => string;
private webSocket: WebSocket; private webSocket: WebSocket;
constructor(accessToken: () => string, logger: ILogger) { constructor(accessTokenFactory: () => string, logger: ILogger) {
this.logger = logger; this.logger = logger;
this.accessToken = accessToken; this.accessTokenFactory = accessTokenFactory || (() => null);
} }
connect(url: string, requestedTransferMode: TransferMode, connection: IConnection): Promise<TransferMode> { connect(url: string, requestedTransferMode: TransferMode, connection: IConnection): Promise<TransferMode> {
return new Promise<TransferMode>((resolve, reject) => { return new Promise<TransferMode>((resolve, reject) => {
url = url.replace(/^http/, "ws"); url = url.replace(/^http/, "ws");
if (this.accessToken) { let token = this.accessTokenFactory();
let token = this.accessToken(); if (token) {
url += (url.indexOf("?") < 0 ? "?" : "&") + `signalRTokenHeader=${token}`; url += (url.indexOf("?") < 0 ? "?" : "&") + `access_token=${encodeURIComponent(token)}`;
} }
let webSocket = new WebSocket(url); let webSocket = new WebSocket(url);
@ -105,14 +105,14 @@ export class WebSocketTransport implements ITransport {
export class ServerSentEventsTransport implements ITransport { export class ServerSentEventsTransport implements ITransport {
private readonly httpClient: HttpClient; private readonly httpClient: HttpClient;
private readonly accessToken: () => string; private readonly accessTokenFactory: () => string;
private readonly logger: ILogger; private readonly logger: ILogger;
private eventSource: EventSource; private eventSource: EventSource;
private url: string; private url: string;
constructor(httpClient: HttpClient, accessToken: () => string, logger: ILogger) { constructor(httpClient: HttpClient, accessTokenFactory: () => string, logger: ILogger) {
this.httpClient = httpClient; this.httpClient = httpClient;
this.accessToken = accessToken; this.accessTokenFactory = accessTokenFactory || (() => null);
this.logger = logger; this.logger = logger;
} }
@ -123,9 +123,9 @@ export class ServerSentEventsTransport implements ITransport {
this.url = url; this.url = url;
return new Promise<TransferMode>((resolve, reject) => { return new Promise<TransferMode>((resolve, reject) => {
if (this.accessToken) { let token = this.accessTokenFactory();
let token = this.accessToken(); if (token) {
url += (url.indexOf("?") < 0 ? "?" : "&") + `signalRTokenHeader=${token}`; url += (url.indexOf("?") < 0 ? "?" : "&") + `access_token=${encodeURIComponent(token)}`;
} }
let eventSource = new EventSource(url); let eventSource = new EventSource(url);
@ -145,7 +145,7 @@ export class ServerSentEventsTransport implements ITransport {
} }
}; };
eventSource.onerror = (e: ErrorEvent) => { eventSource.onerror = (e: any) => {
reject(); reject();
// don't report an error if the transport did not start successfully // 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> { 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> { stop(): Promise<void> {
@ -185,16 +185,16 @@ export class ServerSentEventsTransport implements ITransport {
export class LongPollingTransport implements ITransport { export class LongPollingTransport implements ITransport {
private readonly httpClient: HttpClient; private readonly httpClient: HttpClient;
private readonly accessToken: () => string; private readonly accessTokenFactory: () => string;
private readonly logger: ILogger; private readonly logger: ILogger;
private url: string; private url: string;
private pollXhr: XMLHttpRequest; private pollXhr: XMLHttpRequest;
private pollAbort: AbortController; private pollAbort: AbortController;
constructor(httpClient: HttpClient, accessToken: () => string, logger: ILogger) { constructor(httpClient: HttpClient, accessTokenFactory: () => string, logger: ILogger) {
this.httpClient = httpClient; this.httpClient = httpClient;
this.accessToken = accessToken; this.accessTokenFactory = accessTokenFactory || (() => null);
this.logger = logger; this.logger = logger;
this.pollAbort = new AbortController(); this.pollAbort = new AbortController();
} }
@ -225,8 +225,9 @@ export class LongPollingTransport implements ITransport {
pollOptions.responseType = "arraybuffer"; pollOptions.responseType = "arraybuffer";
} }
if (this.accessToken) { let token = this.accessTokenFactory();
pollOptions.headers.set("Authorization", `Bearer ${this.accessToken()}`); if (token) {
pollOptions.headers.set("Authorization", `Bearer ${token}`);
} }
while (!this.pollAbort.signal.aborted) { while (!this.pollAbort.signal.aborted) {
@ -281,7 +282,7 @@ export class LongPollingTransport implements ITransport {
} }
async send(data: any): Promise<void> { 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> { stop(): Promise<void> {
@ -293,11 +294,12 @@ export class LongPollingTransport implements ITransport {
onclose: TransportClosed; 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; let headers;
if (accessToken) { let token = accessTokenFactory();
if (token) {
headers = new Map<string, string>(); headers = new Map<string, string>();
headers.set("Authorization", `Bearer ${accessToken()}`) headers.set("Authorization", `Bearer ${accessTokenFactory()}`)
} }
await httpClient.post(url, { await httpClient.post(url, {

View File

@ -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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -50,12 +50,12 @@ namespace JwtSample
{ {
OnMessageReceived = context => 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.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; return Task.CompletedTask;
} }

View File

@ -68,7 +68,7 @@
.then(function () { .then(function () {
var options = { var options = {
transport: transportType, transport: transportType,
accessToken: function () { return tokens[clientId]; } accessTokenFactory: function () { return tokens[clientId]; }
}; };
connection = new signalR.HubConnection('/broadcast', options); connection = new signalR.HubConnection('/broadcast', options);