Skip to content

Instantly share code, notes, and snippets.

@hellerve
Last active February 12, 2020 16:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hellerve/a926b4a0daed639dd9320fb52279cf4a to your computer and use it in GitHub Desktop.
Save hellerve/a926b4a0daed639dd9320fb52279cf4a to your computer and use it in GitHub Desktop.
A simple HTTP client
(load "git@github.com:carpentry-org/sockets@master")
(load "git@github.com:carpentry-org/http@master")
(load "https://veitheller.de/git/carpentry/cli@0.0.7")
(defn read-all [sock s]
(let [read (Socket.read sock)]
(if (= &read "")
(Response.parse &s)
(let [acc (String.concat &[s read])]
(match (Response.parse &acc)
(Result.Error msg) (do (IO.errorln &(fmt "Response: '%s'" &acc)) (Result.Error msg))
(Result.Success r)
(let [cl (Array.first &(Map.get (Response.headers &r) "Content-Length"))
l (Maybe.from (Maybe.apply cl &(fn [s] (Int.from-string &s))) 0)]
(if (<= l (length (Response.body &r)))
(Result.Success r)
(read-all sock acc))))))))
(defn main []
(let [p (=> (CLI.new @"A simple HTTP client.")
(CLI.add &(CLI.str "host" "h" "the host to visit" true))
(CLI.add &(CLI.str "url" "u" "the URL to visit" false @"/"))
(CLI.add &(CLI.bool "verbose" "v" "whether we should be verbose"))
(CLI.add &(CLI.str "verb" "e" "the verb to use" false @"GET"))
(CLI.add &(CLI.str "body" "b" "the body to send" false @""))
(CLI.add &(CLI.str "cookies" "c" "the cookies to send" false @""))
(CLI.add &(CLI.str "proto" "r" "the protocol to use" false @"http"))
(CLI.add &(CLI.int "port" "p" "the port to use" false 80l)))]
(match (CLI.parse &p)
(Result.Error err)
(do
(IO.errorln &err)
(CLI.usage &p))
(Result.Success args)
(let [host (str &(Map.get &args "host"))
url (str &(Map.get &args "url"))
verb (str &(Map.get &args "verb"))
verbose (CLI.Type.to-bool (Map.get &args "verbose"))
body (str &(Map.get &args "body"))
port (to-int (Map.get &args "port"))
proto (str &(Map.get &args "proto"))
cookies (str &(Map.get &args "cookies"))
c (if (/= &cookies "")
(Cookie.parse-many &cookies)
(Result.Success []))
]
(match (URI.parse &url)
(Result.Error err) (IO.errorln &err)
(Result.Success uri)
(match c
(Result.Error err) (IO.errorln &err)
(Result.Success cl)
(Socket.with-client-for sock &host &proto port
(if (Socket.valid? &sock)
(do
(let-do [res &(str &(Request.request verb uri cl {@"Host" [host] @"Content-Length" [(str (length &body))]} body))]
(when verbose (IO.println &(fmt "Request: %s" res)))
(Socket.send &sock res))
(match (read-all &sock @"")
(Result.Success r)
(if verbose
(IO.println &(str &r))
(IO.println (Response.body &r)))
(Result.Error msg) (IO.errorln &msg)))
(IO.errorln
&(fmt "Couldn’t connect to host %s on port %d." &host port))))))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment