Skip to content

Commit 6dc591e

Browse files
committed
Excluded GraphQLWebSocketMiddleware from exception stack trace if request is not a Web Socket
1 parent 0023760 commit 6dc591e

File tree

3 files changed

+41
-25
lines changed

3 files changed

+41
-25
lines changed

RELEASE_NOTES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@
232232
* Migrated all solutions to SLNX format
233233
* Various performance optimizations and bug fixes
234234

235-
### Unreleased
235+
### 3.1.0 - Unreleased
236236

237237
* Added `TimeOnly` GraphQL type
238+
* Excluded `GraphQLWebSocketMiddleware` from exception stack trace if request not a Web Socket

src/FSharp.Data.GraphQL.Server.AspNetCore/GraphQLWebsocketMiddleware.fs

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ open FSharp.Data.GraphQL.Shared.WebSockets
2525

2626
type GraphQLWebSocketMiddleware<'Root>
2727
(
28-
next : RequestDelegate,
2928
applicationLifetime : IHostApplicationLifetime,
3029
serviceProvider : IServiceProvider,
3130
logger : ILogger<GraphQLWebSocketMiddleware<'Root>>,
@@ -35,7 +34,6 @@ type GraphQLWebSocketMiddleware<'Root>
3534
let options = options.Value
3635
let serializerOptions = options.SerializerOptions
3736
let pingHandler = options.WebsocketOptions.CustomPingHandler
38-
let endpointUrl = PathString options.WebsocketOptions.EndpointUrl
3937
let connectionInitTimeout = options.WebsocketOptions.ConnectionInitTimeout
4038

4139
let serializeServerMessage (jsonSerializerOptions : JsonSerializerOptions) (serverMessage : ServerMessage) = task {
@@ -346,25 +344,29 @@ type GraphQLWebSocketMiddleware<'Root>
346344
return Result.Error <| "{nameof ConnectionInit} timeout"
347345
}
348346

349-
member _.InvokeAsync (ctx : HttpContext) = task {
350-
if not (ctx.Request.Path = endpointUrl) then
351-
do! next.Invoke (ctx)
352-
else if ctx.WebSockets.IsWebSocketRequest then
353-
use! socket = ctx.WebSockets.AcceptWebSocketAsync ("graphql-transport-ws")
354-
let! connectionInitResult = socket |> waitForConnectionInitAndRespondToClient
355-
match connectionInitResult with
356-
| Result.Error errMsg -> logger.LogWarning errMsg
357-
| Ok _ ->
358-
let longRunningCancellationToken =
359-
(CancellationTokenSource
360-
.CreateLinkedTokenSource(ctx.RequestAborted, applicationLifetime.ApplicationStopping)
361-
.Token)
362-
longRunningCancellationToken.Register (fun _ -> (socket |> tryToGracefullyCloseSocketWithDefaultBehavior).Wait ())
363-
|> ignore
364-
try
365-
do! socket |> handleMessages longRunningCancellationToken ctx
366-
with ex ->
367-
logger.LogError (ex, "Cannot handle WebSocket message.")
347+
member _.InvokeAsync (ctx : HttpContext) : Task =
348+
if ctx.WebSockets.IsWebSocketRequest then
349+
task {
350+
use! socket = ctx.WebSockets.AcceptWebSocketAsync ("graphql-transport-ws")
351+
let! connectionInitResult = socket |> waitForConnectionInitAndRespondToClient
352+
match connectionInitResult with
353+
| Result.Error errMsg -> logger.LogWarning errMsg
354+
| Ok _ ->
355+
let longRunningCancellationToken =
356+
(CancellationTokenSource
357+
.CreateLinkedTokenSource(ctx.RequestAborted, applicationLifetime.ApplicationStopping)
358+
.Token)
359+
longRunningCancellationToken.Register (fun _ -> (socket |> tryToGracefullyCloseSocketWithDefaultBehavior).Wait ())
360+
|> ignore
361+
try
362+
do! socket |> handleMessages longRunningCancellationToken ctx
363+
with ex ->
364+
logger.LogError (ex, "Cannot handle WebSocket message.")
365+
}
368366
else
369-
do! next.Invoke (ctx)
370-
}
367+
TypedResults.Problem (
368+
title = "WebSocket connection expected.",
369+
detail = $"'{options.WebsocketOptions.EndpointUrl}' endpoint only accepts WebSocket connections.",
370+
statusCode = StatusCodes.Status400BadRequest
371+
) :> IResult
372+
|> _.ExecuteAsync(ctx)

src/FSharp.Data.GraphQL.Server.AspNetCore/ServiceCollectionExtensions.fs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,5 +329,18 @@ module ApplicationBuilderExtensions =
329329

330330
type IApplicationBuilder with
331331

332+
/// <summary>
333+
/// Registers the GraphQL WebSocket middleware to handle WebSocket connections at the configured endpoint.
334+
/// The middleware will only be applied to requests matching the endpoint path configured in <see cref="GraphQLOptions" />.
335+
/// </summary>
332336
[<Extension; CompiledName "UseWebSocketsForGraphQL">]
333-
member builder.UseWebSocketsForGraphQL<'Root> () = builder.UseMiddleware<GraphQLWebSocketMiddleware<'Root>> ()
337+
member builder.UseWebSocketsForGraphQL<'Root> () =
338+
339+
let options = builder.ApplicationServices.GetRequiredService<IOptions<GraphQLOptions<'Root>>>()
340+
let endpointPath = PathString options.Value.WebsocketOptions.EndpointUrl
341+
342+
builder.UseWhen(
343+
(fun ctx -> ctx.Request.Path = endpointPath),
344+
fun appBuilder ->
345+
appBuilder.UseMiddleware<GraphQLWebSocketMiddleware<'Root>>() |> ignore
346+
)

0 commit comments

Comments
 (0)