From c1c1ffde7027e06b7f14ed636b00ddc897f1a798 Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Mon, 13 Feb 2017 19:43:02 +0100 Subject: [PATCH] Extend FileServer to accept options (:expires, :filename) --- src/asciinema/boundary/file_server.clj | 2 +- src/asciinema/component/local_file_server.clj | 7 ++++- src/asciinema/component/s3_file_server.clj | 29 +++++++++++++++++-- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/asciinema/boundary/file_server.clj b/src/asciinema/boundary/file_server.clj index 8fb06bd..c380724 100644 --- a/src/asciinema/boundary/file_server.clj +++ b/src/asciinema/boundary/file_server.clj @@ -1,4 +1,4 @@ (ns asciinema.boundary.file-server) (defprotocol FileServer - (serve [this path])) + (serve [this path] [this path opts])) diff --git a/src/asciinema/component/local_file_server.clj b/src/asciinema/component/local_file_server.clj index 4dbeaa9..70b6df7 100644 --- a/src/asciinema/component/local_file_server.clj +++ b/src/asciinema/component/local_file_server.clj @@ -6,7 +6,12 @@ (defrecord LocalFileServer [file-store] file-server/FileServer (serve [this path] - (response/ok (file-store/input-stream file-store path)))) + (file-server/serve this path {})) + (serve [this path {:keys [filename]}] + (let [resp (response/ok (file-store/input-stream file-store path))] + (if filename + (response/header resp "Content-Disposition" (str "attachment; filename=" filename)) + resp)))) (defn local-file-server [{:keys [file-store]}] (->LocalFileServer file-store)) diff --git a/src/asciinema/component/s3_file_server.clj b/src/asciinema/component/s3_file_server.clj index c4163a7..5529922 100644 --- a/src/asciinema/component/s3_file_server.clj +++ b/src/asciinema/component/s3_file_server.clj @@ -1,15 +1,38 @@ (ns asciinema.component.s3-file-server (:require [asciinema.boundary.file-server :as file-server] [aws.sdk.s3 :as s3] - [ring.util.http-response :as response])) + [clj-time.core :as time] + [clj-time.coerce :as timec] + [ring.util.http-response :as response]) + (:import com.amazonaws.services.s3.model.ResponseHeaderOverrides + com.amazonaws.services.s3.AmazonS3Client + com.amazonaws.auth.BasicAWSCredentials + com.amazonaws.services.s3.model.GeneratePresignedUrlRequest)) -;; TODO support custom expiry date (it's 1 day now) +(defn- s3-client* [cred] + (let [credentials (BasicAWSCredentials. (:access-key cred) (:secret-key cred))] + (AmazonS3Client. credentials))) + +(def ^:private s3-client (memoize s3-client*)) + +(defn- generate-presigned-url [cred bucket path {:keys [expires filename] + :or {expires (-> 1 time/days time/from-now)}}] + (let [client (s3-client cred) + request (GeneratePresignedUrlRequest. bucket path)] + (.setExpiration request (timec/to-date expires)) + (when filename + (let [header-overrides (doto (ResponseHeaderOverrides.) + (.setContentDisposition (str "attachment; filename=" filename)))] + (.setResponseHeaders request header-overrides))) + (.toString (.generatePresignedUrl client request)))) (defrecord S3FileServer [cred bucket path-prefix] file-server/FileServer (serve [this path] + (file-server/serve this path {})) + (serve [this path opts] (let [path (str path-prefix path)] - (response/found (s3/generate-presigned-url cred bucket path))))) + (response/found (generate-presigned-url cred bucket path opts))))) (defn s3-file-server [{:keys [cred bucket path-prefix]}] (->S3FileServer cred bucket path-prefix))