Last active
November 3, 2015 19:19
-
-
Save owskio/ba8968057e5f42116d3a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Heavily modified from: https://www.branded3.com/blog/creating-a-simple-http-server-with-f | |
open System; open System.Text; open System.IO; open System.Net | |
//Eliminate .NET line noise | |
type HttpListenerResponse with | |
member me.Close = me.OutputStream.Close | |
member me.WriteAsync str = Encoding.ASCII.GetBytes(s=str) |> me.OutputStream.AsyncWrite | |
type Uri with | |
member me.RelativeTo host = Uri(host).MakeRelativeUri(me).OriginalString | |
let (/) a b = Path.Combine(a,b) | |
//Config | |
let root,host = @"C:\GitHub\Nancy","http://localhost:8888/" | |
//Init the listener in a closure, Return an async block which has its '>>=' | |
//called for every request (it seems to me), yielding a 'context' | |
let listen = | |
let l = new HttpListener() | |
l.Prefixes.Add host | |
l.Start() //Called once upon definition of 'listen' | |
async { //Is accessed repeatedly, however | |
let b,e = l.BeginGetContext, l.EndGetContext | |
let! context = Async.FromBeginEnd(b, e) | |
return context.Request,context.Response | |
} | |
let loop requestHandler = | |
Async.Start <| async { //Non-blocking | |
while true do | |
let! request, response = listen //Get the context asynchronously | |
do! requestHandler(request,response) //Handle the context asynchronously | |
} | |
Console.ReadLine() |> ignore //Retain console for printfn | |
//Can be broken down further to reveal the usual String -> String | |
//development pattern of mapping request urls to response bodies | |
loop(fun(request,response) -> | |
async { | |
let relativePath = request.Url.RelativeTo host //Request routing | |
let file = root / relativePath //Request routing | |
printfn "REQUESTED: %A" file //Logging | |
response.StatusCode <- int HttpStatusCode.OK //Response packaging | |
response.ContentType <- "text/html" //Response packaging | |
do! if File.Exists file //Response handling | |
then File.ReadAllText file | |
else "File does not exist!" | |
|> response.WriteAsync | |
response.Close() //Resource management :-) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment