Back to blog

SimpleHttp - a basic HTTP server framework written in C

I got bored last night so I started playing around with HttpListener and other relevant classes in the System.Net namespace, and I decided to write respective wrapper classes. The result: SimpleHttp.

For now I’ve included the release binary in the GitHub repository, but as the framework matures and becomes more stable, I’ll release it as a NuGet package.

Here’s the most simple usage of the framework:

using JamesWright.SimpleHttp;

namespace JamesWright.SimpleHttp.Example
{
    class Program
    {
        static void Main(string[] args)
        {
            App app = new App();

            app.Get("/", (req, res) =>
            {
                res.Content = "{ \"message\": \"Hello\" }";
                res.ContentType = "application/json";
                res.Send();
            });

            app.Get("/version", (req, res) =>
            {
                res.Content = "{ \"version\": \"0.1\" }";
                res.ContentType = "application/json";
                res.Send();
            });

            app.Start();
        }
    }
}

The App class bootstraps an internal Server class:

class Server
{
    private Listener listener;
    //contains four Dictionaries for GET, POST, PUT, and DELETE
    public RouteRepository RouteRepository { get; private set; }

    public Server(Listener listener, RouteRepository routeRepository)
    {
        this.listener = listener;
        RouteRepository = routeRepository;
    }

    public void Start(string port)
    {
        Console.Write("SimpleHttp server 0.2\n\n");
        Console.WriteLine("Initialising server on port {0}...", port);
        this.listener.Start(port, RouteRepository);
    }
}

Here’s the Listener class, used internally by Server to handle incoming requests:

class Listener
{
    private HttpListener httpListener;
    private HttpListenerContext context;

    public Listener()
    {
        this.httpListener = new HttpListener();
    }

    public void Start(string port, RouteRepository routeRepository)
    {
        this.httpListener.Prefixes.Add(string.Format("http://localhost:{0}/", port));
        this.httpListener.Start();

        Console.WriteLine("Listening for requests on port {0}.", port);

        Request request;

        while (TryGetNextRequest(out request))
        {
            Console.WriteLine("{0}: {1}", DateTime.Now, request.Endpoint);

            if (!TryRespond(request, routeRepository))
                Console.WriteLine("No handler specified for endpoint {0}.", request.Endpoint);
        }
    }

    private bool TryRespond(Request request, RouteRepository routeRepository)
    {
        if (!routeRepository.Get.ContainsKey(request.Endpoint))
            return false;

        routeRepository.Get[request.Endpoint](request, new Response(context.Response));
        return true;
    }

    private bool TryGetNextRequest(out Request request)
    {
        try
        {
            this.context = this.httpListener.GetContext();
            HttpListenerRequest httpRequest = this.context.Request;
            request = new Request(httpRequest);
            return true;
        }
        catch (Exception)
        {
            //TODO: output/log exception
            request = null;
            return false;
        }
    }
}

The Request and Response classes are simple wrappers around HttpListenerRequest and HttpListenerResponse. Listener retrieves the next request from the HttpListener’s GetContext() method, using the Routes Dictionary to find the appropriate handler and pass the original request, and a new Response instance, to the developer.

I look forward to improving it and ultimately make it as scalable as possible. I’ll post an update soon!