Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -309,11 +309,12 @@ public StreamChatLowLevelClient(AuthCredentials authCredentials, IWebsocketClien

_logs.Prefix = "[Stream Chat] ";

_requestUriFactory = new RequestUriFactory(authProvider: this, connectionProvider: this, _serializer);
var streamClientHeader = BuildStreamClientHeader(applicationInfo);
_requestUriFactory = new RequestUriFactory(authProvider: this, connectionProvider: this, _serializer,
streamClientHeader);

_httpClient.AddDefaultCustomHeader("stream-auth-type", DefaultStreamAuthType);
var header = BuildStreamClientHeader(applicationInfo);
_httpClient.AddDefaultCustomHeader("X-Stream-Client", header);
_httpClient.AddDefaultCustomHeader("X-Stream-Client", streamClientHeader);

_websocketClient.ConnectionFailed += OnWebsocketsConnectionFailed;
_websocketClient.Disconnected += OnWebsocketDisconnected;
Expand Down
5 changes: 4 additions & 1 deletion Assets/Plugins/StreamChat/Core/Web/RequestUriFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ namespace StreamChat.Core.Web
internal class RequestUriFactory : IRequestUriFactory
{
public RequestUriFactory(IAuthProvider authProvider, IStreamChatLowLevelClient connectionProvider,
ISerializer serializer)
ISerializer serializer, string streamClientHeader)
{
_authProvider = authProvider ?? throw new ArgumentNullException(nameof(authProvider));
_connectionProvider = connectionProvider ?? throw new ArgumentNullException(nameof(connectionProvider));
_serializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
_streamClientHeader = streamClientHeader ?? throw new ArgumentNullException(nameof(streamClientHeader));
}

public Uri CreateConnectionUri()
Expand All @@ -43,6 +44,7 @@ public Uri CreateConnectionUri()
{ "api_key", _authProvider.ApiKey },
{ "authorization", _authProvider.UserToken },
{ "stream-auth-type", _authProvider.StreamAuthType },
{ "X-Stream-Client", Uri.EscapeDataString(_streamClientHeader) },
};

var uriBuilder = new UriBuilder(_connectionProvider.ServerUri)
Expand All @@ -69,6 +71,7 @@ public Uri CreateEndpointUri(string endpoint, Dictionary<string, string> paramet
private readonly IAuthProvider _authProvider;
private readonly ISerializer _serializer;
private readonly IStreamChatLowLevelClient _connectionProvider;
private readonly string _streamClientHeader;

private Dictionary<string, string> GetDefaultParameters() =>
new Dictionary<string, string>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#if STREAM_TESTS_ENABLED
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Threading.Tasks;
using NSubstitute;
Expand Down Expand Up @@ -156,6 +157,76 @@ T GetParam<T>(int indexToTestNull) where T : class
}
}

[Test]
public void when_stream_client_created_expect_http_tracking_headers()
{
var mockHttpClient = Substitute.For<IHttpClient>();
var mockApplicationInfo = Substitute.For<IApplicationInfo>();
ConfigureApplicationInfo(mockApplicationInfo);

var client = new StreamChatLowLevelClient(_authCredentials, _mockWebsocketClient, mockHttpClient,
_mockSerializer, _mockTimeService, _mockNetworkMonitor, mockApplicationInfo, _mockLogs,
_mockStreamClientConfig);
_resourcesToDispose.Add(client);

var expectedHeader = BuildExpectedStreamClientHeader(mockApplicationInfo);

mockHttpClient.Received().AddDefaultCustomHeader("stream-auth-type", "jwt");
mockHttpClient.Received().AddDefaultCustomHeader("X-Stream-Client", expectedHeader);
}

[Test]
public void when_stream_client_connects_expect_websocket_connect_url_includes_client_tracking()
{
var mockWebsocketClient = Substitute.For<IWebsocketClient>();
var mockApplicationInfo = Substitute.For<IApplicationInfo>();
ConfigureApplicationInfo(mockApplicationInfo);

_mockSerializer.Serialize(Arg.Any<object>()).Returns("{\"user_id\":\"user123\"}");

var client = new StreamChatLowLevelClient(_authCredentials, mockWebsocketClient, _mockHttpClient,
_mockSerializer, _mockTimeService, _mockNetworkMonitor, mockApplicationInfo, _mockLogs,
_mockStreamClientConfig);
_resourcesToDispose.Add(client);

var expectedHeader = BuildExpectedStreamClientHeader(mockApplicationInfo);
Uri capturedUri = null;
mockWebsocketClient.ConnectAsync(Arg.Do<Uri>(uri => capturedUri = uri)).Returns(Task.CompletedTask);

client.Connect();

Assert.NotNull(capturedUri);
Assert.That(capturedUri.Query, Does.Contain("X-Stream-Client="));

var queryParam = capturedUri.Query.TrimStart('?')
.Split('&')
.First(p => p.StartsWith("X-Stream-Client="));
var actualHeader = Uri.UnescapeDataString(queryParam.Substring("X-Stream-Client=".Length));

Assert.AreEqual(expectedHeader, actualHeader);
}

private static void ConfigureApplicationInfo(IApplicationInfo applicationInfo)
{
applicationInfo.OperatingSystem.Returns("Windows 10");
applicationInfo.Platform.Returns("StandaloneWindows64");
applicationInfo.Engine.Returns("Unity");
applicationInfo.EngineVersion.Returns("2022.3.0f1");
applicationInfo.ScreenSize.Returns("1920x1080");
applicationInfo.MemorySize.Returns(8192);
applicationInfo.GraphicsMemorySize.Returns(4096);
}

private static string BuildExpectedStreamClientHeader(IApplicationInfo applicationInfo)
=> $"stream-chat-unity-client-{StreamChatLowLevelClient.SDKVersion}|" +
$"os={applicationInfo.OperatingSystem}|" +
$"platform={applicationInfo.Platform}|" +
$"engine={applicationInfo.Engine}|" +
$"engine_version={applicationInfo.EngineVersion}|" +
$"screen_size={applicationInfo.ScreenSize}|" +
$"memory_size={applicationInfo.MemorySize}|" +
$"graphics_memory_size={applicationInfo.GraphicsMemorySize}";

[Test]
public void when_stream_client_created_expect_disconnected_state()
{
Expand Down
Loading