public void StartListener() { _listener = new TcpListener(ListenAddress, Port); _listener.Start(); while (_isActive) { var s = _listener.AcceptTcpClient(); var processor = new ClientHttpResponse(s, this); Task.Factory.StartNew(processor.ProcessRequest); } }
public abstract void SendFileWithMimeType(string path, string wwwroot, ClientHttpResponse response, Dictionary<string, string> requestParameters, HTTPMethod method, string postData);
public abstract void HandlePostRequest(ClientHttpResponse response, StreamReader inputData);
private bool RouteDefaultResourcePaths(string requestPath, string wwwroot, ClientHttpResponse response, Dictionary<string, string> urlParameters) { var handled = false; switch (requestPath) { case "/favicon.ico": handled = true; SendBytesWithMimeType(requestPath, wwwroot, response, urlParameters, Resources.logo_ico); break; case "/_indexing_style.css": handled = true; SendBytesWithMimeType(requestPath, wwwroot, response, urlParameters, Encoding.UTF8.GetBytes(Resources.defaultindexstyle_css)); break; default: handled = false; break; } return handled; }
public abstract void HandleGetRequest(ClientHttpResponse response);
public override void HandleGetRequest(ClientHttpResponse response) { var wwwroot = SelectDocumentRoot(response); _currentHookExecutionScope.response = response; bool requestHandled = InvokeHook(FireHTTPServerHookType.GetPreHook, _currentHookExecutionScope); if (requestHandled) return; var requestPath = Uri.UnescapeDataString(response.RequestPath); var urlParameters = ParseUrlParameters(ref requestPath); var handled = RewriteRequestPath(ref requestPath, response, wwwroot); if (handled) return; if (!RouteDefaultResourcePaths(requestPath, wwwroot, response, urlParameters)) //If default resource router didn't handle it, send the file { SendFileWithMimeType(requestPath, wwwroot, response, urlParameters, HTTPMethod.Get, null); } Logger.WriteLine($"GET: {response.RequestPath}"); InvokeHook(FireHTTPServerHookType.GetPostHook, _currentHookExecutionScope); _currentHookExecutionScope = new ExpandoObject(); //reset the execution scope }
private bool HandleFAccessConfig(FileSystemInfo requestedFileInfo, DirectoryInfo containingDir, FAccessConfig faccess, ClientHttpResponse response) { if (faccess == null) return false; var forbidden = !faccess.Allow || _denyFileNames.Contains(requestedFileInfo.Name); //User-defined access rules: var dirAccessRules = faccess.FileAccessRules; var requestedFileName = requestedFileInfo.Name; switch (dirAccessRules) { case AccessRules.ExplicitAllow: if (!faccess.AllowedFiles.Contains(requestedFileName)) { forbidden = true; } break; case AccessRules.ExplicitDeny: if (faccess.DeniedFiles.Contains(requestedFileName)) { forbidden = true; } break; } if (forbidden) { if (faccess.ErrorDocument403 == null) { //Show default 403 Logger.WriteLine("403!"); response.SendFailure403(); //Send 403 Header response.OutputStream.WriteLine( "403 - You don't have permission to access this path on this server."); //Default 403 body return true; //end the connection } var errdocFullPath = containingDir.FullName + _dirSep + faccess.ErrorDocument403; Logger.WriteLine("403!"); response.SendFailure403(); //Send 403 Header response.OutputStream.WriteLine(File.ReadAllText(errdocFullPath)); return true; //end the connection } if (requestedFileInfo.Exists) return false; { // Default 404 //Check if it is a missing index, and display dirindex if enabled if (requestedFileInfo.Name == "index.html" && faccess.EnableIndexing && containingDir.Exists) { response.SendHeader("HTTP/1.1 200 OK"); response.SendHeader("Content-Type: text/html"); response.SendEndHeaders(); response.OutputStream.WriteLine(GenerateDirectoryIndex(containingDir, response)); //Dynamic index Logger.WriteLine("Sent dynamic directory index."); return true; //end the connection } if (faccess.ErrorDocument404 == null) { //Show default 404 Logger.WriteLine("404!"); response.SendFailure404(); //Send 404 Header response.OutputStream.WriteLine("404 - File not found"); //Default 404 body return true; //end the connection } var errdocFullPath = containingDir.FullName + _dirSep + faccess.ErrorDocument404; Logger.WriteLine("404!"); response.SendFailure404(); //Send 404 Header response.OutputStream.WriteLine(File.ReadAllText(errdocFullPath)); return true; //end the connection } }
private static string GenerateDirectoryIndex(DirectoryInfo containingDir, ClientHttpResponse response) { var indexhtmlbody = "<ul>"; var fileList = containingDir.GetFiles(); var dirList = containingDir.GetDirectories(); foreach (var dir in dirList) { var targetAddress = response.RequestPath + dir.Name + "/"; var targetDisplayName = dir.Name + "/"; indexhtmlbody += "<li><a href=\"" + targetAddress + "\">" + targetDisplayName + "</a><br></li>"; } foreach (var file in fileList) { var targetAddress = response.RequestPath + file.Name; var targetDisplayName = file.Name; indexhtmlbody += "<li><a href=\"" + targetAddress + "\">" + targetDisplayName + "</a><br></li>"; } indexhtmlbody += "</ul><p><h5>FireHTTP Server</h5></p>"; var indexhtml = "<html><head><title>Index of " + response.RequestPath + "</title></head><body>" + indexhtmlbody + "</body></html>"; return indexhtml; }
private static bool RewriteRequestPath(ref string requestPath, ClientHttpResponse response, string wwwroot) { var path = requestPath.Substring(1); //Remove slash at beginning string rqfullPath = null; try { rqfullPath = Path.Combine(wwwroot, path); } catch (ArgumentException) { // Invalid path, possibly due to some evil stuff trying to XSS or something response.SendFailure404(); response.OutputStream.WriteLine("404 - The requested resource could not be located."); throw new DeadRequestException(); } var finfo = new FileInfo(rqfullPath); var dinfo = new DirectoryInfo(rqfullPath); if (dinfo.Exists && !requestPath.EndsWith("/")) { // Permanent redirection response.SendHeader("HTTP/1.1 301 Moved Permanently"); response.SendHeader("Location: " + requestPath + "/"); response.SendEndHeaders(); } var isDirectory = requestPath.EndsWith("/", StringComparison.CurrentCulture); if (isDirectory) requestPath += "index.html"; return false; }
public override void SendFileWithMimeType(string path, string wwwroot, ClientHttpResponse response, Dictionary<string, string> requestParameters, HTTPMethod method, string postData) { path = path.Substring(1); //Remove slash at beginning var fullPath = Path.Combine(wwwroot, path); var fileInfo = new FileInfo(fullPath); var containingDir = fileInfo.Directory; var configFile = new FileInfo(containingDir?.FullName + _dirSep + CommonVariables.ConfigFileName); var faccess = _defaultFAccess; var fAccessFound = FindFAccess(ref configFile, wwwroot); if (fAccessFound) { var faccessJson = File.ReadAllText(configFile.FullName); faccess = JsonConvert.DeserializeObject<FAccessConfig>(faccessJson); } var requestHandled = HandleFAccessConfig(fileInfo, containingDir, faccess, response); //Process the FACCESS if (requestHandled) return; var extension = fileInfo.Extension; var mimeType = "application/octet-stream"; if (CommonVariables.MimeTypeMappings.ContainsKey(extension)) { mimeType = CommonVariables.MimeTypeMappings[extension]; } if (!_executableFileTypes.Contains(extension)) { var staticFileHookParameters = new FireHTTPHookParameters { RequestedDocumentFullPath = fullPath, RequestFileName = path, RequestMimeType = mimeType, RequestedFileExtension = extension }; //Static file; if not executable, send normally using (var fs = File.OpenRead(fullPath)) { staticFileHookParameters.RequestFileContentStream = fs; bool staticFileHookHandled = InvokeHook(FireHTTPServerHookType.StaticFileSendHook, _currentHookExecutionScope, staticFileHookParameters); if (!staticFileHookHandled) { SendStreamWithMimeType(fs, mimeType, response); } } } else { //Execute Script var executionParameters = new ScriptExecutionParameters(); ExecuteScript(fullPath, requestParameters, response, extension, mimeType, method, postData, wwwroot, executionParameters); } }
public override void SendStreamWithMimeType(Stream dataStream, string mimeType, ClientHttpResponse response) { response.SendHeader("HTTP/1.1 200 OK"); response.SendHeader("Content-Type: " + mimeType); //response.SendHeader("Content-Length: "+fs.Length); response.SendEndHeaders(); response.OutputStream.Flush(); dataStream.CopyTo(response.OutputStream.BaseStream); }
public void SendBytesWithMimeType(string path, string wwwroot, ClientHttpResponse response, Dictionary<string, string> urlParameters, byte[] bytes) { path = path.Substring(1); var fullPath = Path.Combine(wwwroot, path); var fileInfo = new FileInfo(fullPath); var extension = fileInfo.Extension; var mimeType = "application/octet-stream"; if (CommonVariables.MimeTypeMappings.ContainsKey(extension)) { mimeType = CommonVariables.MimeTypeMappings[extension]; } using (var fs = new MemoryStream(bytes)) { //Static file SendStreamWithMimeType(fs, mimeType, response); } }
public string SelectDocumentRoot(ClientHttpResponse response) { if (_serverSettings.SingleInstance) { //Single instance mode, don't process host header return _documentRootCache.Values.ToList()[0]; } var hostHeader = response.GetHostHeader(); var ipcontents = hostHeader.Split(new[] {':'}, StringSplitOptions.RemoveEmptyEntries); var host = ipcontents[0]; if (ipcontents.Length == 2) { var hostPort = -1; int.TryParse(ipcontents[1], out hostPort); } var serverNames = _documentRootCache.Keys.ToArray(); var matches = serverNames.Where(sn => IsWildcardMatch(host, sn)).ToList(); //Get matches if (matches.Count != 0) return _documentRootCache[matches[0]]; //return first match. Logger.WriteLine("No match found for virtualhost."); throw new DeadRequestException(); }
public override void HandlePostRequest(ClientHttpResponse response, StreamReader postStream) { var wwwroot = SelectDocumentRoot(response); _currentHookExecutionScope.response = response; _currentHookExecutionScope.postStream = postStream; bool requestHandled = InvokeHook(FireHTTPServerHookType.PostPreHook, _currentHookExecutionScope); if (requestHandled) return; var rawPostDataString = postStream.ReadToEnd(); var requestPath = Uri.UnescapeDataString(response.RequestPath); var postData = ParsePostData(rawPostDataString, response.RequestHttpHeaders["content-type"]); var handled = RewriteRequestPath(ref requestPath, response, wwwroot); if (handled) return; SendFileWithMimeType(requestPath, wwwroot, response, postData, HTTPMethod.Post, rawPostDataString); Logger.WriteLine($"POST: {response.RequestPath}"); InvokeHook(FireHTTPServerHookType.PostPostHook, _currentHookExecutionScope); _currentHookExecutionScope = new ExpandoObject(); //reset the execution scope }
public abstract void SendStreamWithMimeType(Stream dataStream, string mimeType, ClientHttpResponse response);
private void ExecuteScript(string fullPath, Dictionary<string, string> urlParameters, ClientHttpResponse response, string extension, string mimeType, HTTPMethod method, string postData, string documentRoot, ScriptExecutionParameters executionParameters) { //Select launcher var launcherProgram = _scriptInterpreterCache[extension]; launcherProgram.ExecuteScript(fullPath, urlParameters, response, extension, mimeType, method, postData, documentRoot, this, executionParameters); }
public void ExecuteScript(string fullPath, Dictionary<string, string> urlParameters, ClientHttpResponse response, string extension, string mimeType, HTTPMethod method, string postData, string documentRoot, dynamic serverHandle, ScriptExecutionParameters executionParameters) { //Prepare JSScript var scriptContents = File.ReadAllText(fullPath); var scriptDir = Path.GetDirectoryName(fullPath); var jsEngine = new Engine(cfg => cfg.AllowClr()); var undefined = Undefined.Instance; //Inject variables if (method == HTTPMethod.Get) { jsEngine.SetValue("_GET", urlParameters); jsEngine.SetValue("_SERVER", response.RequestHttpHeaders); jsEngine.SetValue("_POST", undefined); } if (method == HTTPMethod.Post) { jsEngine.SetValue("_GET", undefined); jsEngine.SetValue("_SERVER", response.RequestHttpHeaders); jsEngine.SetValue("_POST", urlParameters); jsEngine.SetValue("POST_DATA", postData); } //Globals jsEngine.SetValue("DocumentRoot", documentRoot); jsEngine.SetValue("__dirname__", scriptDir); switch (extension) { case ".jscx": //Fully-controlled script { try { //Manipulate Scope jsEngine.SetValue("response", response); jsEngine.SetValue("FireHTTPServer", serverHandle); jsEngine.SetValue("_mimeTypeMappings", CommonVariables.MimeTypeMappings); jsEngine.SetValue("dirSep", _dirSep); DefineScriptingApi(jsEngine); jsEngine.Execute(scriptContents); break; } catch (DeadRequestException) { throw; //Don't catch these. } catch (Exception ex) { var level = (int) jsEngine.GetValue("__error_reporting_level").AsNumber(); if (level > 0) { if (!response.HasFinishedSendingHeaders) { //If headers not sent, send default headers. response.SendHeader("HTTP/1.1 200 OK"); response.SendHeader("Content-Type: text/plain"); response.SendEndHeaders(); } response.OutputStream.WriteLine("Error in script execution. Stack trace:"); response.OutputStream.WriteLine(ex.ToString()); break; } throw; } } } }
public void ExecuteScript(string fullPath, Dictionary<string, string> urlParameters, ClientHttpResponse response, string extension, string mimeType, HTTPMethod method, string postData, string documentRoot, dynamic serverHandle, ScriptExecutionParameters executionParameters) { //Prepare ExaScript var scriptContents = File.ReadAllText(fullPath); var scriptDir = Path.GetDirectoryName(fullPath); var escLauncher = new ExaScriptLauncher(); dynamic escExecutionScope = escLauncher.UnderlyingInstance.Scope; var escEngine = escLauncher.UnderlyingInstance.Engine; //Inject variables //Inject code if (method == HTTPMethod.Get) { escExecutionScope._GET = urlParameters; escExecutionScope._SERVER = response.RequestHttpHeaders; escExecutionScope._POST = null; } if (method == HTTPMethod.Post) { escExecutionScope._GET = null; escExecutionScope._SERVER = response.RequestHttpHeaders; escExecutionScope._POST = urlParameters; escExecutionScope.POST_DATA = postData; } //Globals escExecutionScope.DocumentRoot = documentRoot; escExecutionScope.__dirname__ = scriptDir; switch (extension) { case ".esc": //Simple executable script { //Manipulate Scope //Send Headers response.SendHeader("HTTP/1.1 200 OK"); response.SendHeader("Content-Type: " + mimeType); response.SendEndHeaders(); escLauncher.LoadCode(scriptContents); var result = escLauncher.RunCode(); response.OutputStream.WriteLine(result); break; } case ".escx": //Fully-controlled script { try { //Manipulate Scope escExecutionScope.response = response; escExecutionScope.FireHTTPServer = serverHandle; escExecutionScope._mimeTypeMappings = CommonVariables.MimeTypeMappings; escExecutionScope.dirSep = _dirSep; DefineScriptingApi(escExecutionScope); //Add all the API functions escLauncher.LoadCode(scriptContents); escLauncher.RunCode(); break; } catch (DeadRequestException) { throw; //Don't catch these. } catch (Exception ex) { int level = escExecutionScope.__error_reporting_level; if (level <= 0) throw; if (!response.HasFinishedSendingHeaders) { //If headers not sent, send default headers. response.SendHeader("HTTP/1.1 200 OK"); response.SendHeader("Content-Type: text/plain"); response.SendEndHeaders(); } response.OutputStream.WriteLine("Error in script execution. Stack trace:"); response.OutputStream.WriteLine(ex.ToString()); break; } } } }