basic http server
This commit is contained in:
2
srv/http_utils/__init__.hy
Normal file
2
srv/http_utils/__init__.hy
Normal file
@ -0,0 +1,2 @@
|
||||
(import http-utils.request)
|
||||
(import http-utils.response)
|
57
srv/http_utils/request.hy
Normal file
57
srv/http_utils/request.hy
Normal file
@ -0,0 +1,57 @@
|
||||
(import hyrule.collections [assoc])
|
||||
(require hyrule.control [branch])
|
||||
(require hyrule.argmove [doto])
|
||||
(require hyrule.collections :readers [s])
|
||||
(import urllib.parse [urlsplit unquote-plus parse-qs])
|
||||
|
||||
(defn parse-url-encoded [query]
|
||||
(dfor pair (.items (parse-qs (unquote-plus query) :keep-blank-values True))
|
||||
(get pair 0)
|
||||
(cond
|
||||
(get pair 1 0) (get pair 1 0)
|
||||
True "")))
|
||||
|
||||
(defn parse-data [data]
|
||||
(setv request {})
|
||||
|
||||
(setv [head #* body] (.split data b"\r\n\r\n"))
|
||||
(setv [request-line #* headers] (.split head b"\r\n"))
|
||||
(setv [http-method route http-version] (.split (.decode request-line "utf-8") " "))
|
||||
|
||||
(doto request
|
||||
(assoc :method http-method)
|
||||
(assoc :route (let
|
||||
[[_ _ path query _] (urlsplit route)]
|
||||
(dict
|
||||
:path (.join "/"
|
||||
(do
|
||||
(setv segments [])
|
||||
(for [segment (.split (unquote-plus path) "/")]
|
||||
(cond
|
||||
(!= segment "..") (.append segments segment)
|
||||
(and segments (!= (get segments -1) "..")) (.pop segments)))
|
||||
|
||||
segments))
|
||||
|
||||
:parameters (parse-url-encoded query))))
|
||||
|
||||
(assoc :version http-version)
|
||||
(assoc :headers (dict
|
||||
(dfor header
|
||||
(map (fn [x]
|
||||
(.split (.decode x "utf-8") ": ")) headers)
|
||||
(get header 0)
|
||||
(get header 1))))
|
||||
|
||||
|
||||
(assoc :body (branch (in it (. request (get "headers") (get "Content-Type" "")))
|
||||
"application/x-www-form-urlencoded" (parse-url-encoded (.decode (.join b"\n" body) "utf-8"))
|
||||
"" ""
|
||||
;;"multipart/form-data" ;(do
|
||||
;; (setv content-type-header (. request (get "headers") (get "Content-Type")))
|
||||
;; (when (in "=" content-type-header) (do
|
||||
;; (setv boundary (get (.split content-type-header "=") -1))
|
||||
;; (print "boundary" boundary)
|
||||
;; (print (.split (.join b"\n" body) (.encode boundary "utf-8"))))))
|
||||
else (raise (NotImplementedError f"{(get (.split (. request (get "headers") (get "Content-Type")) ";") 0)} parsing is TODO"))))))
|
||||
|
26
srv/http_utils/response.hy
Normal file
26
srv/http_utils/response.hy
Normal file
@ -0,0 +1,26 @@
|
||||
(import hyrule.collections [assoc])
|
||||
|
||||
(defn send-code [code]
|
||||
(.encode f"HTTP/1.1 {code}\r\n" "utf-8"))
|
||||
|
||||
(defn send-headers [headers]
|
||||
(.encode (+ (.join "\r\n" (lfor [k v] (.items headers) f"{k}: {v}")) "\r\n\r\n") "utf-8"))
|
||||
|
||||
(defn send-body [body]
|
||||
(cond
|
||||
(isinstance body bytes) body
|
||||
(isinstance body str) (.encode body "utf-8")))
|
||||
|
||||
(defn send [[code 200] [headers None] [body ""]]
|
||||
(when (is headers None)
|
||||
(setv headers {}))
|
||||
|
||||
(assoc headers "WHAT...-your-trans-gener..." "that is so cool...")
|
||||
|
||||
(when (not-in "Content-Type" headers)
|
||||
(assoc headers "Content-Type" "text/html"))
|
||||
|
||||
(+
|
||||
(send-code code)
|
||||
(send-headers headers)
|
||||
(send-body body)))
|
Reference in New Issue
Block a user