@@ -531,18 +531,89 @@ private void StartListener()
531531 return ;
532532 }
533533
534+ CallbackRoutes selectedRoute = null ;
535+ bool selectedRouteHasAuth = false ;
536+ string multipleCallback = null ;
537+ bool hasAuthRoutes = false ;
538+ string basicAuthNoCred = null ;
539+ bool authFailed = false ;
540+
534541 // Variables used only within the "for". They are here for performance reasons
535542 bool mustAuthenticate ;
536543 bool isAuthOk ;
537- CallbackRoutes selectedRoute = null ;
538- string multipleCallback = null ;
539544
540545 foreach ( CallbackRoutes route in _callbackRoutes )
541546 {
542547 if ( ! IsRouteMatch ( route , context . Request . HttpMethod , context . Request . RawUrl ) )
543548 {
544549 continue ;
545550 }
551+
552+ // Check auth first
553+ mustAuthenticate = route . Authentication != null && route . Authentication . AuthenticationType != AuthenticationType . None ;
554+ if ( mustAuthenticate )
555+ {
556+ hasAuthRoutes = true ;
557+ if ( route . Authentication . AuthenticationType == AuthenticationType . Basic )
558+ {
559+ var credReq = context . Request . Credentials ;
560+ if ( credReq is null )
561+ {
562+ if ( basicAuthNoCred is null )
563+ {
564+ basicAuthNoCred = route . Route ;
565+ }
566+
567+ continue ;
568+ }
569+
570+ var credSite = route . Authentication . Credentials ?? Credential ;
571+
572+ isAuthOk = credSite != null
573+ && ( credSite . UserName == credReq . UserName )
574+ && ( credSite . Password == credReq . Password ) ;
575+ }
576+ else if ( route . Authentication . AuthenticationType == AuthenticationType . ApiKey )
577+ {
578+ var apikeyReq = GetApiKeyFromHeaders ( context . Request . Headers ) ;
579+ if ( apikeyReq is null )
580+ {
581+ continue ;
582+ }
583+
584+ var apikeySite = route . Authentication . ApiKey ?? ApiKey ;
585+
586+ isAuthOk = apikeyReq == apikeySite ;
587+ }
588+ else
589+ {
590+ isAuthOk = false ;
591+ }
592+
593+ if ( isAuthOk )
594+ {
595+ // This route can be used and has precedence over non-authenticated routes
596+ if ( ! selectedRouteHasAuth )
597+ {
598+ selectedRoute = null ;
599+ multipleCallback = null ;
600+ }
601+
602+ selectedRouteHasAuth = true ;
603+ }
604+ else
605+ {
606+ authFailed = true ;
607+ continue ;
608+ }
609+ }
610+ else if ( selectedRouteHasAuth || authFailed )
611+ {
612+ // The selected route has authentication and/or a route exists with failed authentication.
613+ // Those have precedence over non-authenticated routes
614+ continue ;
615+ }
616+
546617 if ( selectedRoute is null )
547618 {
548619 selectedRoute = route ;
@@ -554,17 +625,21 @@ private void StartListener()
554625 }
555626 }
556627
557- if ( multipleCallback is not null )
558- {
559- multipleCallback += "." ;
560- context . Response . StatusCode = ( int ) HttpStatusCode . InternalServerError ;
561- OutPutStream ( context . Response , multipleCallback ) ;
562628
563- HandleContextResponse ( context ) ;
564- }
565- else if ( selectedRoute is null )
629+ if ( selectedRoute is null )
566630 {
567- if ( CommandReceived != null )
631+ if ( hasAuthRoutes )
632+ {
633+ if ( ! authFailed && basicAuthNoCred is not null )
634+ {
635+ context . Response . Headers . Add ( "WWW-Authenticate" ,
636+ $ "Basic realm=\" Access to { basicAuthNoCred } \" ") ;
637+ }
638+
639+ context . Response . StatusCode = ( int ) HttpStatusCode . Unauthorized ;
640+ context . Response . ContentLength64 = 0 ;
641+ }
642+ else if ( CommandReceived != null )
568643 {
569644 // Starting a new thread to be able to handle a new request in parallel
570645 CommandReceived . Invoke ( this , new WebServerEventArgs ( context ) ) ;
@@ -574,55 +649,19 @@ private void StartListener()
574649 context . Response . StatusCode = ( int ) HttpStatusCode . NotFound ;
575650 context . Response . ContentLength64 = 0 ;
576651 }
577-
578- HandleContextResponse ( context ) ;
652+ }
653+ else if ( multipleCallback is not null )
654+ {
655+ multipleCallback += "." ;
656+ context . Response . StatusCode = ( int ) HttpStatusCode . InternalServerError ;
657+ OutPutStream ( context . Response , multipleCallback ) ;
579658 }
580659 else
581660 {
582- // Check auth first
583- mustAuthenticate = selectedRoute . Authentication != null && selectedRoute . Authentication . AuthenticationType != AuthenticationType . None ;
584- isAuthOk = ! mustAuthenticate ;
585-
586- if ( mustAuthenticate )
587- {
588- if ( selectedRoute . Authentication . AuthenticationType == AuthenticationType . Basic )
589- {
590- var credSite = selectedRoute . Authentication . Credentials ?? Credential ;
591- var credReq = context . Request . Credentials ;
592-
593- isAuthOk = credReq != null && credSite != null
594- && ( credSite . UserName == credReq . UserName )
595- && ( credSite . Password == credReq . Password ) ;
596- }
597- else if ( selectedRoute . Authentication . AuthenticationType == AuthenticationType . ApiKey )
598- {
599- var apikeySite = selectedRoute . Authentication . ApiKey ?? ApiKey ;
600- var apikeyReq = GetApiKeyFromHeaders ( context . Request . Headers ) ;
601-
602- isAuthOk = apikeyReq != null
603- && apikeyReq == apikeySite ;
604- }
605- }
606-
607- if ( ! isAuthOk )
608- {
609- if ( selectedRoute . Authentication != null &&
610- selectedRoute . Authentication . AuthenticationType == AuthenticationType . Basic )
611- {
612- context . Response . Headers . Add ( "WWW-Authenticate" ,
613- $ "Basic realm=\" Access to { selectedRoute . Route } \" ") ;
614- }
615-
616- context . Response . StatusCode = ( int ) HttpStatusCode . Unauthorized ;
617- context . Response . ContentLength64 = 0 ;
618-
619- HandleContextResponse ( context ) ;
620- return ;
621- }
622-
623661 InvokeRoute ( selectedRoute , context ) ;
624- HandleContextResponse ( context ) ;
625662 }
663+
664+ HandleContextResponse ( context ) ;
626665 } ) . Start ( ) ;
627666
628667 }
0 commit comments