Last active
February 12, 2020 16:04
-
-
Save hellerve/a926b4a0daed639dd9320fb52279cf4a to your computer and use it in GitHub Desktop.
A simple HTTP client
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(load "[email protected]:carpentry-org/sockets@master") | |
(load "[email protected]:carpentry-org/http@master") | |
(load "https://veitheller.de/git/carpentry/[email protected]") | |
(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