Here I am going to show how to use F# to write an HTTP request using the TcpClient classes. This is nice way to get in a little deeper and be able to tune/optimze further and just implement the bare minimum you need.
First, let’s get the method setup and include the namespaces we will need. In the method we will create 3 mutable variables to hold the HttpStatus code, header text, and body text – these values will be returned as a tuple at the end of the method.
open System
open System.IO
open System.Net
open System.Net.Sockets
open System.Text
open System.Collections.Generic
module mod_http =
let SendHTTPCall (url:string, httpMethod:string, userAgent:string, body:string) =
let mutable httStatusCode = HttpStatusCode.OK
let mutable headerText = ""
let mutable bodyText = ""Now let’s get the code in place to send out the request. Note the call at the end of this block waiting for “DataAvailable” to become true.
let URL = new Uri(url)
let sblog = new StringBuilder()
use log = new StringWriter(sblog)
let sb = new StringBuilder()
sb.AppendFormat("{0} {1}{2} HTTP/1.1", httpMethod, URL.LocalPath, URL.Query) |> ignore
sb.Append(Environment.NewLine) |> ignore
sb.AppendFormat("User-Agent: {0}", userAgent) |> ignore
sb.Append(Environment.NewLine) |> ignore
sb.AppendFormat("Host: {0}", URL.Host) |> ignore
sb.Append(Environment.NewLine) |> ignore
sb.AppendFormat("Connection: {0}", "Close") |> ignore
sb.Append(Environment.NewLine) |> ignore
sb.AppendFormat("Date: {0}", DateTime.Now.ToString("r")) |> ignore
sb.Append(Environment.NewLine) |> ignore
sb.Append(Environment.NewLine) |> ignore
let message = sb.ToString()
use client = new TcpClient(URL.Host, URL.Port)
let stream = client.GetStream()
let bytes = Encoding.ASCII.GetBytes(message)
stream.Write(bytes, 0, bytes.Length)
stream.Flush()
let mutable waitCount = 0
let mutable cndDA = false
while not stream.DataAvailable do
ignore()Now we need to parse out the output and return the results. Again, this will return the HttpStatusCode and the strings for the header and body text.
use rdr = new StreamReader(stream)
let sOut = rdr.ReadToEnd()
let sbheaders = new StringBuilder()
use sr = new StringReader(sOut)
bodyText <- sr.ReadToEnd()
headerText <- sbheaders.ToString()
if headerText.StartsWith("HTTP/1.1 200 OK") then
httStatusCode <- HttpStatusCode.OK;
else
httStatusCode <- HttpStatusCode.ServiceUnavailable;
client.Close()
(httStatusCode, headerText, bodyText)Now this is complete and already to start to using it. A lot of the time I would take this approach again is if I have very specific work I am doing over HTTP that would require a certain level of output logging, or specific specific control over the request/response actions that would make it simpler to have this grain of control.