Set X-Requested-With on all requests (#1848)
This commit is contained in:
parent
80f87e7730
commit
32b4d5cc6c
|
|
@ -428,6 +428,10 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
httpClient.DefaultRequestHeaders.Remove("X-Requested-With");
|
||||||
|
// Tell auth middleware to 401 instead of redirecting
|
||||||
|
httpClient.DefaultRequestHeaders.Add("X-Requested-With", "XMLHttpRequest");
|
||||||
|
|
||||||
return httpClient;
|
return httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,8 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
|
||||||
_closeTimeout = httpOptions.CloseTimeout;
|
_closeTimeout = httpOptions.CloseTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_webSocket.Options.SetRequestHeader("X-Requested-With", "XMLHttpRequest");
|
||||||
|
|
||||||
_logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<WebSocketsTransport>();
|
_logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<WebSocketsTransport>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Connections;
|
||||||
using Microsoft.AspNetCore.Http.Connections;
|
using Microsoft.AspNetCore.Http.Connections;
|
||||||
using Microsoft.AspNetCore.Http.Connections.Client;
|
using Microsoft.AspNetCore.Http.Connections.Client;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
|
@ -64,7 +63,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
||||||
o.Url = url;
|
o.Url = url;
|
||||||
o.Transport = transportType;
|
o.Transport = transportType;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (configureHttpConnection != null)
|
if (configureHttpConnection != null)
|
||||||
{
|
{
|
||||||
hubConnectionBuilder.Services.Configure(configureHttpConnection);
|
hubConnectionBuilder.Services.Configure(configureHttpConnection);
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,46 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
||||||
Assert.True(requestsExecuted);
|
Assert.True(requestsExecuted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(HttpTransportType.LongPolling)]
|
||||||
|
[InlineData(HttpTransportType.ServerSentEvents)]
|
||||||
|
public async Task HttpConnectionSetsRequestedWithOnAllRequests(HttpTransportType transportType)
|
||||||
|
{
|
||||||
|
var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false);
|
||||||
|
var requestsExecuted = false;
|
||||||
|
|
||||||
|
testHttpHandler.OnRequest((request, next, token) =>
|
||||||
|
{
|
||||||
|
return Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent));
|
||||||
|
});
|
||||||
|
|
||||||
|
testHttpHandler.OnNegotiate((_, cancellationToken) =>
|
||||||
|
{
|
||||||
|
return ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent());
|
||||||
|
});
|
||||||
|
|
||||||
|
testHttpHandler.OnRequest(async (request, next, token) =>
|
||||||
|
{
|
||||||
|
var requestedWithHeader = request.Headers.GetValues("X-Requested-With");
|
||||||
|
var requestedWithValue = Assert.Single(requestedWithHeader);
|
||||||
|
Assert.Equal("XMLHttpRequest", requestedWithValue);
|
||||||
|
|
||||||
|
requestsExecuted = true;
|
||||||
|
|
||||||
|
return await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
await WithConnectionAsync(
|
||||||
|
CreateConnection(testHttpHandler, transportType: transportType),
|
||||||
|
async (connection) =>
|
||||||
|
{
|
||||||
|
await connection.StartAsync(TransferFormat.Text).OrTimeout();
|
||||||
|
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello World"));
|
||||||
|
});
|
||||||
|
// Fail safe in case the code is modified and some requests don't execute as a result
|
||||||
|
Assert.True(requestsExecuted);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CanReceiveData()
|
public async Task CanReceiveData()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Connections;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
public class AuthConnectionHandler : ConnectionHandler
|
||||||
|
{
|
||||||
|
public override async Task OnConnectedAsync(ConnectionContext connection)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var result = await connection.Transport.Input.ReadAsync();
|
||||||
|
var buffer = result.Buffer;
|
||||||
|
|
||||||
|
if (!buffer.IsEmpty)
|
||||||
|
{
|
||||||
|
await connection.Transport.Output.WriteAsync(buffer.ToArray());
|
||||||
|
}
|
||||||
|
else if (result.IsCompleted)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.Transport.Input.AdvanceTo(buffer.End);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -302,6 +302,69 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[WebSocketsSupportedCondition]
|
||||||
|
public async Task UnauthorizedWebSocketsConnectionDoesNotConnect()
|
||||||
|
{
|
||||||
|
using (StartLog(out var loggerFactory, LogLevel.Trace))
|
||||||
|
{
|
||||||
|
var logger = loggerFactory.CreateLogger<EndToEndTests>();
|
||||||
|
|
||||||
|
var url = _serverFixture.Url + "/auth";
|
||||||
|
var connection = new HttpConnection(new Uri(url), HttpTransportType.WebSockets, loggerFactory);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
logger.LogInformation("Starting connection to {url}", url);
|
||||||
|
await connection.StartAsync(TransferFormat.Binary).OrTimeout();
|
||||||
|
Assert.True(false);
|
||||||
|
}
|
||||||
|
catch (WebSocketException) { }
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.LogInformation(ex, "Test threw exception");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
logger.LogInformation("Disposing Connection");
|
||||||
|
await connection.DisposeAsync().OrTimeout();
|
||||||
|
logger.LogInformation("Disposed Connection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(HttpTransportType.LongPolling)]
|
||||||
|
[InlineData(HttpTransportType.ServerSentEvents)]
|
||||||
|
public async Task UnauthorizedConnectionDoesNotConnect(HttpTransportType transportType)
|
||||||
|
{
|
||||||
|
using (StartLog(out var loggerFactory, LogLevel.Trace, testName: $"{nameof(UnauthorizedConnectionDoesNotConnect)}_{transportType}"))
|
||||||
|
{
|
||||||
|
var logger = loggerFactory.CreateLogger<EndToEndTests>();
|
||||||
|
|
||||||
|
var url = _serverFixture.Url + "/auth";
|
||||||
|
var connection = new HttpConnection(new Uri(url), transportType, loggerFactory);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
logger.LogInformation("Starting connection to {url}", url);
|
||||||
|
await connection.StartAsync(TransferFormat.Binary).OrTimeout();
|
||||||
|
Assert.True(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Assert.Equal("Response status code does not indicate success: 401 (Unauthorized).", ex.Message);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
logger.LogInformation("Disposing Connection");
|
||||||
|
await connection.DisposeAsync().OrTimeout();
|
||||||
|
logger.LogInformation("Disposed Connection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
[WebSocketsSupportedCondition]
|
[WebSocketsSupportedCondition]
|
||||||
public async Task ServerClosesConnectionWithErrorIfHubCannotBeCreated_WebSocket()
|
public async Task ServerClosesConnectionWithErrorIfHubCannotBeCreated_WebSocket()
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="$(MicrosoftAspNetCoreHttpAbstractionsPackageVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="$(MicrosoftAspNetCoreHttpAbstractionsPackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Server.IntegrationTesting" Version="$(MicrosoftAspNetCoreServerIntegrationTestingPackageVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.Server.IntegrationTesting" Version="$(MicrosoftAspNetCoreServerIntegrationTestingPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="$(MicrosoftAspNetCoreAuthorizationPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="$(MicrosoftAspNetCoreAuthenticationCookiesPackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion)" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsDependencyInjectionPackageVersion)" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsDependencyInjectionPackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -16,6 +18,12 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
{
|
{
|
||||||
options.EnableDetailedErrors = true;
|
options.EnableDetailedErrors = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||||
|
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||||
|
}).AddCookie();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||||
|
|
@ -25,6 +33,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
routes.MapConnectionHandler<EchoConnectionHandler>("/echo");
|
routes.MapConnectionHandler<EchoConnectionHandler>("/echo");
|
||||||
routes.MapConnectionHandler<WriteThenCloseConnectionHandler>("/echoAndClose");
|
routes.MapConnectionHandler<WriteThenCloseConnectionHandler>("/echoAndClose");
|
||||||
routes.MapConnectionHandler<HttpHeaderConnectionHandler>("/httpheader");
|
routes.MapConnectionHandler<HttpHeaderConnectionHandler>("/httpheader");
|
||||||
|
routes.MapConnectionHandler<AuthConnectionHandler>("/auth");
|
||||||
});
|
});
|
||||||
|
|
||||||
app.UseSignalR(routes =>
|
app.UseSignalR(routes =>
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,30 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[WebSocketsSupportedCondition]
|
||||||
|
public async Task WebSocketsTransportSendsXRequestedWithHeader()
|
||||||
|
{
|
||||||
|
using (StartLog(out var loggerFactory))
|
||||||
|
{
|
||||||
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
var webSocketsTransport = new WebSocketsTransport(httpOptions: null, loggerFactory: loggerFactory);
|
||||||
|
await webSocketsTransport.StartAsync(new Uri(_serverFixture.WebSocketsUrl + "/httpheader"), pair.Application,
|
||||||
|
TransferFormat.Binary, connection: Mock.Of<IConnection>()).OrTimeout();
|
||||||
|
|
||||||
|
await pair.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("X-Requested-With"));
|
||||||
|
|
||||||
|
// The HTTP header endpoint closes the connection immediately after sending response which should stop the transport
|
||||||
|
await webSocketsTransport.Running.OrTimeout();
|
||||||
|
|
||||||
|
Assert.True(pair.Transport.Input.TryRead(out var result));
|
||||||
|
|
||||||
|
string headerValue = Encoding.UTF8.GetString(result.Buffer.ToArray());
|
||||||
|
|
||||||
|
Assert.Equal("XMLHttpRequest", headerValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
[WebSocketsSupportedCondition]
|
[WebSocketsSupportedCondition]
|
||||||
public async Task WebSocketsTransportStopsWhenConnectionChannelClosed()
|
public async Task WebSocketsTransportStopsWhenConnectionChannelClosed()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue