SimpleHTTPServer in C# GitHub
SimpleHTTPServer in C# GitHub
aksakalli / SimpleHTTPServer.cs
Last active Apr 30, 2019
SimpleHTTPServer in C#
SimpleHTTPServer.cs
https://gist.github.com/aksakalli/9191056 1/10
2/5/2019 SimpleHTTPServer in C# · GitHub
61 {".mpg", "video/mpeg"},
62 {".msi", "application/octet-stream"},
63 {".msm", "application/octet-stream"},
64 {".msp", "application/octet-stream"},
65 {".pdb", "application/x-pilot"},
66 {".pdf", "application/pdf"},
67 {".pem", "application/x-x509-ca-cert"},
68 {".pl", "application/x-perl"},
69 {".pm", "application/x-perl"},
70 {".png", "image/png"},
71 {".prc", "application/x-pilot"},
72 {".ra", "audio/x-realaudio"},
73 {".rar", "application/x-rar-compressed"},
74 {".rpm", "application/x-redhat-package-manager"},
75 {".rss", "text/xml"},
76 {".run", "application/x-makeself"},
77 {".sea", "application/x-sea"},
78 {".shtml", "text/html"},
79 {".sit", "application/x-stuffit"},
80 {".swf", "application/x-shockwave-flash"},
81 {".tcl", "application/x-tcl"},
82 {".tk", "application/x-tcl"},
83 {".txt", "text/plain"},
84 {".war", "application/java-archive"},
85 {".wbmp", "image/vnd.wap.wbmp"},
86 {".wmv", "video/x-ms-wmv"},
87 {".xml", "text/xml"},
88 {".xpi", "application/x-xpinstall"},
89 {".zip", "application/zip"},
90 #endregion
91 };
92 private Thread _serverThread;
93 private string _rootDirectory;
94 private HttpListener _listener;
95 private int _port;
96
97 public int Port
98 {
99 get { return _port; }
100 private set { }
101 }
102
103 /// <summary>
104 /// Construct server with given port.
105 /// </summary>
106 /// <param name="path">Directory path to serve.</param>
107 /// <param name="port">Port of the server.</param>
108 public SimpleHTTPServer(string path, int port)
109 {
110 this.Initialize(path, port);
111 }
112
113 /// <summary>
114 /// Construct server with suitable port.
115 /// </summary>
116 /// <param name="path">Directory path to serve.</param>
117 public SimpleHTTPServer(string path)
118 {
119 //get an empty port
120 TcpListener l = new TcpListener(IPAddress.Loopback, 0);
121 l.Start();
122 int port = ((IPEndPoint)l.LocalEndpoint).Port;
123 l.Stop();
124 this.Initialize(path, port);
125 }
126
127 /// <summary>
128 /// Stop server and dispose all functions.
129 /// </summary>
130 public void Stop()
131 {
132 _serverThread.Abort();
133 _listener.Stop();
https://gist.github.com/aksakalli/9191056 2/10
2/5/2019 SimpleHTTPServer in C# · GitHub
134 }
135
136 private void Listen()
137 {
138 _listener = new HttpListener();
139 _listener.Prefixes.Add("http://*:" + _port.ToString() + "/");
140 _listener.Start();
141 while (true)
142 {
143 try
144 {
145 HttpListenerContext context = _listener.GetContext();
146 Process(context);
147 }
148 catch (Exception ex)
149 {
150
151 }
152 }
153 }
154
155 private void Process(HttpListenerContext context)
156 {
157 string filename = context.Request.Url.AbsolutePath;
158 Console.WriteLine(filename);
159 filename = filename.Substring(1);
160
161 if (string.IsNullOrEmpty(filename))
162 {
163 foreach (string indexFile in _indexFiles)
164 {
165 if (File.Exists(Path.Combine(_rootDirectory, indexFile)))
166 {
167 filename = indexFile;
168 break;
169 }
170 }
171 }
172
173 filename = Path.Combine(_rootDirectory, filename);
174
175 if (File.Exists(filename))
176 {
177 try
178 {
179 Stream input = new FileStream(filename, FileMode.Open);
180
181 //Adding permanent http response headers
182 string mime;
183 context.Response.ContentType = _mimeTypeMappings.TryGetValue(Path.GetExtension(filename), out mime) ? mime : "application/o
184 context.Response.ContentLength64 = input.Length;
185 context.Response.AddHeader("Date", DateTime.Now.ToString("r"));
186 context.Response.AddHeader("Last-Modified", System.IO.File.GetLastWriteTime(filename).ToString("r"));
187
188 byte[] buffer = new byte[1024 * 16];
189 int nbytes;
190 while ((nbytes = input.Read(buffer, 0, buffer.Length)) > 0)
191 context.Response.OutputStream.Write(buffer, 0, nbytes);
192 input.Close();
193
194 context.Response.StatusCode = (int)HttpStatusCode.OK;
195 context.Response.OutputStream.Flush();
196 }
197 catch (Exception ex)
198 {
199 context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
200 }
201
202 }
203 else
204 {
205 context.Response.StatusCode = (int)HttpStatusCode.NotFound;
206 }
https://gist.github.com/aksakalli/9191056 3/10
2/5/2019 SimpleHTTPServer in C# · GitHub
207
208 context.Response.OutputStream.Close();
209 }
210
211 private void Initialize(string path, int port)
212 {
213 this._rootDirectory = path;
214 this._port = port;
215 _serverThread = new Thread(this.Listen);
216 _serverThread.Start();
217 }
218
219
220 }
If you need to run a quick web server and you don't want to mess with setting up IIS or something then this simple class allows you to serve
your static files on .Net Client Profile. It is a simple class that uses HttpListener Class and acts like SimpleHTTPServer of Python. It serves given
path on specified port or auto assigned empty port.
Now it is running.
//stop server
myServer.Stop();
Nice. One thing I noticed: you have to set the OK status for the response before you flush the output stream or you get a server internal error.
(Line 192)
Thanks for the awesome code! I've changed a single line, otherwise I couldn't stop the application/thread.
Find this:
_serverThread.IsBackground = true;
https://gist.github.com/aksakalli/9191056 4/10
2/5/2019 SimpleHTTPServer in C# · GitHub
Not really sure if thats necessary, however it fixed my problem of not being able to close the application.
https://github.com/cloudkitsch/nMVC
https://github.com/cloudkitsch/nMVC/blob/master/nMVC/Core%20Classes/HTTPServer.cs
Usage https://github.com/cloudkitsch/nMVC/blob/master/SampleProject/WebApplication.cs#L52
Cool, thanks a lot! How can I wait until HTTPListener is really started to show MessageBox with text like "HTTP server was succesfully started on
port 80."?
context.Response.StatusCode = (int)HttpStatusCode.OK;
to the top when the headers are set fixes this, but I'm not sure if that's the right way...
@ddoubleday , @raffomania you are right, I updated it. Thanks for your feedback.
@nobodyguy it is a synchronous method, you can show the port in the second line after SimpleHTTPServer myServer = new
SimpleHTTPServer(myFolder, 8084);
@Sotam have you tried to call myServer.Stop(); before closing your app?
not a big deal just : using(Stream input = new FileStream(filename, FileMode.Open)), will call dispose method
nice, thanks
I'm getting an error: An unhandled exception of type 'System.Net.HttpListenerException' occurred in System.dll Access is denied
https://gist.github.com/aksakalli/9191056 5/10
2/5/2019 SimpleHTTPServer in C# · GitHub
Please help!
P.S Otherwise great class and I look forward to using it in my application!
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??
Great snippet!
Take care of Path.Combine, if the second parameter is absolute path, it returns second parameter. So when I put something like:
http://localhost/C:/somefile.txt this implementation streams content of C:/somefile.txt without taking care, if this path is under specified
directory or not!!!
I got ProtocolViolationException on context.Response.OutputStream.Write(buffer, 0, nbytes); when I tried to download files with old version of
wget.
According to the article, we could get rid of the exception by not to send content when client requested header.
I have updated line 187 ~ 190 as followed:
if (context.Request.HttpMethod != "HEAD")
{
byte[] buffer = new byte[1024 * 16];
int nbytes;
while ((nbytes = input.Read(buffer, 0, buffer.Length)) > 0)
context.Response.OutputStream.Write(buffer, 0, nbytes);
}
https://gist.github.com/wqweto/f698cbe9ac8bfdbb3f300b0c4563f7e2 - the same with regex routing implementation in 174 LOC of C#. Includes
directory browsing "middleware" as a sample extension method.
https://gist.github.com/aksakalli/9191056 6/10
2/5/2019 SimpleHTTPServer in C# · GitHub
Fixed memory leaks, Mono / Linux / macOS support issues and threading bugs.
https://gist.github.com/zezba9000/04054e3128e6af413e5bc8002489b2fe
Anyone please?
@Euler29 @muzack2
what you need to do is run your command prompt as an administrator. Then, use netsh http add urlacl url=http://+:80/ user=DOMAIN\user
Substitute 80 to whatever port you are using, DOMAIN to the name of your computer, and the second user to your windows user name.
Also change the asterisk on Line 138 to a + sign. You should be able to now run the server w/o an exception then go to localhost:port/path in
your browser and it will work.
I would like to run my server in 10.10.10.10 on default port 80 (10.10.10.10) or (10.10.10.10:80). But this line is throwing an exception.
httpListener.Prefixes.Add("http://10.10.10.10:" + "/"); How do I handle this.Also how do i connect with my server from my mobile at same time..
Fixes needed:
Add {".mp4", "video/mpeg"} , to the MIME list.
To serve file with spaces, in Proceess, decode the URL: System.Web.HttpUtility.UrlDecode(filename.Substring(1));
You must use _listener.Prefixes.Add("http://127.0.0.1: or localhost to avoid Access Denied issues.
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:
It's a nice implementation, one point I would generally change - getting of the MIME-type. This should be done each time or on start at/from
Registry. Extensions there registered and MIME type is available most times from value Content Type (with space between both words). There
you can add also other MIME types or provide a static functionality at your class to add new custom MIME types to this you find on the
Registry. A dynamic solution would be to lookup at Registry on demand and store found in static dictionary. All other with no registered MIME
type should become application/octet-stream .
https://gist.github.com/aksakalli/9191056 7/10
2/5/2019 SimpleHTTPServer in C# · GitHub
if you want to make sure videos (larger files) are working properly:
context.Response.SendChunked = input.Length > 1024 * 16;
Note that this solution does not work if your website needs more than 1 concurrent request like it does if it streams a video and the user clicks
a link for example. The request following the click will not be processed because the server is busy serving the video. To solve this problem it is
necessary to process requests decoupled from the listener thread. Here it gets quite complicated. It has been done, for example:
https://github.com/JamesDunne/aardwolf
A very comfortable alternative solution (if you dont mind >200 dlls) which works in all cases is using Microsoft.AspNetCore (does not require
IIS): https://www.meziantou.net/2017/05/02/starting-a-http-file-server-from-the-file-explorer-using-net-core
Its simple and clear. Thanks... But how to resize request header length? How can I increase?
https://stackoverflow.com/questions/4019466/httplistener-access-denied
https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/configuring-http-and-https
Basically use netsh -command to allow particular URL to particular user. Another option is to use localhost URL which is by default
allowed to everybody.
Any idea why JavaScript files are not working? Trying to load a html template with JQuery and other simple JS files, but they won't run.
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:
https://gist.github.com/aksakalli/9191056 8/10
2/5/2019 SimpleHTTPServer in C# · GitHub
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:
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?
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?
@Reza805
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;
}
using System.Web.Script.Serialization;
https://gist.github.com/aksakalli/9191056 9/10
2/5/2019 SimpleHTTPServer in C# · GitHub
https://gist.github.com/aksakalli/9191056 10/10