Skip to content
heff

std.http

For HTTP requests: a request sent, and its response, or why none came. The C backend’s alone: libcurl in the process, loaded at the first request, or a curl spawned where there is none, with the same answers; a page’s fetch is browser.http’s. Import it by a name, import std.http as HTTP, as its names are common ones: HTTP.get, HTTP.send.

import co
import std.http as HTTP
-- | the response's status, or 0 where none came
upload : {e : HFunctor} -> {{web : HTTP.http <: e}} -> Bytes -> Co e Int
upload b = do
r <- HTTP.send
{ url = "http://localhost:8080/up"
, method = "POST"
, body = b
, timeout = 5000
, connectTimeout = 1000
}
pure (either (\err -> 0) (\(res : Http.Response) -> res.status) r)

A response is whatever the server answered, a 404 or a 500 too; an error is that no response came — the connection refused, the name not found, TLS, the time up — with curl’s code, what it says, and the URL.

Request

type Request =
{ url : String
, method : String = "GET"
, headers : List (String, String) = []
, body : Bytes = Bytes.empty
, timeout : Int = 0
, connectTimeout : Int = 0
, follow : Bool = True
}

A request: where it goes, its method, its headers (a name and a value each, sent in their order), its body, how long it may take in all in milliseconds (0: as long as it takes), how long its connection may take to be made (0: as long as curl’s default, five minutes) — a server that does not answer given up on soon, a long download, once connected, not cut — and whether a redirect is followed (up to 50 of them) or is the response. A body is sent with a POST, or with any method where it is not empty, and with no Content-Type but the one in its headers. Either time up is curl’s code 28.

Response

type Response = { status : Int, headers : List (String, String), body : Bytes }

A response: its status, its headers (a name and a value each, as the server wrote them, of the last response where a redirect was followed), and its body.

HttpError

type HttpError = { code : Int, message : String, url : String }

Why no response came: curl’s code (7, a connection refused; 28, the time up), what it says of it, and the URL the request was for; for getText, a status not 2xx too (22, as curl --fail says it).

HttpF

data HttpF (m : Type -> Type) x = Send Request (Either HttpError Response -> x)

http

http : HFunctor

For HTTP requests sent, and their responses, by libcurl.

send

send : {e : HFunctor}
-> {{ev : http <: e}}
-> Request
-> Co e (Either HttpError Response)

The request sent: its response, or why none came.

get

get : {e : HFunctor}
-> {{ev : http <: e}}
-> String
-> Co e (Either HttpError Response)

A GET of the URL.

text

text : Response -> String

The body as text: UTF-8, what is not UTF-8 U+FFFD.

>>> text { status = 200, headers = Nil, body = Bytes.fromList [104, 105, 255] }
"hi\u{FFFD}"

textOf

textOf : String -> Either HttpError Response -> Either HttpError String

getText

getText : {e : HFunctor}
-> {{ev : http <: e}}
-> String
-> Co e (Either HttpError String)

A GET of the URL: its body as text where its status is 2xx; an error, code 22, where it is another (get has every response), or where no response came.

lowerByte

lowerByte : Int -> Int

sameName

sameName : String -> String -> Bool

headerIn

headerIn : String -> List (String, String) -> Maybe String
header : String -> Response -> Maybe String

The first header of that name, its case not minded (an ASCII name’s), if there is one.

>>> header "content-type" { status = 200, headers = [MkPair "Content-Type" "text/plain"], body = Bytes.empty }
Just "text/plain"

instanceShowHttpError

instance instanceShowHttpError : Show HttpError

As curl’s tool says it, the URL first: http://localhost:1/: curl: (7) Failed to connect ....

>>> show ({ code = 28, message = "Operation timed out", url = "http://localhost:8080/up" } : HttpError)
"http://localhost:8080/up: curl: (28) Operation timed out"