diff --git a/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/HubConnection.java b/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/HubConnection.java index aa333fb508..0ad972053e 100644 --- a/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/HubConnection.java +++ b/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/HubConnection.java @@ -57,6 +57,8 @@ public class HubConnection { private Map streamMap = new ConcurrentHashMap<>(); private TransportEnum transportEnum = TransportEnum.ALL; private String connectionId; + private String connectionToken; + private final int negotiateVersion = 1; private final Logger logger = LoggerFactory.getLogger(HubConnection.class); /** @@ -339,11 +341,12 @@ public class HubConnection { }); stopError = null; + String urlWithQS = Utils.appendQueryString(baseUrl, "negotiateVersion=" + negotiateVersion); Single negotiate = null; if (!skipNegotiate) { - negotiate = tokenCompletable.andThen(Single.defer(() -> startNegotiate(baseUrl, 0))); + negotiate = tokenCompletable.andThen(Single.defer(() -> startNegotiate(urlWithQS, 0))); } else { - negotiate = tokenCompletable.andThen(Single.defer(() -> Single.just(new NegotiateResponse(baseUrl)))); + negotiate = tokenCompletable.andThen(Single.defer(() -> Single.just(new NegotiateResponse(urlWithQS)))); } CompletableSubject start = CompletableSubject.create(); @@ -376,7 +379,6 @@ public class HubConnection { hubConnectionStateLock.lock(); try { hubConnectionState = HubConnectionState.CONNECTED; - this.connectionId = negotiateResponse.getConnectionId(); logger.info("HubConnection started."); resetServerTimeout(); //Don't send pings if we're using long polling. @@ -446,19 +448,21 @@ public class HubConnection { throw new RuntimeException("There were no compatible transports on the server."); } - String finalUrl = url; - if (response.getConnectionId() != null) { - if (url.contains("?")) { - finalUrl = url + "&id=" + response.getConnectionId(); - } else { - finalUrl = url + "?id=" + response.getConnectionId(); - } + if (response.getVersion() > 0) { + this.connectionId = response.getConnectionId(); + this.connectionToken = response.getConnectionToken(); + } else { + this.connectionToken = this.connectionId = response.getConnectionId(); } + + String finalUrl = Utils.appendQueryString(url, "id=" + this.connectionToken); + response.setFinalUrl(finalUrl); return Single.just(response); } - return startNegotiate(response.getRedirectUrl(), negotiateAttempts + 1); + String redirectUrl = Utils.appendQueryString(response.getRedirectUrl(), "negotiateVersion=" + negotiateVersion); + return startNegotiate(redirectUrl, negotiateAttempts + 1); }); } @@ -520,6 +524,7 @@ public class HubConnection { handshakeResponseSubject.onComplete(); redirectAccessTokenProvider = null; connectionId = null; + connectionToken = null; transportEnum = TransportEnum.ALL; this.localHeaders.clear(); this.streamMap.clear(); diff --git a/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/Negotiate.java b/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/Negotiate.java index d63359b90c..d177d32fb9 100644 --- a/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/Negotiate.java +++ b/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/Negotiate.java @@ -10,7 +10,7 @@ class Negotiate { // Check if we have a query string. If we do then we ignore it for now. int queryStringIndex = url.indexOf('?'); if (queryStringIndex > 0) { - negotiateUrl = url.substring(0, url.indexOf('?')); + negotiateUrl = url.substring(0, queryStringIndex); } else { negotiateUrl = url; } @@ -24,7 +24,7 @@ class Negotiate { // Add the query string back if it existed. if (queryStringIndex > 0) { - negotiateUrl += url.substring(url.indexOf('?')); + negotiateUrl += url.substring(queryStringIndex); } return negotiateUrl; diff --git a/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/NegotiateResponse.java b/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/NegotiateResponse.java index f115e9601b..bf09b37578 100644 --- a/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/NegotiateResponse.java +++ b/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/NegotiateResponse.java @@ -11,11 +11,13 @@ import com.google.gson.stream.JsonReader; class NegotiateResponse { private String connectionId; + private String connectionToken; private Set availableTransports = new HashSet<>(); private String redirectUrl; private String accessToken; private String error; private String finalUrl; + private int version; public NegotiateResponse(JsonReader reader) { try { @@ -30,6 +32,12 @@ class NegotiateResponse { case "ProtocolVersion": this.error = "Detected 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."; return; + case "negotiateVersion": + this.version = reader.nextInt(); + break; + case "connectionToken": + this.connectionToken = reader.nextString(); + break; case "url": this.redirectUrl = reader.nextString(); break; @@ -106,6 +114,14 @@ class NegotiateResponse { return finalUrl; } + public int getVersion() { + return version; + } + + public String getConnectionToken() { + return connectionToken; + } + public void setFinalUrl(String url) { this.finalUrl = url; } diff --git a/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/Utils.java b/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/Utils.java new file mode 100644 index 0000000000..d08c6fb914 --- /dev/null +++ b/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/Utils.java @@ -0,0 +1,14 @@ +// 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. + +package com.microsoft.signalr; + +class Utils { + public static String appendQueryString(String original, String queryStringValue) { + if (original.contains("?")) { + return original + "&" + queryStringValue; + } else { + return original + "?" + queryStringValue; + } + } +} \ No newline at end of file diff --git a/src/SignalR/clients/java/signalr/src/test/java/com/microsoft/signalr/HubConnectionTest.java b/src/SignalR/clients/java/signalr/src/test/java/com/microsoft/signalr/HubConnectionTest.java index f28adf13e7..d23cdc7464 100644 --- a/src/SignalR/clients/java/signalr/src/test/java/com/microsoft/signalr/HubConnectionTest.java +++ b/src/SignalR/clients/java/signalr/src/test/java/com/microsoft/signalr/HubConnectionTest.java @@ -1714,12 +1714,12 @@ class HubConnectionTest { List sentRequests = client.getSentRequests(); assertEquals(1, sentRequests.size()); - assertEquals("http://example.com/negotiate", sentRequests.get(0).getUrl()); + assertEquals("http://example.com/negotiate?negotiateVersion=1", sentRequests.get(0).getUrl()); } @Test public void negotiateThatRedirectsForeverFailsAfter100Tries() { - TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate", + TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(200, "", "{\"url\":\"http://example.com\"}"))); HubConnection hubConnection = HubConnectionBuilder @@ -1752,7 +1752,7 @@ class HubConnectionTest { @Test public void connectionIdIsAvailableAfterStart() { - TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate", + TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}"))); @@ -1775,9 +1775,62 @@ class HubConnectionTest { assertNull(hubConnection.getConnectionId()); } + @Test + public void connectionTokenAppearsInQSConnectionIdIsOnConnectionInstance() { + TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate?negotiateVersion=1", + (req) -> Single.just(new HttpResponse(200, "", + "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\"," + + "\"negotiateVersion\": 1," + + "\"connectionToken\":\"connection-token-value\"," + + "\"availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}"))); + + MockTransport transport = new MockTransport(true); + HubConnection hubConnection = HubConnectionBuilder + .create("http://example.com") + .withTransportImplementation(transport) + .withHttpClient(client) + .build(); + + assertEquals(HubConnectionState.DISCONNECTED, hubConnection.getConnectionState()); + assertNull(hubConnection.getConnectionId()); + hubConnection.start().timeout(1, TimeUnit.SECONDS).blockingAwait(); + assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); + assertEquals("bVOiRPG8-6YiJ6d7ZcTOVQ", hubConnection.getConnectionId()); + assertEquals("http://example.com?negotiateVersion=1&id=connection-token-value", transport.getUrl()); + hubConnection.stop().timeout(1, TimeUnit.SECONDS).blockingAwait(); + assertEquals(HubConnectionState.DISCONNECTED, hubConnection.getConnectionState()); + assertNull(hubConnection.getConnectionId()); + } + + @Test + public void connectionTokenIsIgnoredIfNegotiateVersionIsNotPresentInNegotiateResponse() { + TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate?negotiateVersion=1", + (req) -> Single.just(new HttpResponse(200, "", + "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\"," + + "\"connectionToken\":\"connection-token-value\"," + + "\"availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}"))); + + MockTransport transport = new MockTransport(true); + HubConnection hubConnection = HubConnectionBuilder + .create("http://example.com") + .withTransportImplementation(transport) + .withHttpClient(client) + .build(); + + assertEquals(HubConnectionState.DISCONNECTED, hubConnection.getConnectionState()); + assertNull(hubConnection.getConnectionId()); + hubConnection.start().timeout(1, TimeUnit.SECONDS).blockingAwait(); + assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); + assertEquals("bVOiRPG8-6YiJ6d7ZcTOVQ", hubConnection.getConnectionId()); + assertEquals("http://example.com?negotiateVersion=1&id=bVOiRPG8-6YiJ6d7ZcTOVQ", transport.getUrl()); + hubConnection.stop().timeout(1, TimeUnit.SECONDS).blockingAwait(); + assertEquals(HubConnectionState.DISCONNECTED, hubConnection.getConnectionState()); + assertNull(hubConnection.getConnectionId()); + } + @Test public void afterSuccessfulNegotiateConnectsWithWebsocketsTransport() { - TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate", + TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}"))); @@ -1798,7 +1851,7 @@ class HubConnectionTest { @Test public void afterSuccessfulNegotiateConnectsWithLongPollingTransport() { - TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate", + TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + "availableTransports\":[{\"transport\":\"LongPolling\",\"transferFormats\":[\"Text\",\"Binary\"]}]}"))); @@ -1891,7 +1944,7 @@ class HubConnectionTest { @Test public void receivingServerSentEventsTransportFromNegotiateFails() { - TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate", + TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + "availableTransports\":[{\"transport\":\"ServerSentEvents\",\"transferFormats\":[\"Text\"]}]}"))); @@ -1911,7 +1964,7 @@ class HubConnectionTest { @Test public void negotiateThatReturnsErrorThrowsFromStart() { - TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate", + TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(200, "", "{\"error\":\"Test error.\"}"))); MockTransport transport = new MockTransport(true); @@ -1928,7 +1981,7 @@ class HubConnectionTest { @Test public void DetectWhenTryingToConnectToClassicSignalRServer() { - TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate", + TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(200, "", "{\"Url\":\"/signalr\"," + "\"ConnectionToken\":\"X97dw3uxW4NPPggQsYVcNcyQcuz4w2\"," + "\"ConnectionId\":\"05265228-1e2c-46c5-82a1-6a5bcc3f0143\"," + @@ -1954,9 +2007,9 @@ class HubConnectionTest { @Test public void negotiateRedirectIsFollowed() { - TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate", + TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(200, "", "{\"url\":\"http://testexample.com/\"}"))) - .on("POST", "http://testexample.com/negotiate", + .on("POST", "http://testexample.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}"))); @@ -1978,11 +2031,11 @@ class HubConnectionTest { AtomicReference beforeRedirectToken = new AtomicReference<>(); TestHttpClient client = new TestHttpClient() - .on("POST", "http://example.com/negotiate", (req) -> { + .on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> { beforeRedirectToken.set(req.getHeaders().get("Authorization")); return Single.just(new HttpResponse(200, "", "{\"url\":\"http://testexample.com/\",\"accessToken\":\"newToken\"}")); }) - .on("POST", "http://testexample.com/negotiate", (req) -> { + .on("POST", "http://testexample.com/negotiate?negotiateVersion=1", (req) -> { token.set(req.getHeaders().get("Authorization")); return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}")); @@ -2018,7 +2071,7 @@ class HubConnectionTest { public void accessTokenProviderIsUsedForNegotiate() { AtomicReference token = new AtomicReference<>(); TestHttpClient client = new TestHttpClient() - .on("POST", "http://example.com/negotiate", + .on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> { token.set(req.getHeaders().get("Authorization")); return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" @@ -2043,11 +2096,13 @@ class HubConnectionTest { public void accessTokenProviderIsOverriddenFromRedirectNegotiate() { AtomicReference token = new AtomicReference<>(); TestHttpClient client = new TestHttpClient() - .on("POST", "http://example.com/negotiate", (req) -> Single.just(new HttpResponse(200, "", "{\"url\":\"http://testexample.com/\",\"accessToken\":\"newToken\"}"))) - .on("POST", "http://testexample.com/negotiate", (req) -> { + .on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(200, "", "{\"url\":\"http://testexample.com/\",\"accessToken\":\"newToken\"}"))) + .on("POST", "http://testexample.com/negotiate?negotiateVersion=1", (req) -> { token.set(req.getHeaders().get("Authorization")); - return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" - + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}")); + return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\"," + + "\"connectionToken\":\"connection-token-value\"," + + "\"negotiateVersion\":1," + + "\"availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}")); }); MockTransport transport = new MockTransport(true); @@ -2060,7 +2115,7 @@ class HubConnectionTest { hubConnection.start().timeout(1, TimeUnit.SECONDS).blockingAwait(); assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); - assertEquals("http://testexample.com/?id=bVOiRPG8-6YiJ6d7ZcTOVQ", transport.getUrl()); + assertEquals("http://testexample.com/?negotiateVersion=1&id=connection-token-value", transport.getUrl()); hubConnection.stop(); assertEquals("Bearer newToken", token.get()); } @@ -2071,14 +2126,14 @@ class HubConnectionTest { AtomicReference beforeRedirectToken = new AtomicReference<>(); TestHttpClient client = new TestHttpClient() - .on("POST", "http://example.com/negotiate", (req) -> { + .on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> { beforeRedirectToken.set(req.getHeaders().get("Authorization")); return Single.just(new HttpResponse(200, "", "{\"url\":\"http://testexample.com/\",\"accessToken\":\"newToken\"}")); }) - .on("POST", "http://testexample.com/negotiate", (req) -> { + .on("POST", "http://testexample.com/negotiate?negotiateVersion=1", (req) -> { token.set(req.getHeaders().get("Authorization")); - return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" - + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}")); + return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\"," + + "\"availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}")); }); MockTransport transport = new MockTransport(true); @@ -2112,7 +2167,7 @@ class HubConnectionTest { AtomicInteger redirectCount = new AtomicInteger(); TestHttpClient client = new TestHttpClient() - .on("POST", "http://example.com/negotiate", (req) -> { + .on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> { if (redirectCount.get() == 0) { redirectCount.incrementAndGet(); redirectToken.set(req.getHeaders().get("Authorization")); @@ -2122,7 +2177,7 @@ class HubConnectionTest { return Single.just(new HttpResponse(200, "", "{\"url\":\"http://testexample.com/\",\"accessToken\":\"secondRedirectToken\"}")); } }) - .on("POST", "http://testexample.com/negotiate", (req) -> { + .on("POST", "http://testexample.com/negotiate?negotiateVersion=1", (req) -> { token.set(req.getHeaders().get("Authorization")); return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}")); @@ -2189,7 +2244,7 @@ class HubConnectionTest { public void headersAreSetAndSentThroughBuilder() { AtomicReference header = new AtomicReference<>(); TestHttpClient client = new TestHttpClient() - .on("POST", "http://example.com/negotiate", + .on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> { header.set(req.getHeaders().get("ExampleHeader")); return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" @@ -2214,7 +2269,7 @@ class HubConnectionTest { public void headersAreNotClearedWhenConnectionIsRestarted() { AtomicReference header = new AtomicReference<>(); TestHttpClient client = new TestHttpClient() - .on("POST", "http://example.com/negotiate", + .on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> { header.set(req.getHeaders().get("Authorization")); return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" @@ -2244,12 +2299,12 @@ class HubConnectionTest { AtomicReference afterRedirectHeader = new AtomicReference<>(); TestHttpClient client = new TestHttpClient() - .on("POST", "http://example.com/negotiate", + .on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> { beforeRedirectHeader.set(req.getHeaders().get("Authorization")); return Single.just(new HttpResponse(200, "", "{\"url\":\"http://testexample.com/\",\"accessToken\":\"redirectToken\"}\"}")); }) - .on("POST", "http://testexample.com/negotiate", + .on("POST", "http://testexample.com/negotiate?negotiateVersion=1", (req) -> { afterRedirectHeader.set(req.getHeaders().get("Authorization")); return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" @@ -2287,7 +2342,7 @@ class HubConnectionTest { public void sameHeaderSetTwiceGetsOverwritten() { AtomicReference header = new AtomicReference<>(); TestHttpClient client = new TestHttpClient() - .on("POST", "http://example.com/negotiate", + .on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> { header.set(req.getHeaders().get("ExampleHeader")); return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" @@ -2332,8 +2387,8 @@ class HubConnectionTest { public void hubConnectionCanBeStartedAfterBeingStoppedAndRedirected() { MockTransport mockTransport = new MockTransport(); TestHttpClient client = new TestHttpClient() - .on("POST", "http://example.com/negotiate", (req) -> Single.just(new HttpResponse(200, "", "{\"url\":\"http://testexample.com/\"}"))) - .on("POST", "http://testexample.com/negotiate", (req) -> Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + .on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(200, "", "{\"url\":\"http://testexample.com/\"}"))) + .on("POST", "http://testexample.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}"))); HubConnection hubConnection = HubConnectionBuilder @@ -2355,7 +2410,7 @@ class HubConnectionTest { @Test public void non200FromNegotiateThrowsError() { TestHttpClient client = new TestHttpClient() - .on("POST", "http://example.com/negotiate", + .on("POST", "http://example.com/negotiate?negotiateVersion=1", (req) -> Single.just(new HttpResponse(500, "Internal server error", ""))); MockTransport transport = new MockTransport(); diff --git a/src/SignalR/clients/java/signalr/src/test/java/com/microsoft/signalr/NegotiateResponseTest.java b/src/SignalR/clients/java/signalr/src/test/java/com/microsoft/signalr/NegotiateResponseTest.java index 88175d0ac9..1eaa0a00df 100644 --- a/src/SignalR/clients/java/signalr/src/test/java/com/microsoft/signalr/NegotiateResponseTest.java +++ b/src/SignalR/clients/java/signalr/src/test/java/com/microsoft/signalr/NegotiateResponseTest.java @@ -15,8 +15,9 @@ import com.google.gson.stream.JsonReader; class NegotiateResponseTest { @Test public void VerifyNegotiateResponse() { - String stringNegotiateResponse = "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + - "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}," + + String stringNegotiateResponse = "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\"," + + "\"negotiateVersion\": 99, \"connectionToken\":\"connection-token-value\"," + + "\"availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}," + "{\"transport\":\"ServerSentEvents\",\"transferFormats\":[\"Text\"]}," + "{\"transport\":\"LongPolling\",\"transferFormats\":[\"Text\",\"Binary\"]}]}"; NegotiateResponse negotiateResponse = new NegotiateResponse(new JsonReader(new StringReader(stringNegotiateResponse))); @@ -26,6 +27,8 @@ class NegotiateResponseTest { assertNull(negotiateResponse.getAccessToken()); assertNull(negotiateResponse.getRedirectUrl()); assertEquals("bVOiRPG8-6YiJ6d7ZcTOVQ", negotiateResponse.getConnectionId()); + assertEquals("connection-token-value", negotiateResponse.getConnectionToken()); + assertEquals(99, negotiateResponse.getVersion()); } @Test @@ -56,4 +59,23 @@ class NegotiateResponseTest { NegotiateResponse negotiateResponse = new NegotiateResponse(new JsonReader(new StringReader(stringNegotiateResponse))); assertEquals("bVOiRPG8-6YiJ6d7ZcTOVQ", negotiateResponse.getConnectionId()); } + + @Test + public void NegotiateResponseWithNegotiateVersion() { + String stringNegotiateResponse = "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\"," + + "\"negotiateVersion\": 99}"; + NegotiateResponse negotiateResponse = new NegotiateResponse(new JsonReader(new StringReader(stringNegotiateResponse))); + assertEquals("bVOiRPG8-6YiJ6d7ZcTOVQ", negotiateResponse.getConnectionId()); + assertEquals(99, negotiateResponse.getVersion()); + } + + @Test + public void NegotiateResponseWithConnectionToken() { + String stringNegotiateResponse = "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\"," + + "\"negotiateVersion\": 99, \"connectionToken\":\"connection-token-value\"}"; + NegotiateResponse negotiateResponse = new NegotiateResponse(new JsonReader(new StringReader(stringNegotiateResponse))); + assertEquals("bVOiRPG8-6YiJ6d7ZcTOVQ", negotiateResponse.getConnectionId()); + assertEquals("connection-token-value", negotiateResponse.getConnectionToken()); + assertEquals(99, negotiateResponse.getVersion()); + } } diff --git a/src/SignalR/common/Http.Connections/test/NegotiateProtocolTests.cs b/src/SignalR/common/Http.Connections/test/NegotiateProtocolTests.cs index 00d803ffdd..704f0f4d27 100644 --- a/src/SignalR/common/Http.Connections/test/NegotiateProtocolTests.cs +++ b/src/SignalR/common/Http.Connections/test/NegotiateProtocolTests.cs @@ -18,8 +18,6 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests [InlineData("{\"url\": \"http://foo.com/chat\"}", null, null, "http://foo.com/chat", null, 0, null)] [InlineData("{\"url\": \"http://foo.com/chat\", \"accessToken\": \"token\"}", null, null, "http://foo.com/chat", "token", 0, null)] [InlineData("{\"connectionId\":\"123\",\"availableTransports\":[{\"transport\":\"test\",\"transferFormats\":[]}]}", "123", new[] { "test" }, null, null, 0, null)] - [InlineData("{\"connectionId\":\"123\",\"availableTransports\":[{\"\\u0074ransport\":\"test\",\"transferFormats\":[]}]}", "123", new[] { "test" }, null, null, 0, null)] - [InlineData("{\"negotiateVersion\":123,\"connectionId\":\"123\",\"connectionToken\":\"789\",\"availableTransports\":[{\"\\u0074ransport\":\"test\",\"transferFormats\":[]}]}", "123", new[] { "test" }, null, null, 123, "789")] [InlineData("{\"negotiateVersion\":123,\"negotiateVersion\":321, \"connectionToken\":\"789\",\"connectionId\":\"123\",\"availableTransports\":[]}", "123", new string[0], null, null, 321, "789")] [InlineData("{\"ignore\":123,\"negotiateVersion\":123, \"connectionToken\":\"789\",\"connectionId\":\"123\",\"availableTransports\":[]}", "123", new string[0], null, null, 123, "789")] [InlineData("{\"connectionId\":\"123\",\"availableTransports\":[],\"negotiateVersion\":123, \"connectionToken\":\"789\"}", "123", new string[0], null, null, 123, "789")]