@@ -43,7 +43,7 @@ public class WebServer : IDisposable
43
43
44
44
#region internal objects
45
45
46
- private bool _cancel = false ;
46
+ private bool _cancel = true ;
47
47
private Thread _serverThread = null ;
48
48
private readonly ArrayList _callbackRoutes ;
49
49
private readonly HttpListener _listener ;
@@ -92,6 +92,11 @@ public SslProtocols SslProtocols
92
92
/// </summary>
93
93
public string ApiKey { get ; set ; }
94
94
95
+ /// <summary>
96
+ /// Gets a value indicating whether the web server is running.
97
+ /// </summary>
98
+ public bool IsRunning => ! _cancel ;
99
+
95
100
#endregion
96
101
97
102
#region Param
@@ -191,7 +196,7 @@ private void RegisterControllers(Type[] controllers)
191
196
{
192
197
return ;
193
198
}
194
-
199
+
195
200
foreach ( var controller in controllers )
196
201
{
197
202
var controlAttribs = controller . GetCustomAttributes ( true ) ;
@@ -216,7 +221,7 @@ private void RegisterControllers(Type[] controllers)
216
221
{
217
222
continue ;
218
223
}
219
-
224
+
220
225
var callbackRoutes = new CallbackRoutes
221
226
{
222
227
Route = ( ( RouteAttribute ) attrib ) . Route ,
@@ -330,6 +335,8 @@ private Authentication ExtractAuthentication(string strAuth)
330
335
/// <summary>
331
336
/// Delegate for the CommandReceived event.
332
337
/// </summary>
338
+ /// <param name="obj">The source of the event.</param>
339
+ /// <param name="e">A WebServerEventArgs that contains the event data.</param>
333
340
public delegate void GetRequestHandler ( object obj , WebServerEventArgs e ) ;
334
341
335
342
/// <summary>
@@ -338,6 +345,18 @@ private Authentication ExtractAuthentication(string strAuth)
338
345
/// </summary>
339
346
public event GetRequestHandler CommandReceived ;
340
347
348
+ /// <summary>
349
+ /// Represents the method that will handle the WebServerStatusChanged event of a WebServer.
350
+ /// </summary>
351
+ /// <param name="obj">The source of the event.</param>
352
+ /// <param name="e">A WebServerStatusEventArgs that contains the event data.</param>
353
+ public delegate void WebServerStatusHandler ( object obj , WebServerStatusEventArgs e ) ;
354
+
355
+ /// <summary>
356
+ /// Occurs when the status of the WebServer changes.
357
+ /// </summary>
358
+ public event WebServerStatusHandler WebServerStatusChanged ;
359
+
341
360
#endregion
342
361
343
362
#region Public and private methods
@@ -353,8 +372,10 @@ public bool Start()
353
372
}
354
373
355
374
bool bStarted = true ;
375
+ #if DEBUG
356
376
// List Ethernet interfaces, so we can determine the server's address
357
377
ListInterfaces ( ) ;
378
+ #endif
358
379
// start server
359
380
try
360
381
{
@@ -368,6 +389,12 @@ public bool Start()
368
389
_cancel = true ;
369
390
bStarted = false ;
370
391
}
392
+
393
+ if ( bStarted )
394
+ {
395
+ WebServerStatusChanged ? . Invoke ( this , new WebServerStatusEventArgs ( WebServerStatus . Running ) ) ;
396
+ }
397
+
371
398
return bStarted ;
372
399
}
373
400
@@ -380,7 +407,8 @@ public void Stop()
380
407
Thread . Sleep ( 100 ) ;
381
408
_serverThread . Abort ( ) ;
382
409
_serverThread = null ;
383
- Debug . WriteLine ( "Stopped server in thread " ) ;
410
+ // Event is generate in the running thread
411
+ Debug . WriteLine ( "Stopped server in thread " ) ;
384
412
}
385
413
386
414
/// <summary>
@@ -487,106 +515,117 @@ public static void SendFileOverHTTP(HttpListenerResponse response, string fileNa
487
515
488
516
private void StartListener ( )
489
517
{
490
- _listener . Start ( ) ;
491
- while ( ! _cancel )
518
+ try
492
519
{
493
- HttpListenerContext context = _listener . GetContext ( ) ;
494
- if ( context == null )
495
- {
496
- return ;
497
- }
498
-
499
- new Thread ( ( ) =>
520
+ _listener . Start ( ) ;
521
+ while ( ! _cancel )
500
522
{
501
- //This is for handling with transitory or bad requests
502
- if ( context . Request . RawUrl == null )
523
+ HttpListenerContext context = _listener . GetContext ( ) ;
524
+ if ( context == null )
503
525
{
504
526
return ;
505
527
}
506
528
507
- // Variables used only within the "for". They are here for performance reasons
508
- bool mustAuthenticate ;
509
- bool isAuthOk ;
510
- bool isRoute = false ;
511
-
512
- foreach ( CallbackRoutes route in _callbackRoutes )
529
+ new Thread ( ( ) =>
513
530
{
514
- if ( ! IsRouteMatch ( route , context . Request . HttpMethod , context . Request . RawUrl ) )
531
+ //This is for handling with transitory or bad requests
532
+ if ( context . Request . RawUrl == null )
515
533
{
516
- continue ;
534
+ return ;
517
535
}
518
536
519
- isRoute = true ;
520
-
521
- // Check auth first
522
- mustAuthenticate = route . Authentication != null && route . Authentication . AuthenticationType != AuthenticationType . None ;
523
- isAuthOk = ! mustAuthenticate ;
537
+ // Variables used only within the "for". They are here for performance reasons
538
+ bool mustAuthenticate ;
539
+ bool isAuthOk ;
540
+ bool isRoute = false ;
524
541
525
- if ( mustAuthenticate )
542
+ foreach ( CallbackRoutes route in _callbackRoutes )
526
543
{
527
- if ( route . Authentication . AuthenticationType == AuthenticationType . Basic )
544
+ if ( ! IsRouteMatch ( route , context . Request . HttpMethod , context . Request . RawUrl ) )
528
545
{
529
- var credSite = route . Authentication . Credentials ?? Credential ;
530
- var credReq = context . Request . Credentials ;
531
-
532
- isAuthOk = credReq != null
533
- && ( credSite . UserName == credReq . UserName )
534
- && ( credSite . Password == credReq . Password ) ;
546
+ continue ;
535
547
}
536
- else if ( route . Authentication . AuthenticationType == AuthenticationType . ApiKey )
537
- {
538
- var apikeySite = route . Authentication . ApiKey ?? ApiKey ;
539
- var apikeyReq = GetApiKeyFromHeaders ( context . Request . Headers ) ;
540
548
541
- isAuthOk = apikeyReq != null
542
- && apikeyReq == apikeySite ;
543
- }
544
- }
549
+ isRoute = true ;
545
550
546
- if ( ! isAuthOk )
547
- {
548
- if ( route . Authentication != null &&
549
- route . Authentication . AuthenticationType == AuthenticationType . Basic )
551
+ // Check auth first
552
+ mustAuthenticate = route . Authentication != null && route . Authentication . AuthenticationType != AuthenticationType . None ;
553
+ isAuthOk = ! mustAuthenticate ;
554
+
555
+ if ( mustAuthenticate )
550
556
{
551
- context . Response . Headers . Add ( "WWW-Authenticate" ,
552
- $ "Basic realm=\" Access to { route . Route } \" ") ;
557
+ if ( route . Authentication . AuthenticationType == AuthenticationType . Basic )
558
+ {
559
+ var credSite = route . Authentication . Credentials ?? Credential ;
560
+ var credReq = context . Request . Credentials ;
561
+
562
+ isAuthOk = credReq != null
563
+ && ( credSite . UserName == credReq . UserName )
564
+ && ( credSite . Password == credReq . Password ) ;
565
+ }
566
+ else if ( route . Authentication . AuthenticationType == AuthenticationType . ApiKey )
567
+ {
568
+ var apikeySite = route . Authentication . ApiKey ?? ApiKey ;
569
+ var apikeyReq = GetApiKeyFromHeaders ( context . Request . Headers ) ;
570
+
571
+ isAuthOk = apikeyReq != null
572
+ && apikeyReq == apikeySite ;
573
+ }
553
574
}
554
575
555
- context . Response . StatusCode = ( int ) HttpStatusCode . Unauthorized ;
556
- context . Response . ContentLength64 = 0 ;
576
+ if ( ! isAuthOk )
577
+ {
578
+ if ( route . Authentication != null &&
579
+ route . Authentication . AuthenticationType == AuthenticationType . Basic )
580
+ {
581
+ context . Response . Headers . Add ( "WWW-Authenticate" ,
582
+ $ "Basic realm=\" Access to { route . Route } \" ") ;
583
+ }
584
+
585
+ context . Response . StatusCode = ( int ) HttpStatusCode . Unauthorized ;
586
+ context . Response . ContentLength64 = 0 ;
587
+
588
+ HandleContextResponse ( context ) ;
589
+ return ;
590
+ }
557
591
592
+ InvokeRoute ( route , context ) ;
558
593
HandleContextResponse ( context ) ;
559
- return ;
560
594
}
561
595
562
- InvokeRoute ( route , context ) ;
563
- HandleContextResponse ( context ) ;
564
- }
565
-
566
- if ( ! isRoute )
567
- {
568
- if ( CommandReceived != null )
596
+ if ( ! isRoute )
569
597
{
570
- // Starting a new thread to be able to handle a new request in parallel
571
- CommandReceived . Invoke ( this , new WebServerEventArgs ( context ) ) ;
572
- }
573
- else
574
- {
575
- context . Response . StatusCode = ( int ) HttpStatusCode . NotFound ;
576
- context . Response . ContentLength64 = 0 ;
598
+ if ( CommandReceived != null )
599
+ {
600
+ // Starting a new thread to be able to handle a new request in parallel
601
+ CommandReceived . Invoke ( this , new WebServerEventArgs ( context ) ) ;
602
+ }
603
+ else
604
+ {
605
+ context . Response . StatusCode = ( int ) HttpStatusCode . NotFound ;
606
+ context . Response . ContentLength64 = 0 ;
607
+ }
608
+
609
+ HandleContextResponse ( context ) ;
577
610
}
611
+ } ) . Start ( ) ;
578
612
579
- HandleContextResponse ( context ) ;
580
- }
581
- } ) . Start ( ) ;
613
+ }
582
614
615
+ if ( _listener . IsListening )
616
+ {
617
+ _listener . Stop ( ) ;
618
+ }
583
619
}
584
- if ( _listener . IsListening )
620
+ catch
585
621
{
586
- _listener . Stop ( ) ;
587
- }
622
+ // If we are here then set the server state to not running
623
+ _cancel = true ;
624
+ }
625
+
626
+ WebServerStatusChanged ? . Invoke ( this , new WebServerStatusEventArgs ( WebServerStatus . Stopped ) ) ;
588
627
}
589
-
628
+
590
629
/// <summary>
591
630
/// Checks if route matches called resource.
592
631
/// For internal use only.
@@ -601,14 +640,14 @@ public static bool IsRouteMatch(CallbackRoutes route, string method, string rawU
601
640
{
602
641
return false ;
603
642
}
604
-
643
+
605
644
var urlParam = rawUrl . IndexOf ( ParamStart ) ;
606
645
var incForSlash = route . Route . IndexOf ( '/' ) == 0 ? 0 : 1 ;
607
646
var rawUrlToCompare = route . CaseSensitive ? rawUrl : rawUrl . ToLower ( ) ;
608
647
var routeToCompare = route . CaseSensitive ? route . Route : route . Route . ToLower ( ) ;
609
648
bool isFound ;
610
-
611
- if ( urlParam > 0 )
649
+
650
+ if ( urlParam > 0 )
612
651
{
613
652
isFound = urlParam == routeToCompare . Length + incForSlash ;
614
653
}
@@ -771,6 +810,6 @@ protected virtual void Dispose(bool disposing)
771
810
}
772
811
}
773
812
774
- #endregion
813
+ #endregion
775
814
}
776
815
}
0 commit comments