Skip to content

Commit e4fdd4a

Browse files
[SignalR] Copy cookies from negotiate to WebSockets (#24572) (#26566)
1 parent ee80495 commit e4fdd4a

File tree

4 files changed

+60
-5
lines changed

4 files changed

+60
-5
lines changed

src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,34 @@ public async Task WebSocketOptionsAreApplied()
15141514
}
15151515
}
15161516

1517+
[ConditionalFact]
1518+
[WebSocketsSupportedCondition]
1519+
public async Task CookiesFromNegotiateAreAppliedToWebSockets()
1520+
{
1521+
using (StartServer<Startup>(out var server))
1522+
{
1523+
var hubConnection = new HubConnectionBuilder()
1524+
.WithLoggerFactory(LoggerFactory)
1525+
.WithUrl(server.Url + "/default", HttpTransportType.WebSockets)
1526+
.Build();
1527+
try
1528+
{
1529+
await hubConnection.StartAsync().OrTimeout();
1530+
var cookieValue = await hubConnection.InvokeAsync<string>(nameof(TestHub.GetCookieValue), "fromNegotiate").OrTimeout();
1531+
Assert.Equal("a value", cookieValue);
1532+
}
1533+
catch (Exception ex)
1534+
{
1535+
LoggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "{ExceptionType} from test", ex.GetType().FullName);
1536+
throw;
1537+
}
1538+
finally
1539+
{
1540+
await hubConnection.DisposeAsync().OrTimeout();
1541+
}
1542+
}
1543+
}
1544+
15171545
[Fact(Skip = "Returning object from Hub method not support by System.Text.Json yet")]
15181546
public async Task CheckHttpConnectionFeatures()
15191547
{

src/SignalR/clients/csharp/Client/test/FunctionalTests/Startup.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ public void Configure(IApplicationBuilder app)
5858
app.UseAuthentication();
5959
app.UseAuthorization();
6060

61+
app.Use(next =>
62+
{
63+
return context =>
64+
{
65+
if (context.Request.Path.Value.EndsWith("/negotiate"))
66+
{
67+
context.Response.Cookies.Append("fromNegotiate", "a value");
68+
}
69+
return next(context);
70+
};
71+
});
72+
6173
app.UseEndpoints(endpoints =>
6274
{
6375
endpoints.MapHub<TestHub>("/default");

src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnection.Log.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ private static class Log
6969
private static readonly Action<ILogger, Exception> _serverSentEventsNotSupportedByBrowser =
7070
LoggerMessage.Define(LogLevel.Debug, new EventId(19, "ServerSentEventsNotSupportedByBrowser"), "Skipping ServerSentEvents because they are not supported by the browser.");
7171

72+
private static readonly Action<ILogger, Exception> _cookiesNotSupported =
73+
LoggerMessage.Define(LogLevel.Trace, new EventId(20, "CookiesNotSupported"), "Cookies are not supported on this platform.");
74+
7275
public static void Starting(ILogger logger)
7376
{
7477
_starting(logger, null);
@@ -175,6 +178,11 @@ public static void ServerSentEventsNotSupportedByBrowser(ILogger logger)
175178
{
176179
_serverSentEventsNotSupportedByBrowser(logger, null);
177180
}
181+
182+
public static void CookiesNotSupported(ILogger logger)
183+
{
184+
_cookiesNotSupported(logger, null);
185+
}
178186
}
179187
}
180188
}

src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnection.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@ public HttpConnection(HttpConnectionOptions httpConnectionOptions, ILoggerFactor
153153

154154
_isRunningInBrowser = Utils.IsRunningInBrowser();
155155

156-
157156
if (httpConnectionOptions.Transports == HttpTransportType.ServerSentEvents && _isRunningInBrowser)
158157
{
159158
throw new ArgumentException("ServerSentEvents can not be the only transport specified when running in the browser.", nameof(httpConnectionOptions));
@@ -534,13 +533,21 @@ private HttpClient CreateHttpClient()
534533
httpClientHandler.Proxy = _httpConnectionOptions.Proxy;
535534
}
536535

537-
// Only access HttpClientHandler.ClientCertificates and HttpClientHandler.CookieContainer
538-
// if the user has configured those options
539-
// Some variants of Mono do not support client certs or cookies and will throw NotImplementedException
540-
if (_httpConnectionOptions.Cookies.Count > 0)
536+
try
541537
{
538+
// On supported platforms, we need to pass the cookie container to the http client
539+
// so that we can capture any cookies from the negotiate response and give them to WebSockets.
542540
httpClientHandler.CookieContainer = _httpConnectionOptions.Cookies;
543541
}
542+
// Some variants of Mono do not support client certs or cookies and will throw NotImplementedException or NotSupportedException
543+
// Also WASM doesn't support some settings in the browser
544+
catch (Exception ex) when (ex is NotSupportedException || ex is NotImplementedException)
545+
{
546+
Log.CookiesNotSupported(_logger);
547+
}
548+
549+
// Only access HttpClientHandler.ClientCertificates
550+
// if the user has configured those options
544551
// https://github.com/aspnet/SignalR/issues/2232
545552
var clientCertificates = _httpConnectionOptions.ClientCertificates;
546553
if (clientCertificates?.Count > 0)

0 commit comments

Comments
 (0)