Introduction
MiniHttpd is a standalone HTTP and HTTP web server library. It can be used either as a web server, or as an HTTP listener in situations where deploying a full-blown web server such as IIS or Apache would not be feasible.
One of the original motives for making MiniHttpd was to make a web interface for the Windows Media Player that I could use to control Media Player from my phone or Pocket PC and download tracks onto. One such program, called PlayerPal, as of version 3.0 uses the Cassini library which is similar in functionality but is no longer under development.
Another motive was to make an alternative file server to use between my friends. It doesn't seem to matter how many ways there are to send files - MSN, IRC, FTP, email... sometimes none of them work!
MiniHttpd is not complete, and additional features and improvements are sure to come. If you have any suggestions or problems, I'd be glad to hear them. If you're using MiniHttpd in the wild, I recommend isolating it in a separate OS account with limited privileges. As always, I appreciate bug finds - this is a one-man project for now, and there's only so much that I can do alone. Many thanks to those who've looked at the code.
Download
To demonstrate the server, I've set up a MiniHttpd server on my friend's computer hosting the demo application binary. You can download the MiniHttpdApp here.
Compared to other web servers
Here is a feature comparison of MiniHttpd and other common web servers. This list is exhaustive only to the limit of my knowledge, so let me know if I'm missing anything important.
| Apache | IIS | XSP | Cassini | MiniHttpd |
Windows compatible | | | | | |
*NIX/BSD/OS X compatible | | | | | |
.NET Compact framework compatible | | | | | Possibly in the future |
Standalone | | | | | |
Portable library | | | | | |
ASPX capable | With Mod-Mono | | | | As of version 1.1 |
PHP capable | | | | | |
Commercially suitable | | | | | |
Programmability | PHP/CGI | ASP/ASPX | ASPX | ASPX | ASPX, IFile /IDirectory |
Supports resuming | | | | | |
SSL (HTTPS) support | | | | | Hopefully soon |
Using the code
Basic setup
At minimum, setting up a web server requires only a few lines of code. This example initializes a web server that uses your C drive as the root directory:
HttpWebServer server = new HttpWebServer();
server.Root = new DriveDirectory(@"c:\");
server.Start();
Console.ReadLine();
server.Stop();
And that's it! You can browse to your local address in your favorite browser and it should show you a directory listing or an index.htm/index.html page if there is one. You can specify a different listener port in the constructor or by setting the Port
property.
Virtual directories
Virtual directories are directories that you can populate programmatically rather than by reflecting a physical directory. By default, an HttpWebServer
instance sets root
to an empty virtual directory upon creation. You can choose either to work with this one or create your own. This example creates a virtual directory, adds a few files and folders, and deletes a few.
VirtualDirectory root = new VirtualDirectory();
server.Root = root;
root.AddFile("notepad.exe");
root.AddFile("autoexec.bat");
root.AddDirectory(@"c:\windows");
root.Remove(@"autoexec.bat");
root.AddDirectory(new VirtualDirectory("virtual", root));
ASP.NET support
ASPX is implemented as extensions of DriveDirectory
and HttpWebServer
, and AspxAppDir
and AspxWebServer
respectively. Both have the same constructors as their base classes, so setting up is as easy as replacing all instances of the two.
Unfortunately, there is no virtual ASPX directory because ASP.NET requires files to have absolute paths on-disk. I will keep an eye out for workarounds -- it'd be really nice to be able to store ASPX applications in assemblies.
The ASPX code is contained in the MiniHttpd assembly to avoid cluttering distributions. If for any reason you don't want the ASPX at all, you can just exclude the Aspx folder from the project and recompile.
Certain features are still not implemented in version 1.1; the two that I know are not yet implemented are HTTP handlers and HTTPS.
Note that MiniHttpd leaves Bin folders with MiniHttpd.dll in whichever folder you use as an ASPX directory. MiniHttpd 1.2.0 onwards will remove the file upon disposal as well as the folder if it is empty.
PHP support
PHP is implemented similar to ASPX, with PhpAppDirectory
and PhpWebServer
inheriting DriveDirectory
and HttpWebServer
. PHP support is even more primitive than ASPX for the time being, accepting only scripts with text output and no request/response headers.
There are three assemblies you need to use PHP with MiniHttpd:
- MiniHttpd.Php.dll - you can download this along with its source from the link at the top of the article.
- php4app.dll - this is included in the project, but you can also download it from here.
- php5ts.dll - because this is a rather big file (4 MB), I've hosted it here. You can also find it in the PHP Windows binaries, which you can download here.
Thanks to Daaron Dwyer for demonstrating PHP on MiniHttpd to me and doing the bulk of the work on MiniHttpd.Php!
Index Page
The index page currently built into the library is a very boring list of files available in the folder. You can override this by replacing the HttpWebServer.IndexPage
property. Optionally, you can override the IndexPage
class, which provides a BuildPath
method that you can use to determine the relative path of a directory.
Additionally, as of version 1.2.0, there's a slightly fancier index page called IndexPageEx
. You can use it by creating a new IndexPageEx
object and assigning it to HttpWebServer.IndexPage
. You can specify the columns and order of columns to display, by setting an array of ResourceColumn
values in the IndexPageEx.Columns
property. The default is Modified, Size, Name
. IndexPageEx
can be slow for large directories, so decide carefully whether or not to use it. (My suspicion is that this will change in a few months when MSH and/or Vista is released.)
HttpServer
HttpServer
, along with its satellite classes, implement the essential workings of the HTTP/1.1 protocol. HttpWebServer
is derived from this class. You can use this class to handle HTTP transactions manually without using the directory structure that the HttpWebServer
provides. However, a similar class, System.Net.HttpListener
, is introduced in the .NET 2.0 Framework, so you may want to use that instead if all you need is an HTTP listener.
Logging
The server writes log messages to the TextWriter
specified by HttpServer.Log
. By default, this writes to the console, unless there is no console available (such as on Pocket PC). You can disable this by setting LogConnections
and LogRequests
to false
, and you can redirect the output to other TextWriter
s by setting the Log
property.
Authentication
As of version 1.2.0, MiniHttpd supports a very simple authentication (logins and passwords) through the IAuthenticator
interface. There are two implemented IAuthenticator
s in MiniHttpd: BasicAuthenticator
and LdapAuthenticator
. You can enable it by setting HttpServer.RequireAuthentication
to true
. The default is BasicAuthenticator
, but you can enable LdapAuthenticator
just as easily by assigning a new LdapAuthenticator
to HttpServer.Authenticator
.
BasicAuthenticator
just maintains a Hashtable
containing user/password pairs. Passwords are stored as MD5 hashes to be ready for serialization and on-disk storage. LdapAuthenticator
authenticates against an Active Directory server with the username and password given by the client.
Authentication is primitive for the time being; access is server-wide. Also note that this is not HTTPS, so passwords and transactions are not encrypted.
Thanks again to Daaron Dwyer for demonstrating LDAP and authentication on MiniHttpd.
IDirectory and IFile
All objects in the HttpWebServer
file tree are described by implementations of IDirectory
and IFile
. Both IDirectory
and IFile
inherit IResource
, which provides properties to identify a file or directory. Internally, the IDirectory
is implemented by DriveDirectory
to reference physical directories, and VirtualDirectory
for memory-resident directories containing other IDirectory
s and IFile
s. IFile
is implemented by DriveFile
to reference files on disk.
IDirectory
and IFile
can be used to make dynamic content. Any tree-file structure can be represented by an IDirectory
object; for example, the Media Library in Windows Media Player. IFile
can be used to send anything from redirects to streaming video. The IDirectory
/IFile
interfaces have been used for some cool projects so far:
- "What's my IP" image generator
- Webcam feed that automatically turns on the garage lights before snapping
- Video stream to web-enabled TV devices
There isn't much ASPX couldn't do that IFile
/IDirectory
could, so they shine most in situations where ASPX is not available. But at this point, MiniHttpd isn't compatible with any OS that doesn't have ASPX. If there's any interest, I'll try to restore the Compact Framework compatibility so that it can be used as a programmable web server for Pocket PC and SmartPhones. I'd love to see it running on SPOT OS (used for SPOT watches and Windows Vista's Auxiliary Displays) if they ever make it available to the public for hobby electronics and robotics. Let's hope they do!
Implementing IDirectory
Implementing IDirectory
is pretty straightforward. An IDirectory
object typically holds a collection of subdirectories and subfiles. There are just three required steps:
- Create a constructor that takes in the name and the parent directory of the directory, and stores them for the
Name
and Parent
properties to return (see IFile
example below).
- Implement the
IResource.Name
and IResource.Parent
properties by returning the values passed in from the constructor.
- Implement all of the
IDirectory.Get...()
functions. Their usages are described in the XML documentation in FileSystem/IDirectory.cs.
Be sure to call Dispose()
on all subdirectories and files when they are removed, and in the Dispose
function.
Implementing IFile
Implementing IFile
is slightly more complicated, although from a programmer's perspective, I find it easier to grasp conceptually than an ASPX webpage (but that's probably just me).
Like IDirectory
, the first step is to create a constructor that takes the name and the parent directory as arguments, and stores them for the Name
and Parent
properties.
Then you implement ContentType
. Content Types (also called MIME types) are the Web's way of describing the type of a resource, much like the way Windows identifies file types by their filename extensions. .txt files are called "text/plain", .jpg files are called "image/jpeg", and .html/.htm files are called "text/html". In general, you can use ContentTypes.GetExtensionType()
to retrieve the MIME equivalents of common file extensions.
Last but not least, implement the OnFileRequested
method. request
provides all of the properties and methods to manipulate the request, while directory
provides the parent directory of the file. In most cases, the Response
property is the only one that matters, and specifically, the ResponseContent
property of the Response
property. You can assign any sort of stream to the ResponseContent
stream, so long as it supports reading, seeking, and has a definite length.
An IFile
implementation that sends the text "Hello, world!" to the client might look like this:
public class HelloWorldFile : IFile
{
public HelloWorldFile(string name, IDirectory parent)
{
this.name = name;
this.parent = parent;
}
string name;
IDirectory parent;
public void OnFileRequested(HttpRequest request,
IDirectory directory)
{
request.Response.ResponseContent = new MemoryStream();
StreamWriter writer =
new StreamWriter(request.Response.ResponseContent);
writer.WriteLine("Hello, world!");
writer.Flush();
}
public string ContentType
{
get { return ContentTypes.GetExtensionType(".txt"); }
}
public string Name
{
get { return name; }
}
public IDirectory Parent
{
get { return parent; }
}
public void Dispose()
{
}
}
Chunked Responses
Because HTTP normally requires that you provide the size of a resource in the header, MiniHttpd uses the Length
property of the stream assigned to HttpResponse.ResponseStream
to retrieve this information. However, there are some forms of data that don't have a definite size - dynamic web pages and video/audio streams are examples of such. The HTTP/1.1 protocol provides a mechanism to allow for this, called Chunked transfer encoding (HTTP/1.0 implicitly signals the end of a transmission by disconnecting after each transmission). You can enable it by calling BeginChunkedOutput()
instead of assigning a stream to HttpResponse.ResponseStream
(the function does this for you).
MiniHttpdApp demo projects
MiniHttpdApp
MiniHttpdApp is a web server sample application that demonstrates the MiniHttpd library. Although the GUI looks nearly the same, I've rewritten it from scratch for version 1.2.0 to address several crashing issues that were part of its crude design and lack of thread-safety consideration. It should now be stable enough to be a permanent resident of your Windows tray.
Specify a port and optionally the host name if you are behind a router or other NAT device, and then click Server -> Start. There are more options in the property grid on the left, most of them are self-explanatory.
With RootType
set to Drive
in the Directories
section of the left pane, you can specify a folder to share in the RootFolder
box. With RootType
set to Virtual
, you can drag and drop files and folders to share, and right click or press Delete to remove. Settings are saved to MiniHttpdAppSettings.xml.
MiniHttpdConsole
MiniHttpdConsole is a command-line demo project I made primarily to try MiniHttpd on Linux. The interface is primitive, with a somewhat nostalgic text-based menu system (maybe not so to Unix users) and command-line argument input. Entering "?" brings up a list of available menu items, and entering "h" brings up a list of available command-line arguments.
Aside the VirtualDirectory
format (which unfortunately is a base-64 encoded binary serialization of the root VirtualDirectory
due to .NET 1.1's incomplete XML serialization implementation), you can use the same config file for MiniHttpdApp with MiniHttpdConsole. Once you've set all your settings, you can run MiniHttpdConsole on Mono in the background doing the following:
mono MiniHttpdConsole.exe -s -l &
-s
specifies silent mode (no output, no menu); -l
turns on file logging to MiniHttpd.log.
Note that MiniHttpdConsole requires .NET 2.0 or Mono 1.1.10.
MSH is awesome
Microsoft is working on a new command-line shell for the Longhorn Server (and possibly Vista) called Microsoft Shell (Monad), a .NET-powered shell with type-safe pipes and a syntax borrowed from functional languages, SQL and Unix shells. I couldn't resist sharing the fact that I tried MiniHttpd through Monad. Note that I did this right in the shell, but this could almost as easily be made into a function (called a cmdlet) and saved to a cmdlet file:
> [Reflection.Assembly]::LoadFile($(combine-path
$(get-location) "minihttpd.dll"))
GAC Version Location
--- ------- --------
False v1.1.4322 C:\Documents and Settings\Rei Miyasaka\
My Documents\Visual Studio Proj...
>$server = new-object MiniHttpd.HttpWebServer
>$server.Root = new-object MiniHttpd.DriveDirectory($(get-location))
>$server.Start()
Server: MiniHttpd/1.2.0.92
CLR: 2.0.50727.42
Server running at http://rei/
Isn't that cool?!
Pseudo-legal stuff
I will bind MiniHttpd by the Creative Commons Attribution 2.5 license, which in a word says that you may use MiniHttpd for anything you want, however you want (including commercially, but with no warranty), so long as you credit me for the original work.
On the other hand, I'm a college student, and programming work here in Vancouver is not very well-paying despite being scarce. In my position, it's hard to justify working on anything that won't earn me at least something. So if you ever do find commercial use for MiniHttpd, a small donation would be appreciated to give me encouragement.
Also, please let me know if you use MiniHttpd for a project. It'd look good on my resume :)
Future updates
These are ideas for future versions, in no particular order, and with no particular deadline. I will increment a minor version number (1.x) each time I make a breaking change.
- Register HTTP handlers from web.config.
- Repair .NET Compact Framework compatibility.
- More debugging, especially ASPX.
- HTTPS support.
- Permissions and passwords.
- Per-directory MIME types and other settings.
- Upload cap/quota control.
- Chunked POST data.
- Improve PHP support.
- Try multiplexing instead of asynchronous IO (see article by Alexey Popov).
- Windows service.
- Custom error pages.
- Request handlers for better ASPX and PHP.
- Think of a better name.
- Use XML serialization for MiniHttpdApp in .NET 2.0.
- Use W3C Extended Log Format.
- Remote admin page.
- Rewrite the whole thing in Spec# for .NET 2.0.
Links
History
- 2004.12.20 - Beginning of project.
- 2005.08.18 - First release - version 1.0.0.
- 2005.08.18 - version 1.0.1 - I left some debug code in from last night... it would dump all of the headers from requests! Fixed.
- 2005.08.18 - version 1.0.2 - Server now listens on all addresses (including localhost) unless otherwise specified in the constructor or the
LocalAddress
property.
- 2005.08.20 - version 1.0.4 - MiniHttpdApp now starts in
Virtual
mode by default. Really bad bug - I forgot to implement the maximum POST size limit! Sorry. I checked all the other upload limits; everything else should be fine.
- 2005.08.22 - version 1.0.5 - Fixed a severe flaw where a user could enter a URL-encoded backslash to get access to the root folder, among other similar abuses. Please download this version if you are using anything prior. Made a few small improvements.
- 2005.09.17 - version 1.1.1 - Added ASPX support, fixed several small glitches, and made minor improvements. Added a transfer monitor to MiniHttpdApp.
- 2005.12.12 - version 1.2.0
- Several bug fixes.
IResource
now inherits IDisposable
; all IDirectory
s should call Dispose
on their containing resources.
- Advanced index page.
- MiniHttpdApp sample app rewritten with bug fixes and some improvements.
- Log to file support.
- Added MiniHttpdConsole sample app.
- All future versions will be ported to Visual Studio 2005 and .NET 2.0, with the exception of crucial bug fixes.
- Basic authentication.
- Basic PHP support.