Skip to content

Instantly share code, notes, and snippets.

@Hendekagon
Created September 28, 2017 09:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hendekagon/7ab2c5c706dde70268f030c07550abe5 to your computer and use it in GitHub Desktop.
Save Hendekagon/7ab2c5c706dde70268f030c07550abe5 to your computer and use it in GitHub Desktop.
add 206 partial content in Aleph
; ---- the following fns copied from ring.util.response because they were
; useful but private ----
(defn canonical-path [^File file]
(str (.getCanonicalPath file)
(if (.isDirectory file) File/separatorChar)))
(defn safe-path? [^String root ^String path]
(.startsWith (canonical-path (File. root path))
(canonical-path (File. root))))
(defn directory-transversal?
"Check if a path contains '..'."
[^String path]
(-> (str/split path #"/|\\")
(set)
(contains? "..")))
(defn find-file-named [^File dir ^String filename]
(let [path (File. dir filename)]
(if (.isFile path)
path)))
(defn find-file-starting-with [^File dir ^String prefix]
(first
(filter
#(.startsWith (.toLowerCase (.getName ^File %)) prefix)
(.listFiles dir))))
(defn find-index-file
"Search the directory for an index file."
[^File dir]
(or (find-file-named dir "index.html")
(find-file-named dir "index.htm")
(find-file-starting-with dir "index.")))
(defn safely-find-file [^String path opts]
(if-let [^String root (:root opts)]
(if (or (safe-path? root path)
(and (:allow-symlinks? opts) (not (directory-transversal? path))))
(File. root path))
(File. path)))
(defn find-file [^String path opts]
(if-let [^File file (safely-find-file path opts)]
(cond
(.isDirectory file)
(and (:index-files? opts true) (find-index-file file))
(.exists file)
file)))
(defn content-length [resp len]
(if len
(rr/header resp "Content-Length" len)
resp))
; ---- handle 206 partial content requests
(defn partial-file-data [^File file from lenth]
(info " partial file:" from lenth)
(let [
f (RandomAccessFile. file "r")
c (.getChannel f)
b (.map c FileChannel$MapMode/READ_ONLY from lenth)
]
(try
(bs/to-byte-array b)
(finally (.close c)))))
; "bytes=500-999"
(defn parse-range [s]
(debug "parse range " s)
(let [[_ & s] (string/split s #"=|-")]
(map (fn [s] (Long/parseLong s)) s)))
(defn partial-file-response
[root {{uuid :uuid pfrom :from pto :to} :params :as req}]
(debug (str "partial file request " root req))
(let [filepath (str root uuid) opts nil]
(if-let [file (find-file filepath opts)]
(let [
total-length (.length file)
range-str (get-in req [:headers "Range"])
[from to]
(if range-str
(parse-range range-str)
(if (and pfrom pto)
(map (fn [s] (Long/parseLong s)) [pfrom pto])
[0 total-length]))
to (min (or to total-length) total-length)
from (max 0 (or from 0))
lenth (- to from)
]
(debug "206 range" from to lenth )
(if (> to from)
(let [data (partial-file-data file from lenth)]
{:status 206
:headers
{
"Content-Length" lenth
"Content-Range" (str "bytes " from "-" to "/" total-length)
}
:body data})
{:status 400 :body "invalid range"})))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment