Login
7 branches 0 tags
Ben (MBA M2) Revert "WIP root-closure serialization" d34dd5f 2 years ago 1126 Commits
nujel / binlib / net.nuj
(defn http/req* (verb host path header)
      (set! header (if header (:clone header) {}))
      (set! header :Host host)
      (set! header :Connection "close")
      (set! header :User-Agent "Nujel/0.1")
      (def header-lines (join (map (:keys header)
                                   (fn (k) (fmt "{}: {}"
                                                (:string k)
                                                (:string (ref header k)))))
                              "\r\n"))
      (def req (fmt "{verb} {path} HTTP/1.1\r\n{header-lines}\r\n\r\n"))

      (def buf (buffer/allocate 0))
      (def fh (socket/connect host 80))
      (file/write* fh req (:length req))
      (file/flush* fh)
      (def bytes-read 0)
      (def bytes-read-now 1)
      (while (not (zero? bytes-read-now))
        (:length! buf (+ 65536 (:length buf)))
        (set! bytes-read-now (file/read* fh buf 65536 bytes-read))
        (set! bytes-read (+ bytes-read bytes-read-now)))
      (file/close* fh)

      (def raw-res (buffer->string buf bytes-read))
      (def eosl (:index-of raw-res "\r\n"))
      (when (< eosl 0) (return #nil))
      (def eoh (:index-of raw-res "\r\n\r\n"))
      (when (< eoh 0) (return #nil))

      (def headers {})
      (def body (:cut buf (+ 4 eoh)))
      (def status-list (split (buffer->string buf eosl) " "))
      (def status-code (read/int (cadr status-list)))
      (doseq (header (split (buffer->string buf eoh (+ 2 eosl)) "\r\n"))
             (def eok (:index-of header ":"))
             (when (>= eok 0)
               (def key (:keyword (:cut header 0 eok)))
               (def v (trim (:cut header (inc eok))))
               (set! headers key v)))

      { :http-version (car status-list)
        :status-code status-code
        :status-message (join (cddr status-list) " ")
        :headers headers
        :body body})

(defn http/get (url)
      (when (>= (:index-of url "https://") 0)
        (error "https is unsupported right now"))
      (when (>= (:index-of url "http://") 0)
        (set! url (:cut url 7))
        (def path-start (:index-of url "/"))
        (return (if (>= path-start 0)
                    (http/req* "GET"
                               (:cut url 0 path-start)
                               (:cut url path-start))
                    (http/req* "GET" url "/"))))
      (error "unsupported scheme"))

(defn http/wget (url filename)
      (when-not filename
                (set! filename (car (last-pair (split url "/")))))
      (def res (http/get url))
      (when (> (ref res :status-code) 299)
        (error "Couldn't download file" url))
      (file/write (ref res :body) filename))