Merge branch 'rel/1.0.0-alpha1' into dev

This commit is contained in:
Pawel Kadluczka 2017-09-11 21:31:02 -07:00
commit 0557319870
10 changed files with 108 additions and 62 deletions

View File

@ -9,6 +9,10 @@ import { ITransport, TransportType, TransferMode } from "../Microsoft.AspNetCore
import { eachTransport } from "./Common"; import { eachTransport } from "./Common";
describe("Connection", () => { describe("Connection", () => {
it("cannot be created with relative url if document object is not present", () => {
expect(() => new HttpConnection("/test"))
.toThrow(new Error("Cannot resolve '/test'."));
});
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 = {

View File

@ -22,7 +22,8 @@ export namespace TextMessageFormat {
export namespace BinaryMessageFormat { export namespace BinaryMessageFormat {
export function write(output: Uint8Array): ArrayBuffer { export function write(output: Uint8Array): ArrayBuffer {
let size = output.byteLength; // .byteLength does is undefined in IE10
let size = output.byteLength || output.length;
let buffer = new Uint8Array(size + 8); let buffer = new Uint8Array(size + 8);
// javascript bitwise operators only support 32-bit integers // javascript bitwise operators only support 32-bit integers

View File

@ -34,10 +34,10 @@ export class HttpConnection implements IConnection {
readonly features: any = {}; readonly features: any = {};
constructor(url: string, options: IHttpConnectionOptions = {}) { constructor(url: string, options: IHttpConnectionOptions = {}) {
this.url = url; this.logger = LoggerFactory.createLogger(options.logging);
this.url = this.resolveUrl(url);
options = options || {}; options = options || {};
this.httpClient = options.httpClient || new HttpClient(); this.httpClient = options.httpClient || new HttpClient();
this.logger = LoggerFactory.createLogger(options.logging);
this.connectionState = ConnectionState.Initial; this.connectionState = ConnectionState.Initial;
this.options = options; this.options = options;
} }
@ -156,6 +156,28 @@ export class HttpConnection implements IConnection {
} }
} }
private resolveUrl(url: string) : string {
// startsWith is not supported in IE
if (url.lastIndexOf("https://", 0) === 0 || url.lastIndexOf("http://", 0) === 0) {
return url;
}
if (typeof window === 'undefined') {
throw new Error(`Cannot resolve '${url}'.`);
}
let parser = window.document.createElement("a");
parser.href = url;
let baseUrl = (!parser.protocol || parser.protocol === ":")
? `${window.document.location.protocol}//${(parser.host || window.document.location.host)}`
: `${parser.protocol}//${parser.host}`;
let normalizedUrl = baseUrl + url;
this.logger.log(LogLevel.Information, `Normalizing '${url}' to '${normalizedUrl}'`);
return normalizedUrl;
}
onDataReceived: DataReceived; onDataReceived: DataReceived;
onClosed: ConnectionClosed; onClosed: ConnectionClosed;
} }

View File

@ -3,6 +3,7 @@
import { ConnectionClosed } from "./Common" import { ConnectionClosed } from "./Common"
import { IConnection } from "./IConnection" import { IConnection } from "./IConnection"
import { HttpConnection} from "./HttpConnection"
import { TransportType, TransferMode } from "./Transports" import { TransportType, TransferMode } from "./Transports"
import { Subject, Observable } from "./Observable" import { Subject, Observable } from "./Observable"
import { IHubProtocol, ProtocolType, MessageType, HubMessage, CompletionMessage, ResultMessage, InvocationMessage, NegotiationMessage } from "./IHubProtocol"; import { IHubProtocol, ProtocolType, MessageType, HubMessage, CompletionMessage, ResultMessage, InvocationMessage, NegotiationMessage } from "./IHubProtocol";
@ -28,9 +29,15 @@ export class HubConnection {
private id: number; private id: number;
private connectionClosedCallback: ConnectionClosed; private connectionClosedCallback: ConnectionClosed;
constructor(connection: IConnection, options: IHubConnectionOptions = {}) { constructor(urlOrConnection: string | IConnection, options: IHubConnectionOptions = {}) {
this.connection = connection;
options = options || {}; options = options || {};
if (typeof urlOrConnection === "string") {
this.connection = new HttpConnection(urlOrConnection, options);
}
else {
this.connection = urlOrConnection;
}
this.logger = LoggerFactory.createLogger(options.logging); this.logger = LoggerFactory.createLogger(options.logging);
this.protocol = options.protocol || new JsonHubProtocol(); this.protocol = options.protocol || new JsonHubProtocol();

View File

@ -1,10 +1,10 @@
// 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.
import { IHttpConnectionOptions } from "./IHttpConnectionOptions"
import { IHubProtocol } from "./IHubProtocol" import { IHubProtocol } from "./IHubProtocol"
import { ILogger, LogLevel } from "./ILogger" import { ILogger, LogLevel } from "./ILogger"
export interface IHubConnectionOptions { export interface IHubConnectionOptions extends IHttpConnectionOptions {
protocol?: IHubProtocol; protocol?: IHubProtocol;
logging?: ILogger | LogLevel;
} }

View File

@ -247,12 +247,12 @@ export class LongPollingTransport implements ITransport {
} }
this.pollXhr = pollXhr; this.pollXhr = pollXhr;
this.pollXhr.open("GET", url, true);
this.pollXhr.open("GET", `${url}&_=${Date.now()}`, true);
if (transferMode === TransferMode.Binary) { if (transferMode === TransferMode.Binary) {
this.pollXhr.responseType = "arraybuffer"; this.pollXhr.responseType = "arraybuffer";
} }
// IE caches xhr requests
this.pollXhr.setRequestHeader("Cache-Control", "no-cache");
// TODO: consider making timeout configurable // TODO: consider making timeout configurable
this.pollXhr.timeout = 120000; this.pollXhr.timeout = 120000;
this.pollXhr.send(); this.pollXhr.send();

View File

@ -6,7 +6,10 @@
var ECHOENDPOINT_URL = "http://" + document.location.host + "/echo"; var ECHOENDPOINT_URL = "http://" + document.location.host + "/echo";
function getTransportTypes() { function getTransportTypes() {
var transportTypes = [signalR.TransportType.WebSockets]; var transportTypes = [];
if (typeof WebSocket !== "undefined") {
transportTypes.push(signalR.TransportType.WebSockets);
}
if (typeof EventSource !== "undefined") { if (typeof EventSource !== "undefined") {
transportTypes.push(signalR.TransportType.ServerSentEvents); transportTypes.push(signalR.TransportType.ServerSentEvents);
} }
@ -22,7 +25,12 @@ function eachTransport(action) {
} }
function eachTransportAndProtocol(action) { function eachTransportAndProtocol(action) {
var protocols = [new signalR.JsonHubProtocol(), new signalRMsgPack.MessagePackHubProtocol()]; var protocols = [new signalR.JsonHubProtocol()];
// IE9 does not support XmlHttpRequest advanced features so disable for now
// This can be enabled if we fix: https://github.com/aspnet/SignalR/issues/742
if (typeof new XMLHttpRequest().responseType === "string") {
protocols.push(new signalRMsgPack.MessagePackHubProtocol());
}
getTransportTypes().forEach(function (t) { getTransportTypes().forEach(function (t) {
return protocols.forEach(function (p) { return protocols.forEach(function (p) {
return action(t, p); return action(t, p);

View File

@ -4,30 +4,32 @@
"use strict"; "use strict";
describe('connection', function () { describe('connection', function () {
it("can connect to the server without specifying transport explicitly", function (done) { if (typeof WebSocket !== 'undefined') {
var message = "Hello World!"; it("can connect to the server without specifying transport explicitly", function (done) {
var connection = new signalR.HttpConnection(ECHOENDPOINT_URL); var message = "Hello World!";
var connection = new signalR.HttpConnection(ECHOENDPOINT_URL);
var received = ""; var received = "";
connection.onDataReceived = function (data) { connection.onDataReceived = function (data) {
received += data; received += data;
if (data == message) { if (data == message) {
connection.stop(); connection.stop();
} }
}; };
connection.onClosed = function (error) { connection.onClosed = function (error) {
expect(error).toBeUndefined(); expect(error).toBeUndefined();
done(); done();
}; };
connection.start().then(function () { connection.start().then(function () {
connection.send(message); connection.send(message);
}).catch(function (e) { }).catch(function (e) {
fail(); fail();
done(); done();
});
}); });
}); }
eachTransport(function (transportType) { eachTransport(function (transportType) {
it("over " + signalR.TransportType[transportType] + " can send and receive messages", function (done) { it("over " + signalR.TransportType[transportType] + " can send and receive messages", function (done) {

View File

@ -3,7 +3,7 @@
'use strict'; 'use strict';
var TESTHUBENDPOINT_URL = 'http://' + document.location.host + '/testhub'; var TESTHUBENDPOINT_URL = '/testhub';
describe('hubConnection', function () { describe('hubConnection', function () {
eachTransportAndProtocol(function (transportType, protocol) { eachTransportAndProtocol(function (transportType, protocol) {
@ -17,7 +17,7 @@ describe('hubConnection', function () {
protocol: protocol, protocol: protocol,
logging: signalR.LogLevel.Trace logging: signalR.LogLevel.Trace
}; };
var hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, options), options); var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options);
hubConnection.onClosed = function (error) { hubConnection.onClosed = function (error) {
expect(error).toBe(undefined); expect(error).toBe(undefined);
done(); done();
@ -44,7 +44,7 @@ describe('hubConnection', function () {
protocol: protocol, protocol: protocol,
logging: signalR.LogLevel.Trace logging: signalR.LogLevel.Trace
}; };
var hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, options), options); var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options);
hubConnection.onClosed = function (error) { hubConnection.onClosed = function (error) {
expect(error).toBe(undefined); expect(error).toBe(undefined);
@ -79,7 +79,7 @@ describe('hubConnection', function () {
protocol: protocol, protocol: protocol,
logging: signalR.LogLevel.Trace logging: signalR.LogLevel.Trace
}; };
var hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, options), options); var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options);
hubConnection.start().then(function () { hubConnection.start().then(function () {
hubConnection.invoke('ThrowException', errorMessage).then(function () { hubConnection.invoke('ThrowException', errorMessage).then(function () {
@ -105,7 +105,7 @@ describe('hubConnection', function () {
protocol: protocol, protocol: protocol,
logging: signalR.LogLevel.Trace logging: signalR.LogLevel.Trace
}; };
var hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, options), options); var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options);
hubConnection.start().then(function () { hubConnection.start().then(function () {
hubConnection.stream('ThrowException', errorMessage).subscribe({ hubConnection.stream('ThrowException', errorMessage).subscribe({
@ -132,7 +132,7 @@ describe('hubConnection', function () {
protocol: protocol, protocol: protocol,
logging: signalR.LogLevel.Trace logging: signalR.LogLevel.Trace
}; };
var hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, options), options); var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options);
var message = "你好 SignalR"; var message = "你好 SignalR";
@ -170,7 +170,7 @@ describe('hubConnection', function () {
protocol: protocol, protocol: protocol,
logging: signalR.LogLevel.Trace logging: signalR.LogLevel.Trace
}; };
var hubConnection = new signalR.HubConnection(new signalR.HttpConnection('http://' + document.location.host + '/uncreatable', options), options); var hubConnection = new signalR.HubConnection('http://' + document.location.host + '/uncreatable', options);
hubConnection.onClosed = function (error) { hubConnection.onClosed = function (error) {
expect(error.message).toMatch(errorRegex[signalR.TransportType[transportType]]); expect(error.message).toMatch(errorRegex[signalR.TransportType[transportType]]);

View File

@ -3,33 +3,35 @@
'use strict'; 'use strict';
describe('WebSockets', function () { if (typeof WebSocket !== 'undefined') {
it('can be used to connect to SignalR', function (done) { describe('WebSockets', function () {
var message = "message"; it('can be used to connect to SignalR', function (done) {
var message = "message";
var webSocket = new WebSocket(ECHOENDPOINT_URL.replace(/^http/, "ws")); var webSocket = new WebSocket(ECHOENDPOINT_URL.replace(/^http/, "ws"));
webSocket.onopen = function () { webSocket.onopen = function () {
webSocket.send(message); webSocket.send(message);
}; };
var received = ""; var received = "";
webSocket.onmessage = function (event) { webSocket.onmessage = function (event) {
received += event.data; received += event.data;
if (received === message) { if (received === message) {
webSocket.close(); webSocket.close();
} }
}; };
webSocket.onclose = function (event) { webSocket.onclose = function (event) {
if (!event.wasClean) { if (!event.wasClean) {
fail("connection closed with unexpected status code: " + event.code + " " + event.reason); fail("connection closed with unexpected status code: " + event.code + " " + event.reason);
} }
// Jasmine doesn't like tests without expectations // Jasmine doesn't like tests without expectations
expect(event.wasClean).toBe(true); expect(event.wasClean).toBe(true);
done(); done();
}; };
});
}); });
}); }