/// <summary> /// Retrieve a static route. /// </summary> /// <param name="method">The HTTP method.</param> /// <param name="path">URL path.</param> /// <returns>StaticRoute if the route exists, otherwise null.</returns> public StaticRoute Get(HttpMethod method, string path) { if (String.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } path = path.ToLower(); if (!path.StartsWith("/")) { path = "/" + path; } if (!path.EndsWith("/")) { path = path + "/"; } lock (_Lock) { StaticRoute curr = _Routes.FirstOrDefault(i => i.Method == method && i.Path == path); if (curr == null || curr == default(StaticRoute)) { return(null); } else { return(curr); } } }
private void Add(StaticRoute route) { if (route == null) { throw new ArgumentNullException(nameof(route)); } route.Path = route.Path.ToLower(); if (!route.Path.StartsWith("/")) { route.Path = "/" + route.Path; } if (!route.Path.EndsWith("/")) { route.Path = route.Path + "/"; } if (Exists(route.Method, route.Path)) { return; } lock (_Lock) { _Routes.Add(route); } }
public StaticRoute Get(string verb, string path) { if (String.IsNullOrEmpty(verb)) { throw new ArgumentNullException(nameof(verb)); } if (String.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } verb = verb.ToLower(); path = path.ToLower(); if (!path.StartsWith("/")) { path = "/" + path; } if (!path.EndsWith("/")) { path = path + "/"; } lock (RouteLock) { StaticRoute curr = Routes.FirstOrDefault(i => i.Verb == verb && i.Path == path); if (curr == null || curr == default(StaticRoute)) { return(null); } else { return(curr); } } }
public void Remove(string verb, string path) { if (String.IsNullOrEmpty(verb)) { throw new ArgumentNullException(nameof(verb)); } if (String.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } StaticRoute r = Get(verb, path); if (r == null || r == default(StaticRoute)) { return; } else { lock (RouteLock) { Routes.Remove(r); } return; } }
/// <summary> /// Match a request method and URL to a handler method. /// </summary> /// <param name="method">The HTTP method.</param> /// <param name="path">URL path.</param> /// <param name="route">Matching route.</param> /// <returns>Method to invoke.</returns> public Func <HttpContext, Task> Match(HttpMethod method, string path, out StaticRoute route) { route = null; if (String.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } path = path.ToLower(); if (!path.StartsWith("/")) { path = "/" + path; } if (!path.EndsWith("/")) { path = path + "/"; } lock (_Lock) { StaticRoute curr = _Routes.FirstOrDefault(i => i.Method == method && i.Path == path); if (curr == null || curr == default(StaticRoute)) { return(null); } else { route = curr; return(curr.Handler); } } }
private void Remove(StaticRoute route) { if (route == null) { throw new ArgumentNullException(nameof(route)); } lock (_Lock) { _Routes.Remove(route); } return; }
/// <summary> /// Add a route. /// </summary> /// <param name="method">The HTTP method.</param> /// <param name="path">URL path, i.e. /path/to/resource.</param> /// <param name="handler">Method to invoke.</param> public void Add(HttpMethod method, string path, Func <HttpRequest, HttpResponse> handler) { if (String.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } if (handler == null) { throw new ArgumentNullException(nameof(handler)); } StaticRoute r = new StaticRoute(method, path, handler); Add(r); }
/// <summary> /// Add a route. /// </summary> /// <param name="method">The HTTP method.</param> /// <param name="path">URL path, i.e. /path/to/resource.</param> /// <param name="handler">Method to invoke.</param> /// <param name="guid">Globally-unique identifier.</param> /// <param name="metadata">User-supplied metadata.</param> public void Add(HttpMethod method, string path, Func <HttpContext, Task> handler, string guid = null, object metadata = null) { if (String.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } if (handler == null) { throw new ArgumentNullException(nameof(handler)); } StaticRoute r = new StaticRoute(method, path, handler, guid, metadata); Add(r); }
/// <summary> /// Remove a route. /// </summary> /// <param name="method">The HTTP method.</param> /// <param name="path">URL path.</param> public void Remove(HttpMethod method, string path) { if (String.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } StaticRoute r = Get(method, path); if (r == null || r == default(StaticRoute)) { return; } else { lock (_Lock) { _Routes.Remove(r); } return; } }
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); } }