awwx.ws

post2

simple HTTP POST

http://awwx.ws/post2.arc:

(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.

Prerequisites

This hack depends on arc3.1, client-socket1, re3, parseurl0, binary1, read-headers0, and encodequery0.

License

Same as Arc.

Contact me

Twitter: awwx
Email: andrew.wilcox [at] gmail.com