-
Notifications
You must be signed in to change notification settings - Fork 23
/
add_cache_busted_expires_headers.clj
82 lines (67 loc) · 3.04 KB
/
add_cache_busted_expires_headers.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
(ns optimus.optimizations.add-cache-busted-expires-headers
(:require [cemerick.url :as url]
[clojure.set :as set]
[clojure.string :as str]
[optimus.assets :refer [original-path]]
[optimus.digest :as digest]
[optimus.paths :as paths]
[optimus.time :as time])
(:import [java.time ZonedDateTime ZoneId]
[java.time.format DateTimeFormatter]))
(defn- get-contents [file]
(or (:contents file)
(slurp (:resource file))))
(defn- add-cache-busted-expires-header [file]
(-> file
(assoc :path (str (paths/just-the-path (:path file))
(subs (digest/sha-1 (get-contents file)) 0 12)
\/
(paths/just-the-filename (:path file))))
(assoc :original-path (original-path file))
(assoc-in [:headers "Cache-Control"] "max-age=315360000")
(assoc-in [:headers "Expires"] (time/format-http-date
(.plusYears (time/now) 10)))))
(defn- by-path [path files]
(first (filter #(= path (:path %)) files)))
(defn qualify-url [{:keys [base-url context-path path]}]
(cond->> path
context-path (str context-path)
base-url (str (:path (url/url base-url)))))
(defn inverse-string-length [^String s]
(- (.length s)))
(defn- replace-referenced-url [file old new]
(update-in file [:contents] #(str/replace % old new)))
(defn- replace-referenced-urls [file old->new]
(reduce #(replace-referenced-url %1 %2 (old->new %2)) file
(sort-by inverse-string-length (:references file))))
(defn- replace-referenced-urls-with-new-ones [file files]
(if-let [references (:references file)]
(let [orig->curr (into {} (map (juxt original-path qualify-url) files))]
(-> file
(replace-referenced-urls orig->curr)
(assoc :references (set (replace orig->curr references)))))
file))
(defn- add-cache-busted-expires-headers-in-order [to-replace files]
;; three cases:
;; 1. nothing more to replace? return the files
(if (empty? to-replace)
files
;; 2. are there files referenced by this file that aren't fixed yet?
(let [next (by-path (first to-replace) files)
remaining-references (set/intersection to-replace (set (:references next)))]
;; -> then take those first
(if (seq remaining-references)
(recur (concat remaining-references (set/difference to-replace remaining-references))
files)
;; 3. otherwise update all references in this file, and fix it too.
(->> files
(replace {next (-> next
(replace-referenced-urls-with-new-ones files)
(add-cache-busted-expires-header))})
;; and continue with the rest that remain.
(recur (set (rest to-replace))))))))
(defn add-cache-busted-expires-headers [files]
(let [cache-busted-files (add-cache-busted-expires-headers-in-order (set (map :path files)) files)]
(concat
(map #(assoc % :outdated true) files)
cache-busted-files)))