private async Task AcceptConnections() { try { #region Start-Listeners if (_ListenerHostnames != null) { foreach (string curr in _ListenerHostnames) { string prefix = null; if (_ListenerSsl) { prefix = "https://" + curr + ":" + _ListenerPort + "/"; } else { prefix = "http://" + curr + ":" + _ListenerPort + "/"; } _HttpListener.Prefixes.Add(prefix); } } else if (_ListenerUris != null) { foreach (string curr in _ListenerUris) { _HttpListener.Prefixes.Add(curr); } } _HttpListener.Start(); #endregion #region Listen-and-Process-Requests while (_HttpListener.IsListening && !_TokenSource.IsCancellationRequested) { HttpListenerContext listenerContext = await _HttpListener.GetContextAsync(); HttpContext ctx = null; Task unawaited = Task.Run(async() => { DateTime startTime = DateTime.Now; try { #region Build-Context Events.ConnectionReceived?.Invoke( listenerContext.Request.RemoteEndPoint.Address.ToString(), listenerContext.Request.RemoteEndPoint.Port); ctx = new HttpContext(listenerContext, Events); Events.RequestReceived?.Invoke( ctx.Request.SourceIp, ctx.Request.SourcePort, ctx.Request.Method.ToString(), ctx.Request.FullUrl); _Stats.IncrementRequestCounter(ctx.Request.Method); _Stats.ReceivedPayloadBytes += ctx.Request.ContentLength; #endregion #region Check-Access-Control if (!AccessControl.Permit(ctx.Request.SourceIp)) { Events.AccessControlDenied?.Invoke( ctx.Request.SourceIp, ctx.Request.SourcePort, ctx.Request.Method.ToString(), ctx.Request.FullUrl); listenerContext.Response.Close(); return; } #endregion #region Process-Preflight-Requests if (ctx.Request.Method == HttpMethod.OPTIONS) { if (OptionsRoute != null) { await OptionsRoute(ctx); return; } else { OptionsProcessor(listenerContext, ctx.Request); return; } } #endregion #region Pre-Routing-Handler bool terminate = false; if (PreRoutingHandler != null) { terminate = await PreRoutingHandler(ctx); if (terminate) { return; } } #endregion #region Content-Routes if (ctx.Request.Method == HttpMethod.GET || ctx.Request.Method == HttpMethod.HEAD) { if (ContentRoutes.Exists(ctx.Request.RawUrlWithoutQuery)) { await _ContentRouteProcessor.Process(ctx); return; } } #endregion #region Static-Routes Func <HttpContext, Task> handler = StaticRoutes.Match(ctx.Request.Method, ctx.Request.RawUrlWithoutQuery); if (handler != null) { await handler(ctx); return; } #endregion #region Dynamic-Routes handler = DynamicRoutes.Match(ctx.Request.Method, ctx.Request.RawUrlWithoutQuery); if (handler != null) { await handler(ctx); return; } #endregion #region Default-Route await _DefaultRoute(ctx); return; #endregion } catch (Exception eInner) { if (ctx == null || ctx.Request == null) { Events.ExceptionEncountered?.Invoke(null, 0, eInner); } else { Events.ExceptionEncountered?.Invoke(ctx.Request.SourceIp, ctx.Request.SourcePort, eInner); } } finally { if (ctx != null && ctx.Response != null && ctx.Response.ResponseSent) { Events.ResponseSent?.Invoke( ctx.Request.SourceIp, ctx.Request.SourcePort, ctx.Request.Method.ToString(), ctx.Request.FullUrl, ctx.Response.StatusCode, TotalMsFrom(startTime)); _Stats.SentPayloadBytes += ctx.Response.ContentLength; } } }, _Token); } #endregion } catch (Exception e) { Events.ExceptionEncountered?.Invoke(null, 0, e); } finally { Events.ServerStopped?.Invoke(); } }
private async Task AcceptConnections(CancellationToken token) { try { #region Process-Requests while (_HttpListener.IsListening) { if (_RequestCount >= _Settings.IO.MaxRequests) { await Task.Delay(100, token).ConfigureAwait(false); continue; } HttpListenerContext listenerCtx = await _HttpListener.GetContextAsync().ConfigureAwait(false); Interlocked.Increment(ref _RequestCount); HttpContext ctx = null; Task unawaited = Task.Run(async() => { DateTime startTime = DateTime.Now; try { #region Build-Context Events.HandleConnectionReceived(this, new ConnectionEventArgs( listenerCtx.Request.RemoteEndPoint.Address.ToString(), listenerCtx.Request.RemoteEndPoint.Port)); ctx = new HttpContext(listenerCtx, _Settings, Events); Events.HandleRequestReceived(this, new RequestEventArgs(ctx)); if (_Settings.Debug.Requests) { Events.Logger?.Invoke( _Header + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); } Statistics.IncrementRequestCounter(ctx.Request.Method); Statistics.IncrementReceivedPayloadBytes(ctx.Request.ContentLength); #endregion #region Check-Access-Control if (!_Settings.AccessControl.Permit(ctx.Request.Source.IpAddress)) { Events.HandleRequestDenied(this, new RequestEventArgs(ctx)); if (_Settings.Debug.AccessControl) { Events.Logger?.Invoke(_Header + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " denied due to access control"); } listenerCtx.Response.StatusCode = 403; listenerCtx.Response.Close(); return; } #endregion #region Process-Preflight-Requests if (ctx.Request.Method == HttpMethod.OPTIONS) { if (_Routes.Preflight != null) { if (_Settings.Debug.Routing) { Events.Logger?.Invoke( _Header + "preflight route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); } await _Routes.Preflight(ctx).ConfigureAwait(false); return; } } #endregion #region Pre-Routing-Handler bool terminate = false; if (_Routes.PreRouting != null) { terminate = await _Routes.PreRouting(ctx).ConfigureAwait(false); if (terminate) { if (_Settings.Debug.Routing) { Events.Logger?.Invoke( _Header + "prerouting terminated connection for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); } return; } } #endregion #region Content-Routes if (ctx.Request.Method == HttpMethod.GET || ctx.Request.Method == HttpMethod.HEAD) { ContentRoute cr = null; if (_Routes.Content.Match(ctx.Request.Url.RawWithoutQuery, out cr)) { if (_Settings.Debug.Routing) { Events.Logger?.Invoke( _Header + "content route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); } ctx.RouteType = RouteTypeEnum.Content; ctx.Route = cr; await _Routes.ContentHandler.Process(ctx, token).ConfigureAwait(false); return; } } #endregion #region Static-Routes StaticRoute sr = null; Func <HttpContext, Task> handler = _Routes.Static.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out sr); if (handler != null) { if (_Settings.Debug.Routing) { Events.Logger?.Invoke( _Header + "static route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); } ctx.RouteType = RouteTypeEnum.Static; ctx.Route = sr; await handler(ctx).ConfigureAwait(false); return; } #endregion #region Parameter-Routes ParameterRoute pr = null; Dictionary <string, string> parameters = null; handler = _Routes.Parameter.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out parameters, out pr); if (handler != null) { ctx.Request.Url.Parameters = new Dictionary <string, string>(parameters); if (_Settings.Debug.Routing) { Events.Logger?.Invoke( _Header + "parameter route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); } ctx.RouteType = RouteTypeEnum.Parameter; ctx.Route = pr; await handler(ctx).ConfigureAwait(false); return; } #endregion #region Dynamic-Routes DynamicRoute dr = null; handler = _Routes.Dynamic.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out dr); if (handler != null) { if (_Settings.Debug.Routing) { Events.Logger?.Invoke( _Header + "dynamic route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); } ctx.RouteType = RouteTypeEnum.Dynamic; ctx.Route = dr; await handler(ctx).ConfigureAwait(false); return; } #endregion #region Default-Route if (_Routes.Default != null) { if (_Settings.Debug.Routing) { Events.Logger?.Invoke( _Header + "default route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); } ctx.RouteType = RouteTypeEnum.Default; await _Routes.Default(ctx).ConfigureAwait(false); return; } else { if (_Settings.Debug.Routing) { Events.Logger?.Invoke( _Header + "default route not found for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); } ctx.Response.StatusCode = 404; ctx.Response.ContentType = Pages.Default404Page.ContentType; await ctx.Response.Send(Pages.Default404Page.Content).ConfigureAwait(false); return; } #endregion } catch (Exception eInner) { ctx.Response.StatusCode = 500; ctx.Response.ContentType = Pages.Default500Page.ContentType; await ctx.Response.Send(Pages.Default500Page.Content).ConfigureAwait(false); Events.HandleExceptionEncountered(this, new ExceptionEventArgs(ctx, eInner)); } finally { Interlocked.Decrement(ref _RequestCount); if (ctx != null && ctx.Response != null && ctx.Response.ResponseSent) { Events.HandleResponseSent(this, new ResponseEventArgs(ctx, TotalMsFrom(startTime))); Statistics.IncrementSentPayloadBytes(ctx.Response.ContentLength); } } }, token); } #endregion } catch (TaskCanceledException) { } catch (OperationCanceledException) { } catch (HttpListenerException) { } catch (Exception e) { Events.HandleExceptionEncountered(this, new ExceptionEventArgs(null, e)); } finally { Events.HandleServerStopped(this, EventArgs.Empty); } }