(def connect (url)
((case url!scheme
http socket-connect
https ssl-connect
(err (string "don't know how to connect to URL scheme " url!scheme) url))
url!host
(or url!port
(case url!scheme
http 80
https 443
(err (string "don't know the default port for URL scheme " url!scheme) url)))))
(mac close-after (s . body)
`(after (do ,@body)
(close s)))
(def parse-http-resp-header (lines)
(w/table r
(let status-line (tokens lines.0)
(= r!version (begins-rest "HTTP/" status-line.0))
(= r!status (errsafe:int status-line.1))
(= r!message status-line.2))
(= r!headers
(map [re-match "^([-\\w]+)\\s*:\\s*(.*)" _] cdr.lines))
(= r!content-length
(aif (alref r!headers "Content-Length") (errsafe:int it)))))
(def crlf xs
(each x xs (pr x))
(pr "\r\n"))
(def post (url headers content onresp)
(with (url (if (isa url 'table) url (parse-url url))
content (binary content))
(let (i o) (connect url)
(after
(do (w/stdout o
(crlf "POST " url!path " HTTP/1.0")
(crlf "Host: " url!hostport)
(crlf "Content-Length: " len.content)
(each header headers
(if (alist header)
(crlf header.0 ": " header.1)
(crlf header)))
(crlf)
(pr content)
(flushout))
(let r (parse-http-resp-header (read-headers i))
(onresp r i)))
(do (close i)
(close o))))))
(def mustbe200 (onresp)
(fn (r i)
(unless (is r!status 200) (err r!status))
(onresp r i)))
(def postform (url args onresp)
(post url
'((Content-Type application/x-www-form-urlencoded))
(encodequery args)
(mustbe200 onresp)))
This hack does just enough to implement making HTTP POST requests, allowing the caller to read the request response directly from the socket. For a more general purpose HTTP client implementation, see Mark Huetsch’s web.arc in Anarki.
This hack depends on arc3.1, client-socket1, re3, parseurl0, binary1, read-headers0, and encodequery0.
Same as Arc.