From e0f95cfa6feec402ea34a605965f356720006513 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Wed, 21 Aug 2019 16:15:39 -0500 Subject: [PATCH] Set the user agent header in the Java client (#13168) --- src/SignalR/clients/java/signalr/build.gradle | 24 +++++++ .../com/microsoft/signalr/HubConnection.java | 1 + .../microsoft/signalr/UserAgentHelper.java | 54 ++++++++++++++ .../java/com/microsoft/signalr/Version.java | 11 +++ .../microsoft/signalr/HubConnectionTest.java | 71 +++++++++++++++++++ .../com/microsoft/signalr/UserAgentTest.java | 54 ++++++++++++++ 6 files changed, 215 insertions(+) create mode 100644 src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/UserAgentHelper.java create mode 100644 src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/Version.java create mode 100644 src/SignalR/clients/java/signalr/src/test/java/com/microsoft/signalr/UserAgentTest.java diff --git a/src/SignalR/clients/java/signalr/build.gradle b/src/SignalR/clients/java/signalr/build.gradle index 61b170a40d..8feab7b9b7 100644 --- a/src/SignalR/clients/java/signalr/build.gradle +++ b/src/SignalR/clients/java/signalr/build.gradle @@ -108,3 +108,27 @@ task generatePOM { } task createPackage(dependsOn: [jar,sourceJar,javadocJar,generatePOM]) + +task generateVersionClass { + inputs.property "version", project.version + outputs.dir "$buildDir/generated" + doFirst { + def versionFile = file("$buildDir/../src/main/java/com/microsoft/signalr/Version.java") + versionFile.parentFile.mkdirs() + versionFile.text = + """ +// 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 Version { + public static String getDetailedVersion() { + return "$project.version"; + } +} +""" + } +} + +compileJava.dependsOn generateVersionClass 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..96ecd142c5 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 @@ -327,6 +327,7 @@ public class HubConnection { handshakeResponseSubject = CompletableSubject.create(); handshakeReceived = false; CompletableSubject tokenCompletable = CompletableSubject.create(); + localHeaders.put(UserAgentHelper.getUserAgentName(), UserAgentHelper.createUserAgentString()); if (headers != null) { this.localHeaders.putAll(headers); } diff --git a/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/UserAgentHelper.java b/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/UserAgentHelper.java new file mode 100644 index 0000000000..988da567f4 --- /dev/null +++ b/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/UserAgentHelper.java @@ -0,0 +1,54 @@ +// 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; + +public class UserAgentHelper { + + private final static String USER_AGENT = "User-Agent"; + + public static String getUserAgentName() { + return USER_AGENT; + } + + public static String createUserAgentString() { + StringBuilder agentBuilder = new StringBuilder("Microsoft SignalR/"); + + // Parsing version numbers + String detailedVersion = Version.getDetailedVersion(); + agentBuilder.append(getVersion(detailedVersion)); + agentBuilder.append("; ("); + agentBuilder.append(detailedVersion); + agentBuilder.append("; "); + + // Getting the OS name + agentBuilder.append(getOS()); + agentBuilder.append("; Java; "); + + // Vendor and Version + agentBuilder.append(getJavaVersion()); + agentBuilder.append("; "); + agentBuilder.append(getJavaVendor()); + agentBuilder.append(")"); + + return agentBuilder.toString(); + } + + static String getVersion(String detailedVersion) { + // Getting the index of the second . so we can return just the major and minor version. + int shortVersionIndex = detailedVersion.indexOf(".", detailedVersion.indexOf(".") + 1); + return detailedVersion.substring(0, shortVersionIndex); + } + + static String getJavaVendor() { + return System.getProperty("java.vendor"); + } + + static String getJavaVersion() { + return System.getProperty("java.version"); + } + + static String getOS() { + return System.getProperty("os.name"); + } +} diff --git a/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/Version.java b/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/Version.java new file mode 100644 index 0000000000..4c73a498f6 --- /dev/null +++ b/src/SignalR/clients/java/signalr/src/main/java/com/microsoft/signalr/Version.java @@ -0,0 +1,11 @@ + +// 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 Version { + public static String getDetailedVersion() { + return "99.99.99-dev"; + } +} 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..051b5fed83 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 @@ -2185,6 +2185,77 @@ class HubConnectionTest { } } + @Test + public void userAgentHeaderIsSet() { + AtomicReference header = new AtomicReference<>(); + TestHttpClient client = new TestHttpClient() + .on("POST", "http://example.com/negotiate", + (req) -> { + header.set(req.getHeaders().get("User-Agent")); + return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}")); + }); + + MockTransport transport = new MockTransport(); + HubConnection hubConnection = HubConnectionBuilder.create("http://example.com") + .withTransportImplementation(transport) + .withHttpClient(client) + .build(); + + hubConnection.start().timeout(1, TimeUnit.SECONDS).blockingAwait(); + assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); + hubConnection.stop(); + + assertTrue(header.get().startsWith("Microsoft SignalR/")); + } + + @Test + public void userAgentHeaderCanBeOverwritten() { + AtomicReference header = new AtomicReference<>(); + TestHttpClient client = new TestHttpClient() + .on("POST", "http://example.com/negotiate", + (req) -> { + header.set(req.getHeaders().get("User-Agent")); + return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}")); + }); + + MockTransport transport = new MockTransport(); + HubConnection hubConnection = HubConnectionBuilder.create("http://example.com") + .withTransportImplementation(transport) + .withHttpClient(client) + .withHeader("User-Agent", "Updated Value") + .build(); + + hubConnection.start().timeout(1, TimeUnit.SECONDS).blockingAwait(); + assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); + hubConnection.stop(); + assertEquals("Updated Value", header.get()); + } + + @Test + public void userAgentCanBeCleared() { + AtomicReference header = new AtomicReference<>(); + TestHttpClient client = new TestHttpClient() + .on("POST", "http://example.com/negotiate", + (req) -> { + header.set(req.getHeaders().get("User-Agent")); + return Single.just(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}")); + }); + + MockTransport transport = new MockTransport(); + HubConnection hubConnection = HubConnectionBuilder.create("http://example.com") + .withTransportImplementation(transport) + .withHttpClient(client) + .withHeader("User-Agent", "") + .build(); + + hubConnection.start().timeout(1, TimeUnit.SECONDS).blockingAwait(); + assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); + hubConnection.stop(); + assertEquals("", header.get()); + } @Test public void headersAreSetAndSentThroughBuilder() { AtomicReference header = new AtomicReference<>(); diff --git a/src/SignalR/clients/java/signalr/src/test/java/com/microsoft/signalr/UserAgentTest.java b/src/SignalR/clients/java/signalr/src/test/java/com/microsoft/signalr/UserAgentTest.java new file mode 100644 index 0000000000..59715223b9 --- /dev/null +++ b/src/SignalR/clients/java/signalr/src/test/java/com/microsoft/signalr/UserAgentTest.java @@ -0,0 +1,54 @@ +// 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; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class UserAgentTest { + + private static Stream Versions() { + return Stream.of( + Arguments.of("1.0.0", "1.0"), + Arguments.of("3.1.4-preview9-12345", "3.1"), + Arguments.of("3.1.4-preview9-12345-extrastuff", "3.1"), + Arguments.of("99.99.99-dev", "99.99")); + } + + @ParameterizedTest + @MethodSource("Versions") + public void getVersionFromDetailedVersion(String detailedVersion, String version) { + assertEquals(version, UserAgentHelper.getVersion(detailedVersion)); + } + + @Test + public void verifyJavaVendor(){ + assertEquals(System.getProperty("java.vendor"), UserAgentHelper.getJavaVendor()); + } + + @Test + public void verifyJavaVersion(){ + assertEquals(System.getProperty("java.version"), UserAgentHelper.getJavaVersion()); + } + + @Test + public void checkUserAgentString(){ + String userAgent = UserAgentHelper.createUserAgentString(); + assertNotNull(userAgent); + + String detailedVersion = Version.getDetailedVersion(); + String handMadeUserAgent = "Microsoft SignalR/" + UserAgentHelper.getVersion(detailedVersion) + + "; (" + detailedVersion + "; " + UserAgentHelper.getOS() + "; Java; " + + UserAgentHelper.getJavaVersion() + "; " + UserAgentHelper.getJavaVendor() + ")"; + + assertEquals(handMadeUserAgent, userAgent); + } +}