Advertisement
Guest User

Untitled

a guest
Jul 2nd, 2017
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. module WebSockets
  2.  
  3. open System
  4. open System.IO
  5. open System.Net
  6. open System.Net.Sockets
  7. open System.Security
  8. open System.Text
  9. open System.Threading
  10.  
  11. type TcpListener with
  12.     member this.AsyncAcceptTcpClient() =
  13.         Async.FromBeginEnd(this.BeginAcceptTcpClient, this.EndAcceptTcpClient)
  14.  
  15. #nowarn "25"
  16. type HttpRequest =
  17.   { headers:Map<string, string>;
  18.     body:byte[] } with
  19.       static member fromStream(stream:NetworkStream) =
  20.           let bytes = Array.create 4096 0uy
  21.           let bytesReadCount = stream.Read(bytes, 0, bytes.Length)
  22.           let header = Encoding.UTF8.GetString(bytes.[0..bytesReadCount - 9])
  23.           let lines = header.Split([|"\r"; "\n"|], StringSplitOptions.RemoveEmptyEntries)
  24.           let kvs = lines.[1..lines.Length - 1]
  25.                     |> Array.map (fun s -> s.Split([|":"|], 2, StringSplitOptions.RemoveEmptyEntries))
  26.                     |> Array.map (function [|k; v|] -> (k.Trim(), v.Trim()) | _ -> ("Unknown", "Unknown"))
  27.           { headers = new Map<string, string>(kvs);
  28.             body = bytes.[bytesReadCount - 8 .. bytesReadCount - 1] }
  29.  
  30. let (|WebSocketRequest|_|) (r:HttpRequest) =
  31.     if r.headers.["Upgrade"] = "WebSocket" && r.headers.["Connection"] = "Upgrade"
  32.     then Some (r.headers.["Sec-WebSocket-Key1"], r.headers.["Sec-WebSocket-Key2"], r.body)
  33.     else None
  34.  
  35. let computeKey (k:string) =
  36.     let aux (sb:StringBuilder, cnt:int) = function
  37.         | ' ' -> (sb, cnt + 1)
  38.         | c -> if Char.IsDigit(c) then (sb.Append(c), cnt) else (sb, cnt)
  39.     let (n, c) = k.ToCharArray() |> Array.fold aux (new StringBuilder(), 0)
  40.     Int64.Parse(n.ToString()) / int64(c) |> int
  41.  
  42. let keyBytes (k:int) = k |> BitConverter.GetBytes |> Array.rev
  43.  
  44. let challenge (k1:string) (k2:string) (body:byte[]) =
  45.     let k1 = computeKey k1
  46.     let k2 = computeKey k2
  47.     use md5 = Cryptography.MD5.Create()
  48.     md5.ComputeHash(Array.concat([keyBytes k1; keyBytes k2; body]))
  49.  
  50. let handleClient (stream:NetworkStream) = async {
  51.     try
  52.         while true do
  53.             let buf = Encoding.UTF8.GetBytes("hello")
  54.             stream.WriteByte(0x00uy)
  55.             stream.Write(buf, 0, buf.Length)
  56.             stream.WriteByte(0xffuy)
  57.             do! Async.Sleep(1000)
  58.     with
  59.         | :? IOException -> stream.Close()
  60. }
  61.  
  62. let handleRequest (client:TcpClient) = async {
  63.     let stream = client.GetStream()
  64.     let request = HttpRequest.fromStream(stream)
  65.     match request with
  66.     | WebSocketRequest (k1, k2, body) ->
  67.         let response = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" +
  68.                        "Upgrade: WebSocket\r\n" +
  69.                        "Connection: Upgrade\r\n" +
  70.                        "Sec-WebSocket-Origin: " + request.headers.["Origin"] + "\r\n" +
  71.                        "Sec-WebSocket-Location: ws://localhost:8080/test\r\n\r\n"
  72.         let buf = Array.append (Encoding.UTF8.GetBytes(response)) (challenge k1 k2 body)
  73.         do! stream.AsyncWrite(buf, 0, buf.Length)
  74.         stream.WriteByte(0x0auy)
  75.         let buf = Encoding.UTF8.GetBytes("hello")
  76.         stream.WriteByte(0x00uy)
  77.         stream.Write(buf, 0, buf.Length)
  78.         stream.WriteByte(0xffuy)
  79.         client.Close()
  80.         //return! handleClient stream
  81.     | _ -> client.Close()
  82. }
  83.  
  84. let startServer port =
  85.     let listener = new TcpListener(IPAddress.Any, port)
  86.     let stop = ref false
  87.  
  88.     let main = async {
  89.         listener.Start(50)
  90.         printfn "Server started..."
  91.         while not !stop do
  92.             let! client = listener.AsyncAcceptTcpClient()
  93.             Async.Start <| handleRequest client
  94.     }
  95.  
  96.     Async.Start(main)
  97.     { new IDisposable with
  98.         member this.Dispose() = stop := true }
  99.  
  100. let main () =
  101.     use server = startServer 8080
  102.     Console.ReadKey() |> ignore
  103.  
  104. do main ()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement