Skip to content

Commit 96764d2

Browse files
authored
Returning rejected promises in HttpConnection (#8315)
1 parent c9c2bf6 commit 96764d2

File tree

2 files changed

+76
-10
lines changed

2 files changed

+76
-10
lines changed

src/SignalR/clients/ts/signalr/src/HttpConnection.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export class HttpConnection implements IConnection {
115115

116116
public send(data: string | ArrayBuffer): Promise<void> {
117117
if (this.connectionState !== ConnectionState.Connected) {
118-
throw new Error("Cannot send data if the connection is not in the 'Connected' State.");
118+
return Promise.reject(new Error("Cannot send data if the connection is not in the 'Connected' State."));
119119
}
120120

121121
// Transport will not be null if state is connected
@@ -157,7 +157,7 @@ export class HttpConnection implements IConnection {
157157
// No fallback or negotiate in this case.
158158
await this.transport!.connect(url, transferFormat);
159159
} else {
160-
throw Error("Negotiation can only be skipped when using the WebSocket transport directly.");
160+
return Promise.reject(new Error("Negotiation can only be skipped when using the WebSocket transport directly."));
161161
}
162162
} else {
163163
let negotiateResponse: INegotiateResponse | null = null;
@@ -171,11 +171,11 @@ export class HttpConnection implements IConnection {
171171
}
172172

173173
if (negotiateResponse.error) {
174-
throw Error(negotiateResponse.error);
174+
return Promise.reject(new Error(negotiateResponse.error));
175175
}
176176

177177
if ((negotiateResponse as any).ProtocolVersion) {
178-
throw Error("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details.");
178+
return Promise.reject(new Error("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details."));
179179
}
180180

181181
if (negotiateResponse.url) {
@@ -194,7 +194,7 @@ export class HttpConnection implements IConnection {
194194
while (negotiateResponse.url && redirects < MAX_REDIRECTS);
195195

196196
if (redirects === MAX_REDIRECTS && negotiateResponse.url) {
197-
throw Error("Negotiate redirection limit exceeded.");
197+
return Promise.reject(new Error("Negotiate redirection limit exceeded."));
198198
}
199199

200200
await this.createTransport(url, this.options.transport, negotiateResponse, transferFormat);
@@ -214,7 +214,7 @@ export class HttpConnection implements IConnection {
214214
this.logger.log(LogLevel.Error, "Failed to start the connection: " + e);
215215
this.connectionState = ConnectionState.Disconnected;
216216
this.transport = undefined;
217-
throw e;
217+
return Promise.reject(e);
218218
}
219219
}
220220

@@ -238,13 +238,13 @@ export class HttpConnection implements IConnection {
238238
});
239239

240240
if (response.statusCode !== 200) {
241-
throw Error(`Unexpected status code returned from negotiate ${response.statusCode}`);
241+
return Promise.reject(new Error(`Unexpected status code returned from negotiate ${response.statusCode}`));
242242
}
243243

244244
return JSON.parse(response.content as string) as INegotiateResponse;
245245
} catch (e) {
246246
this.logger.log(LogLevel.Error, "Failed to complete negotiation with the server: " + e);
247-
throw e;
247+
return Promise.reject(e);
248248
}
249249
}
250250

@@ -293,9 +293,9 @@ export class HttpConnection implements IConnection {
293293
}
294294

295295
if (transportExceptions.length > 0) {
296-
throw new Error(`Unable to connect to the server with any of the available transports. ${transportExceptions.join(" ")}`);
296+
return Promise.reject(new Error(`Unable to connect to the server with any of the available transports. ${transportExceptions.join(" ")}`));
297297
}
298-
throw new Error("None of the transports supported by the client are supported by the server.");
298+
return Promise.reject(new Error("None of the transports supported by the client are supported by the server."));
299299
}
300300

301301
private constructTransport(transport: HttpTransportType) {

src/SignalR/clients/ts/signalr/tests/HttpConnection.test.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,72 @@ describe("HttpConnection", () => {
150150
});
151151
});
152152

153+
it("cannot send with an un-started connection", async () => {
154+
await VerifyLogger.run(async (logger) => {
155+
const connection = new HttpConnection("http://tempuri.org");
156+
157+
await expect(connection.send("LeBron James"))
158+
.rejects
159+
.toThrow("Cannot send data if the connection is not in the 'Connected' State.");
160+
});
161+
});
162+
163+
it("sending before start doesn't throw synchronously", async () => {
164+
await VerifyLogger.run(async (logger) => {
165+
const connection = new HttpConnection("http://tempuri.org");
166+
167+
try {
168+
connection.send("test").catch((e) => {});
169+
} catch (e) {
170+
expect(false).toBe(true);
171+
}
172+
173+
});
174+
});
175+
176+
it("cannot be started if negotiate returns non 200 response", async () => {
177+
await VerifyLogger.run(async (logger) => {
178+
const options: IHttpConnectionOptions = {
179+
...commonOptions,
180+
httpClient: new TestHttpClient()
181+
.on("POST", () => new HttpResponse(999))
182+
.on("GET", () => ""),
183+
logger,
184+
} as IHttpConnectionOptions;
185+
186+
const connection = new HttpConnection("http://tempuri.org", options);
187+
await expect(connection.start(TransferFormat.Text))
188+
.rejects
189+
.toThrow("Unexpected status code returned from negotiate 999");
190+
},
191+
"Failed to start the connection: Error: Unexpected status code returned from negotiate 999");
192+
});
193+
194+
it("all transport failure error get aggregated", async () => {
195+
await VerifyLogger.run(async (loggerImpl) => {
196+
const options: IHttpConnectionOptions = {
197+
WebSocket: false,
198+
...commonOptions,
199+
httpClient: new TestHttpClient()
200+
.on("POST", () => defaultNegotiateResponse)
201+
.on("GET", () => new HttpResponse(200))
202+
.on("DELETE", () => new HttpResponse(202)),
203+
204+
logger: loggerImpl,
205+
transport: HttpTransportType.WebSockets,
206+
} as IHttpConnectionOptions;
207+
208+
const connection = new HttpConnection("http://tempuri.org", options);
209+
await expect(connection.start(TransferFormat.Text))
210+
.rejects
211+
.toThrow("Unable to connect to the server with any of the available transports. WebSockets failed: null ServerSentEvents failed: Error: 'ServerSentEvents' is disabled by the client. LongPolling failed: Error: 'LongPolling' is disabled by the client.");
212+
},
213+
"Failed to start the transport 'WebSockets': null",
214+
"Failed to start the transport 'ServerSentEvents': Error: 'ServerSentEvents' is disabled by the client.",
215+
"Failed to start the transport 'LongPolling': Error: 'LongPolling' is disabled by the client.",
216+
"Failed to start the connection: Error: Unable to connect to the server with any of the available transports. WebSockets failed: null ServerSentEvents failed: Error: 'ServerSentEvents' is disabled by the client. LongPolling failed: Error: 'LongPolling' is disabled by the client.");
217+
});
218+
153219
it("can stop a non-started connection", async () => {
154220
await VerifyLogger.run(async (logger) => {
155221
const connection = new HttpConnection("http://tempuri.org", { ...commonOptions, logger });

0 commit comments

Comments
 (0)