Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[question] Would it be possible to make Giraffe.EndpointRouting case-sensitive? #585

Closed
toraritte opened this issue Mar 31, 2024 · 3 comments

Comments

@toraritte
Copy link

I've been obsessing on this question for a while now, so just curious if it could be done (even if it is probably not worth it).

The Endpoint Routing section in the docs states that

several existing [default] routing functions couldn't be ported to Giraffe.EndpointRouting and [ASP.NET Core routing] routes are case-insensitive by default.

but the RouteOptions.LowercaseUrls property in the Microsoft.AspNetCore.Routing namespace is supposed to toggle this behaviour.

Again, my .NET (let alone ASP.NET Core) understanding is limited, but every online search points to the above solution... Thank you for any clarification!

@64J0
Copy link
Member

64J0 commented Apr 2, 2024

Hi @toraritte, thanks for creating this issue, I'll be taking a look at it this week.

@64J0
Copy link
Member

64J0 commented Apr 4, 2024

Hello again @toraritte. I've been looking for the official .NET documentation and other sources on the web, and I did test this option that you mentioned with the EndpointRoutingApp sample from this repository. It didn't work for me. This was the code I was using, if you'd like to play with it (from samples/EndpointRoutingApp):

open System
open Microsoft.AspNetCore
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Hosting
open Microsoft.AspNetCore.Http
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
open Giraffe
open Giraffe.EndpointRouting

let handler1: HttpHandler =
    fun (_: HttpFunc) (ctx: HttpContext) -> ctx.WriteTextAsync "Hello World"

let handler2 (firstName: string, age: int) : HttpHandler =
    fun (_: HttpFunc) (ctx: HttpContext) ->
        sprintf "Hello %s, you are %i years old." firstName age |> ctx.WriteTextAsync

let handler3 (a: string, b: string, c: string, d: int) : HttpHandler =
    fun (_: HttpFunc) (ctx: HttpContext) -> sprintf "Hello %s %s %s %i" a b c d |> ctx.WriteTextAsync

let endpoints =
    [ subRoute
          "/foo"
          [ GET
                [ route "/bar" (text "aloha!")
                  route "/Bar" (text "Aloha!")
                  route "/BAR" (text "ALOHA!") ] ]
      GET
          [ route "/" (text "Hello World")
            routef "/%s/%i" handler2
            routef "/%s/%s/%s/%i" handler3 ]
      GET_HEAD
          [ route "/foo" (text "Bar")
            route "/x" (text "y")
            route "/abc" (text "def")
            route "/123" (text "456") ]
      // Not specifying a http verb means it will listen to all verbs
      subRoute "/sub" [ route "/test" handler1 ] ]

let notFoundHandler = "Not Found" |> text |> RequestErrors.notFound

let configureApp (appBuilder: IApplicationBuilder) =
    appBuilder.UseRouting().UseGiraffe(endpoints).UseGiraffe(notFoundHandler)

let configureServices (services: IServiceCollection) =
    services.AddRouting(fun ctx -> ctx.LowercaseUrls <- false).AddGiraffe()
    |> ignore

[<EntryPoint>]
let main args =
    let builder = WebApplication.CreateBuilder(args)
    configureServices builder.Services

    let app = builder.Build()

    if app.Environment.IsDevelopment() then
        app.UseDeveloperExceptionPage() |> ignore

    configureApp app
    app.Run()

    0

And was testing with:

curl localhost:5000/foo/bar

curl localhost:5000/foo/Bar

curl localhost:5000/foo/BAR

Any of these returned this exception:

fail: Microsoft.AspNetCore.Server.Kestrel[13]
      Connection id "0HN2KSIQ7O89J", Request id "0HN2KSIQ7O89J:00000001": An unhandled exception was thrown by the application.
      Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints. Matches: 
      
      HTTP: GET /foo/bar
      HTTP: GET /foo/Bar
      HTTP: GET /foo/BAR
         at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(Span`1 candidateState)
         at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ProcessFinalCandidates(HttpContext httpContext, Span`1 candidateState)
         at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.Select(HttpContext httpContext, Span`1 candidateState)
         at Microsoft.AspNetCore.Routing.Matching.DfaMatcher.MatchAsync(HttpContext httpContext)
         at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
         at Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Watch.BrowserRefresh.BrowserRefreshMiddleware.InvokeAsync(HttpContext context)
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

@toraritte
Copy link
Author

Thank you for taking the time looking into this and also for posting the sample code! I can't even name a valid use case for case-sensitive URL paths, but had to ask..:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants