babashka/examples/http_server_from_scratch.clj

64 lines
3.2 KiB
Clojure
Raw Normal View History

2020-01-06 12:22:43 +00:00
#!/usr/bin/env bb
2021-03-09 09:58:27 +00:00
;; This example creates a file serving web server from scratch.
;; It accepts a single connection from a browser and serves content to the connected browser
;; after the connection times out, this script will serve no more.
2020-09-23 12:32:11 +00:00
;; Also see notes.clj for another web app example.
2021-03-09 09:58:27 +00:00
;; Note that babashka comes with org.httpkit.server now, so you don't need to
;; build an http server from scratch anymore. We leave this script here for educational purposes.
2020-01-06 12:22:43 +00:00
(import (java.net ServerSocket))
2020-09-23 12:32:11 +00:00
(require '[clojure.java.io :as io]
'[clojure.string :as string])
2020-01-06 12:22:43 +00:00
(with-open [server-socket (new ServerSocket 8080)
client-socket (.accept server-socket)]
(loop []
(let [out (io/writer (.getOutputStream client-socket))
in (io/reader (.getInputStream client-socket))
2020-09-23 12:32:11 +00:00
[req-line & _headers] (loop [headers []]
(let [line (.readLine in)]
(if (string/blank? line)
headers
(recur (conj headers line)))))
2020-01-06 12:22:43 +00:00
[_ _ path _] (re-find #"([^\s]+)\s([^\s]+)\s([^\s]+)" req-line)
f (io/file (format "./%s" path))
status (if (.exists f)
200
404)
html (fn html-fn [tag & body]
(let [attrs? (map? (first body))
attrs-str (str (when attrs?
(format " %s" (string/join " " (for [[k v] (first body)]
(format "%s=%s" (name k) (name v)))))))]
(format "<%s%s>%s</%s>"
(name tag)
attrs-str
(string/join (if attrs? (rest body) body))
(name tag))))
body (cond
(not (.exists f)) (str path " not exist")
2020-01-06 12:22:43 +00:00
(.isFile f) (slurp f)
(.isDirectory f) (format "<!DOCTYPE html>\n%s"
(html :html
(html :head
(html :title path))
(html :body
(html :h1 path)
(html :tt
(apply html :pre
(for [i (.list f)]
(html :div
2020-09-23 12:32:11 +00:00
(html
:a
{:href
(str (when (> (count path) 1) path) "/" i)} i)))))))))]
2020-01-06 12:22:43 +00:00
(prn path)
(.write out (format "HTTP/1.1 %s OK\r\nContent-Length: %s\r\n\r\n%s"
status
(count body)
body))
(.flush out))
(recur)))