-
-
Save aksakalli/9191056 to your computer and use it in GitHub Desktop.
// MIT License - Copyright (c) 2016 Can Güney Aksakalli | |
// https://aksakalli.github.io/2014/02/24/simple-http-server-with-csparp.html | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Net.Sockets; | |
using System.Net; | |
using System.IO; | |
using System.Threading; | |
using System.Diagnostics; | |
class SimpleHTTPServer | |
{ | |
private readonly string[] _indexFiles = { | |
"index.html", | |
"index.htm", | |
"default.html", | |
"default.htm" | |
}; | |
private static IDictionary<string, string> _mimeTypeMappings = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) { | |
#region extension to MIME type list | |
{".asf", "video/x-ms-asf"}, | |
{".asx", "video/x-ms-asf"}, | |
{".avi", "video/x-msvideo"}, | |
{".bin", "application/octet-stream"}, | |
{".cco", "application/x-cocoa"}, | |
{".crt", "application/x-x509-ca-cert"}, | |
{".css", "text/css"}, | |
{".deb", "application/octet-stream"}, | |
{".der", "application/x-x509-ca-cert"}, | |
{".dll", "application/octet-stream"}, | |
{".dmg", "application/octet-stream"}, | |
{".ear", "application/java-archive"}, | |
{".eot", "application/octet-stream"}, | |
{".exe", "application/octet-stream"}, | |
{".flv", "video/x-flv"}, | |
{".gif", "image/gif"}, | |
{".hqx", "application/mac-binhex40"}, | |
{".htc", "text/x-component"}, | |
{".htm", "text/html"}, | |
{".html", "text/html"}, | |
{".ico", "image/x-icon"}, | |
{".img", "application/octet-stream"}, | |
{".iso", "application/octet-stream"}, | |
{".jar", "application/java-archive"}, | |
{".jardiff", "application/x-java-archive-diff"}, | |
{".jng", "image/x-jng"}, | |
{".jnlp", "application/x-java-jnlp-file"}, | |
{".jpeg", "image/jpeg"}, | |
{".jpg", "image/jpeg"}, | |
{".js", "application/x-javascript"}, | |
{".mml", "text/mathml"}, | |
{".mng", "video/x-mng"}, | |
{".mov", "video/quicktime"}, | |
{".mp3", "audio/mpeg"}, | |
{".mpeg", "video/mpeg"}, | |
{".mpg", "video/mpeg"}, | |
{".msi", "application/octet-stream"}, | |
{".msm", "application/octet-stream"}, | |
{".msp", "application/octet-stream"}, | |
{".pdb", "application/x-pilot"}, | |
{".pdf", "application/pdf"}, | |
{".pem", "application/x-x509-ca-cert"}, | |
{".pl", "application/x-perl"}, | |
{".pm", "application/x-perl"}, | |
{".png", "image/png"}, | |
{".prc", "application/x-pilot"}, | |
{".ra", "audio/x-realaudio"}, | |
{".rar", "application/x-rar-compressed"}, | |
{".rpm", "application/x-redhat-package-manager"}, | |
{".rss", "text/xml"}, | |
{".run", "application/x-makeself"}, | |
{".sea", "application/x-sea"}, | |
{".shtml", "text/html"}, | |
{".sit", "application/x-stuffit"}, | |
{".swf", "application/x-shockwave-flash"}, | |
{".tcl", "application/x-tcl"}, | |
{".tk", "application/x-tcl"}, | |
{".txt", "text/plain"}, | |
{".war", "application/java-archive"}, | |
{".wbmp", "image/vnd.wap.wbmp"}, | |
{".wmv", "video/x-ms-wmv"}, | |
{".xml", "text/xml"}, | |
{".xpi", "application/x-xpinstall"}, | |
{".zip", "application/zip"}, | |
#endregion | |
}; | |
private Thread _serverThread; | |
private string _rootDirectory; | |
private HttpListener _listener; | |
private int _port; | |
public int Port | |
{ | |
get { return _port; } | |
private set { } | |
} | |
/// <summary> | |
/// Construct server with given port. | |
/// </summary> | |
/// <param name="path">Directory path to serve.</param> | |
/// <param name="port">Port of the server.</param> | |
public SimpleHTTPServer(string path, int port) | |
{ | |
this.Initialize(path, port); | |
} | |
/// <summary> | |
/// Construct server with suitable port. | |
/// </summary> | |
/// <param name="path">Directory path to serve.</param> | |
public SimpleHTTPServer(string path) | |
{ | |
//get an empty port | |
TcpListener l = new TcpListener(IPAddress.Loopback, 0); | |
l.Start(); | |
int port = ((IPEndPoint)l.LocalEndpoint).Port; | |
l.Stop(); | |
this.Initialize(path, port); | |
} | |
/// <summary> | |
/// Stop server and dispose all functions. | |
/// </summary> | |
public void Stop() | |
{ | |
_serverThread.Abort(); | |
_listener.Stop(); | |
} | |
private void Listen() | |
{ | |
_listener = new HttpListener(); | |
_listener.Prefixes.Add("http://*:" + _port.ToString() + "/"); | |
_listener.Start(); | |
while (true) | |
{ | |
try | |
{ | |
HttpListenerContext context = _listener.GetContext(); | |
Process(context); | |
} | |
catch (Exception ex) | |
{ | |
} | |
} | |
} | |
private void Process(HttpListenerContext context) | |
{ | |
string filename = context.Request.Url.AbsolutePath; | |
Console.WriteLine(filename); | |
filename = filename.Substring(1); | |
if (string.IsNullOrEmpty(filename)) | |
{ | |
foreach (string indexFile in _indexFiles) | |
{ | |
if (File.Exists(Path.Combine(_rootDirectory, indexFile))) | |
{ | |
filename = indexFile; | |
break; | |
} | |
} | |
} | |
filename = Path.Combine(_rootDirectory, filename); | |
if (File.Exists(filename)) | |
{ | |
try | |
{ | |
Stream input = new FileStream(filename, FileMode.Open); | |
//Adding permanent http response headers | |
string mime; | |
context.Response.ContentType = _mimeTypeMappings.TryGetValue(Path.GetExtension(filename), out mime) ? mime : "application/octet-stream"; | |
context.Response.ContentLength64 = input.Length; | |
context.Response.AddHeader("Date", DateTime.Now.ToString("r")); | |
context.Response.AddHeader("Last-Modified", System.IO.File.GetLastWriteTime(filename).ToString("r")); | |
byte[] buffer = new byte[1024 * 16]; | |
int nbytes; | |
while ((nbytes = input.Read(buffer, 0, buffer.Length)) > 0) | |
context.Response.OutputStream.Write(buffer, 0, nbytes); | |
input.Close(); | |
context.Response.StatusCode = (int)HttpStatusCode.OK; | |
context.Response.OutputStream.Flush(); | |
} | |
catch (Exception ex) | |
{ | |
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; | |
} | |
} | |
else | |
{ | |
context.Response.StatusCode = (int)HttpStatusCode.NotFound; | |
} | |
context.Response.OutputStream.Close(); | |
} | |
private void Initialize(string path, int port) | |
{ | |
this._rootDirectory = path; | |
this._port = port; | |
_serverThread = new Thread(this.Listen); | |
_serverThread.Start(); | |
} | |
} |
This works for what I need. Thanks a lot.
If you don't know what to use for the "user=DOMAIN\user" parameter shown in the netsh command given by @therealpappy, you can use "everyone" instead:
netsh http add urlacl url=http://+:80/ user=everyone
Note, everyone is language dependent so Spanish is "todos", German is 'alles", etc.
Just do http add urlacl url=http://+:80/ sddl=D:(A;;GX;;;S-1-1-0)
sddl=D:(A;;GX;;;S-1-1-0) = "everyone" in all languages
I was trying this and noticed it was having trouble serving up multiple requests at a time. Turns out this line was throwing exceptions occasionally for modifying the status code after headers were sent. I moved it up before anything was send to the output stream and things started working more smoothly, but I wonder why it works sometimes if that's really as problematic as it looks.
Hi, after creating a local server using the code above, I need to open a local file from that server. I have used the following code:
string myFolder = "D:\flower.jpg";
SimpleHTTPServer myServer = new SimpleHTTPServer(myFolder, 8084);
Now, when I try to access the link: http://localhost:8084/, the page isn't loaded. What needs to be done so that I can access the file in my path from localhost?
string myFolder = "D:\flower.jpg";
SimpleHTTPServer myServer = new SimpleHTTPServer(myFolder, 8084);
Your 'myFolder' variable is a file('..flower.jpg') not a folder.
Hi all I'm using
public void StartServer() { myServer = new SimpleHTTPServer(Path.Combine(Application.streamingAssetsPath, "PDF")); Application.OpenURL("http:/localhost:" + myServer.Port + "/" + FirstIndexPath); }
from this link https://answers.unity.com/questions/1245582/create-a-simple-https-server-on-the-streaming-asset.html
and I can't get anything to work. I keep getting localhost page can't be found. I've tried using html files pdfs and jpegs and nothing works. I tried using a folder on the my android to house the pdfs at file:/// thinking it was a streaming asset Unity issue but that didn't help either. Any help would be appreciated.
Hello, while using with .mp4 or .mpeg , video link starts to download mode, but i want it not download in browser, want it stream, can you show how to do it?
hi , how to get list of files in the directory?
for listing the files in the current directory as json, you can add a code block after line 159 like:
if (filename=="getfiles"){
files = System.IO.Directory.GetFiles(_rootDirectory, @"*", SearchOption.TopDirectoryOnly);
var serializer = new JavaScriptSerializer();
var jsonContent = serializer.Serialize(files);
context.Response.Write(jsonContent);
context.Response.StatusCode = (int)HttpStatusCode.OK;
return;
}
also add this to the top
using System.Web.Script.Serialization;
Ps. I didn't run this snippet but it should work.
@aksakalli Thanks for the project. I just wanted to report a potential bug and ask if anybody has encountered it. I've found that the HTTPServer cannot seem to host files that are "Read only".
I have tested your Http Server, why to run my application I have to leave it as an administrator?
I asked the wrong question:
why must run my application with your http server only as an administrator?
I know this is a very old gist and might not be active anymore, but does anyone know how to serve mp4 media files? Not to download but to play within the browser window.
{".mp4","video/mp4"},
I added this to the MIME type list to support mp4 files, but when i then request a file with mp4 format i get a GET http://localhost:8084/video.mp4 500 (Internal Server Error)
with no further information of what the issue is.
My updated process method
private void Process(HttpListenerContext context)
{
string filename = WebUtility.UrlDecode(context.Request.Url.AbsolutePath.Substring(1));
Console.WriteLine(filename);
if (string.IsNullOrEmpty(filename))
{
foreach (string indexFile in _indexFiles)
{
if (File.Exists(Path.Combine(_rootDirectory, indexFile)))
{
filename = indexFile;
break;
}
}
}
filename = Path.Combine(_rootDirectory, filename);
if (File.Exists(filename))
{
try
{
Stream input = new FileStream(filename, FileMode.Open);
context.Response.ContentType = _mimeTypeMappings.TryGetValue(Path.GetExtension(filename), out string mime) ? mime : "application/octet-stream";
context.Response.ContentLength64 = input.Length;
if (context.Request.HttpMethod != "HEAD")
{
byte[] buffer = new byte[1024 * 16];
int nbytes;
while ((nbytes = input.Read(buffer, 0, buffer.Length)) > 0)
{
context.Response.SendChunked = input.Length > 1024 * 16;
context.Response.OutputStream.Write(buffer, 0, nbytes);
}
}
context.Response.StatusCode = (int)HttpStatusCode.OK;
context.Response.OutputStream.Flush();
}
catch
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
}
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
}
context.Response.OutputStream.Close();
}
if (filename=="getfiles"){ files = System.IO.Directory.GetFiles(_rootDirectory, @"*", SearchOption.TopDirectoryOnly); var serializer = new JavaScriptSerializer(); var jsonContent = serializer.Serialize(files); context.Response.Write(jsonContent); context.Response.StatusCode = (int)HttpStatusCode.OK; return; }Ps. I didn't run this snippet but it should work.
This snippet does not work, HTTPListenerResponse does not contain a method called Write, 'files' has no variable declared, and consider using JsonConvert.Serialize(files) instead of JavaScripSerializer as it's not included in the latest version .NET framework.
My version of get all files (somewhat the same).
if (filename == "*")
{
try
{
string responseString = JsonConvert.SerializeObject(Directory.GetFiles(_rootDirectory, @"*.*", SearchOption.AllDirectories));
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
context.Response.ContentLength64 = buffer.Length;
Stream output = context.Response.OutputStream;
output.Write(buffer, 0, buffer.Length);
context.Response.StatusCode = (int)HttpStatusCode.OK;
context.Response.OutputStream.Flush();
}
catch
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
}
}
made quite a few improvements to this and it exits cleanly now. Can't seem to find where to submit a pull request check my fork.
I have a HTML page where we need to access a .xml and a .json file. However, they aren't loaded by the web server. Any ideas on why this isn't working??
it might because there's no ".json" in "_mimeTypeMappings" .
What about https support?