internal async Task SendToOutputAsync(HTTPStreamResult httpStreamResult, HttpListenerContext context) { context.Response.ContentLength64 = httpStreamResult.Stream.Length; context.Response.ContentType = httpStreamResult.ContentType; context.Response.ContentEncoding = Encoding.UTF8; //context.Response.AddHeader("Date", DateTime.Now.ToString("r")); //if (!String.IsNullOrEmpty(httpStreamResult?.FileToRead)) context.Response.AddHeader("Last-Modified", File.GetLastWriteTime(httpStreamResult.FileToRead).ToString("r")); context.Response.StatusCode = (int)HttpStatusCode.OK; await httpStreamResult.Stream.CopyToAsync(context.Response.OutputStream).ConfigureAwait(false); }
public override async Task <ProcessRuleResult> ProcessAsync(string callerIP, Scheme scheme, string host, int port, string path, string pathAndQuery, NameValueCollection query, NameValueCollection headers, StaticFileProcessor parent) { HTTPStreamResult httpStreamResult = await parent.ProcessRequestAsync(callerIP, path, this.AlternativeWWWDirectory).ConfigureAwait(false); if ((int)httpStreamResult.HttpStatusCode >= 200 && (int)httpStreamResult.HttpStatusCode < 300) { return(new ProcessRuleResult() { IsSuccess = true, ActionType = ActionType.AlternativeWWWDirectory, HttpStreamResult = httpStreamResult, Message = "Served '" + httpStreamResult.FileToRead + "'" }); } else { return(new ProcessRuleResult() { IsSuccess = false, ActionType = ActionType.AlternativeWWWDirectory, SendErrorResponsePage_HttpStatusCode = httpStreamResult.HttpStatusCode, LogLevel = LogLevel.Warning, Message = httpStreamResult.ErrorMsg }); } }
private async void OnContext(IAsyncResult result) { if (!_listener.IsListening) { return; } HttpListenerContext context = null; try { context = _listener.EndGetContext(result); _listener.BeginGetContext(OnContext, null); string httpMethod = context.Request.HttpMethod; string callerIP = context.Request.RemoteEndPoint.Address.ToString(); string schemeStr = context.Request.Url.Scheme; Scheme scheme; if (string.Equals(schemeStr, "https", StringComparison.OrdinalIgnoreCase)) { scheme = Scheme.https; } else { scheme = Scheme.http; } string host = context.Request.Url.Host; int port = context.Request.Url.Port; string pathAndQuery = context.Request.Url.PathAndQuery; string absolutePath = context.Request.Url.AbsolutePath; string absoluteURL = context.Request.Url.AbsoluteUri; if (string.IsNullOrWhiteSpace(absolutePath)) { absolutePath = "/"; } if (scheme == Scheme.http && this.Config.AllowLocalhostConnectionsOnlyForHttp) { if (!context.Request.IsLocal) { string msg = callerIP + " requested '" + absoluteURL + "' > Blocked as caller is not local ('AllowLocalhostConnectionsOnlyForHttp' is set to 'true')"; this.OnWarningLog?.Invoke(msg); await SendErrorResponsePage(context, msg, HttpStatusCode.Unauthorized).ConfigureAwait(false); return; } } //Process Rules if (this.Config.Rules != null) { foreach (Rule rule in this.Config.Rules) { if (rule.IsMatch(scheme, host, port, absolutePath)) { ProcessRuleResult processRuleResult = await rule.ResponseAction.ProcessAsync(callerIP, scheme, host, port, absolutePath, pathAndQuery, context.Request.QueryString, context.Request.Headers, this).ConfigureAwait(false); switch (processRuleResult.ActionType) { case ActionType.AlternativeWWWDirectory: if (processRuleResult.IsSuccess) { await this.SendToOutputAsync(processRuleResult.HttpStreamResult, context).ConfigureAwait(false); } break; case ActionType.Redirect: context.Response.Redirect(processRuleResult.RedirectURL); break; case ActionType.Deny: context.Response.StatusCode = (int)HttpStatusCode.Forbidden; //context.Response?.Close(); break; case ActionType.ReverseProxy: if (processRuleResult.IsSuccess) { await this.SendToOutputAsync(processRuleResult.HttpStreamResult, context).ConfigureAwait(false); } break; } string msg = null; if (!string.IsNullOrWhiteSpace(processRuleResult.Message)) { msg = processRuleResult.Message; } if (processRuleResult.LogLevel == LogLevel.Info) { this.OnInfoLog?.Invoke(callerIP + " requested '" + absoluteURL + "' > " + rule.Name + " > " + msg); } else if (processRuleResult.LogLevel == LogLevel.Warning) { this.OnWarningLog?.Invoke(callerIP + " requested '" + absoluteURL + "' > " + rule.Name + " > " + msg); } else if (processRuleResult.LogLevel == LogLevel.Error) { this.OnErrorLog?.Invoke(callerIP + " requested '" + absoluteURL + "' > " + rule.Name + " > " + msg); } if (!processRuleResult.IsSuccess) { await this.SendErrorResponsePage(context, processRuleResult.Message, processRuleResult.SendErrorResponsePage_HttpStatusCode).ConfigureAwait(false); return; } if (!processRuleResult.ContinueNextRule) { context.Response?.Close(); return; } } } } //Process Embedded Web API Paths if (this.WebAPIs != null) { foreach (WebAPIAction action in this.WebAPIs) { if ((httpMethod == null || string.Equals(action.HttpMethod, httpMethod, StringComparison.InvariantCultureIgnoreCase)) && string.Equals(action.Path, absolutePath, StringComparison.InvariantCultureIgnoreCase)) { string body = null; using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding)) body = await reader.ReadToEndAsync().ConfigureAwait(false); string query = WebUtility.UrlDecode(context.Request.Url.Query); WebAPIActionInput webAPIActionInput = new WebAPIActionInput(httpMethod, query, body, action, context, this.OnErrorLog); var actionResult = action.Action?.Invoke(webAPIActionInput); if (actionResult.Exception != null) { throw actionResult.Exception; } return; } } } //Process Static Files HTTPStreamResult httpStreamResult = await this.ProcessRequestAsync(callerIP, absolutePath, this.Config.WWWDirectoryParsed()).ConfigureAwait(false); if (httpStreamResult.HttpStatusCode == HttpStatusCode.OK) { await this.SendToOutputAsync(httpStreamResult, context).ConfigureAwait(false); this.OnInfoLog?.Invoke(callerIP + " requested '" + absoluteURL + "' > Served '" + httpStreamResult.FileToRead + "'"); } else { if (httpStreamResult.HttpStatusCode == HttpStatusCode.NotFound && !httpStreamResult.FaviconError) { this.OnWarningLog?.Invoke(callerIP + " requested '" + absoluteURL + "' > '" + httpStreamResult.FileToRead + "' does not exist. Returning NOT FOUND"); } if (httpStreamResult.HttpStatusCode == HttpStatusCode.InternalServerError) { this.OnErrorLog?.Invoke(httpStreamResult.ErrorMsg); } await SendErrorResponsePage(context, httpStreamResult.ErrorMsg, httpStreamResult.HttpStatusCode).ConfigureAwait(false); } } catch (Exception ex) { var exStr = ex.ToString(); try { if (context != null) { await SendErrorResponsePage(context, exStr, HttpStatusCode.InternalServerError).ConfigureAwait(false); } } catch { } this.OnErrorLog?.Invoke(exStr); } }