6

I'm creating a static file server in Clojure with Compojure and I'm stuck on reading an image from the filesystem and displaying that image through a Compojure route.

slurp unfortunately doesn't handle binary data very well, and I've tried this 100 different ways since, but this is my latest failed attempt:

(defn image-output [filepath]
  (try
    (let [contents (apply str (with-open [rdr (io/reader filepath)]
      (into #{} (line-seq rdr))))]
      {
        :status 200
        :headers 
        {
          "Content-Type" "image/jpeg", 
          "Content-Length" "",
          "Cache-Control" "",
          "Expires" ""
        }
        :body contents
      }))
    (catch Exception e {:status 404})))

(defn endpoint_view [params]
  (if (contains? params :bucket)
    (image-output (join "/" [data_path (:bucket params) (:dir params) (:filename params)]))))

(defroutes main-routes
  (GET "/view/:bucket/:dir/:filename" {params :params} (endpoint_view params))
  (route/files "/")
  (route/resources "/s" {:root "./public/s"})
  (route/not-found "Page not found"))

It seems this current attempt suffers the same fate as using slurp, where I can echo the contents string and it's and encoded string, but when I change the content-type to image/jpeg it's a broken image.

I spent all day yesterday Google searching, but none of the examples accomplished the same goal, and while they helped me understand a little more about Java IO, they weren't clear enough to help me get where I needed to go, or produced the same results I was already getting (example: Best way to read contents of file into a set in Clojure).

(Imaginary bonus points if you can tell me how to get the content type from the filepath as well as that's my next question!)

1 Answer 1

7

Just make the body be (io/file filepath) - Ring is perfectly happy to serve files for you.

Edit for bonus points: you can use ring.middleware.file-info/wrap-file-info to get file metadata for the files you return. Or, you could just serve a whole directory with (compojure.route/files "/public"), which does all this mess for you.

Sign up to request clarification or add additional context in comments.

2 Comments

Well damn. You are correct sir! I'd still be interested in knowing how to read binary data in to a string though as I killed a day trying to figure it out, but this solves my immediate problem. Thanks!
Don't do it. Strings are not binary, nothing good will come of this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.