Skip to content

Instantly share code, notes, and snippets.

@pt2121
Last active February 19, 2021 06:29
Show Gist options
  • Save pt2121/ba50236ba83d93b61a80f04e5878fe81 to your computer and use it in GitHub Desktop.
Save pt2121/ba50236ba83d93b61a80f04e5878fe81 to your computer and use it in GitHub Desktop.
module HttpClient
import Control.App
import Network.Socket
import Types
public export
interface Has [Exception IOError] e => NetworkIO e where
getResponse : Request -> App e String
public export
requestLine : (req : Request) -> String
requestLine req =
show req.method ++ " " ++ req.path ++ " " ++ show req.httpVersion ++ "\r\n"
public export
headers : (req : Request) -> String
headers req = "Host: " ++ req.host ++ "\r\nConnection: close\r\n"
export
Has [PrimIO, Exception IOError] e => NetworkIO e where
getResponse r = do
Right socket <- primIO $ socket AF_INET Stream 0
| Left fail => throw $ GenericErr $ show fail
res <- primIO $ connect socket (Hostname r.host) r.port
if res /= 0
then throw $ GenericErr $ "res " ++ show res
else do
Right _ <- primIO $ send socket $ requestLine r ++ headers r ++ "\r\n"
| Left fail => throw $ GenericErr $ show fail
Right result <- primIO $ recvAll socket
| Left fail => throw $ GenericErr ""
pure result
public export
request : NetworkIO e => Request -> App e String
request r = getResponse r
module Main
import Control.App
import Control.App.Console
import HttpClient
import Types
reqMain : App Init ()
reqMain = handle (request (MkRequest GET False http1_1 "www.neverssl.com" 80 "/" ""))
(\str => putStrLn $ "Response:\n" ++ show str)
(\err : IOError => putStrLn $ "Error: " ++ show err)
main : IO ()
main = run reqMain
module Types
import Data.Strings
import Network.Socket
public export
data Method = GET | POST
export
Show Method where
show GET = "GET"
show POST = "POST"
export
Eq Method where
m1 == m2 = show m1 == show m2
public export
record HttpVersion where
constructor MkHttpVersion
major : Int
minor : Int
export
Show HttpVersion where
show v = "HTTP/" ++ show v.major ++ "." ++ show v.minor
export
http1_0 : HttpVersion
http1_0 = MkHttpVersion 1 0
export
http1_1 : HttpVersion
http1_1 = MkHttpVersion 1 1
export
http2_0 : HttpVersion
http2_0 = MkHttpVersion 2 0
public export
record Request where
constructor MkRequest
method : Method
secure : Bool
httpVersion : HttpVersion
host : String
port : Int
path : String
queryString : String
export
Show Request where
show r = unlines
[ "Request {"
, " method = " ++ show r.method
, " secure = " ++ show r.secure
, " httpVersion = " ++ show r.httpVersion
, " host = " ++ r.host
, " port = " ++ show r.port
, " path = " ++ r.path
, " queryString = " ++ r.queryString
, "}"
]
public export
record Status where
constructor MkStatus
statusCode : Int
statusMessage : String
export
Show Status where
show s = "Status { " ++ show s.statusCode ++ ", " ++ s.statusMessage ++ " }"
public export
record Response responseBody where
constructor MkResponse
status : Status
version : HttpVersion
body : responseBody
export
printResponse : (Response responseBody)
-> (responseBody -> String)
-> String
printResponse r f = unlines
[ "Response {"
, " status = " ++ show r.status
, " version = " ++ show r.version
, " responseBody = " ++ f r.body
, "}"
]
public export
data HttpError : Type where
HttpSocketError : SocketError -> HttpError
export
Show HttpError where
show (HttpSocketError err) = show err
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment