From 003402df401f2bbf46e47017e3b7a2ec27615ea2 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 21 Jan 2021 14:20:13 -0600
Subject: [PATCH] Add ability to invalidate cache entries for Apache

---
 config/config.exs                             |  4 ++-
 docs/configuration/cheatsheet.md              |  5 ++--
 installation/apache-cache-purge.sh.example    | 25 +++++++++++++++++++
 .../web/media_proxy/invalidation/script.ex    | 19 ++++++++++++++
 4 files changed, 50 insertions(+), 3 deletions(-)
 create mode 100755 installation/apache-cache-purge.sh.example

diff --git a/config/config.exs b/config/config.exs
index c4a690799..5eca250bb 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -438,7 +438,9 @@ config :pleroma, Pleroma.Web.MediaProxy.Invalidation.Http,
   headers: [],
   options: []
 
-config :pleroma, Pleroma.Web.MediaProxy.Invalidation.Script, script_path: nil
+config :pleroma, Pleroma.Web.MediaProxy.Invalidation.Script,
+  script_path: nil,
+  url_format: nil
 
 # Note: media preview proxy depends on media proxy to be enabled
 config :pleroma, :media_preview_proxy,
diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md
index 5c0fd6487..9d4b07bf4 100644
--- a/docs/configuration/cheatsheet.md
+++ b/docs/configuration/cheatsheet.md
@@ -321,9 +321,10 @@ This section describe PWA manifest instance-specific values. Currently this opti
 #### Pleroma.Web.MediaProxy.Invalidation.Script
 
 This strategy allow perform external shell script to purge cache.
-Urls of attachments pass to script as arguments.
+Urls of attachments are passed to the script as arguments.
 
-* `script_path`: path to external script.
+* `script_path`: Path to the external script.
+* `url_format`: Set to `:htcacheclean` if using Apache's htcacheclean utility.
 
 Example:
 
diff --git a/installation/apache-cache-purge.sh.example b/installation/apache-cache-purge.sh.example
new file mode 100755
index 000000000..be1d36841
--- /dev/null
+++ b/installation/apache-cache-purge.sh.example
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# A simple shell script to delete a media from Apache's mod_disk_cache.
+
+SCRIPTNAME=${0##*/}
+
+# mod_disk_cache directory
+CACHE_DIRECTORY="/tmp/pleroma-media-cache"
+
+## Removes an item via the htcacheclean utility
+## $1 - the filename, can be a pattern .
+## $2 - the cache directory.
+purge_item() {
+    htcacheclean -p "${2}" "${1}"
+} # purge_item
+
+purge() {
+  for url in "$@"
+  do
+    echo "$SCRIPTNAME delete \`$url\` from cache ($CACHE_DIRECTORY)"
+    purge_item "$url" $CACHE_DIRECTORY
+  done
+}
+
+purge "$@"
diff --git a/lib/pleroma/web/media_proxy/invalidation/script.ex b/lib/pleroma/web/media_proxy/invalidation/script.ex
index 0f66c2fe3..c447614fa 100644
--- a/lib/pleroma/web/media_proxy/invalidation/script.ex
+++ b/lib/pleroma/web/media_proxy/invalidation/script.ex
@@ -13,6 +13,7 @@ defmodule Pleroma.Web.MediaProxy.Invalidation.Script do
   def purge(urls, opts \\ []) do
     args =
       urls
+      |> format_urls(Keyword.get(opts, :url_format))
       |> List.wrap()
       |> Enum.uniq()
       |> Enum.join(" ")
@@ -40,4 +41,22 @@ defmodule Pleroma.Web.MediaProxy.Invalidation.Script do
     Logger.error("Error while cache purge: #{inspect(error)}")
     {:error, inspect(error)}
   end
+
+  def format_urls(urls, :htcacheclean) do
+    urls
+    |> Enum.map(fn url ->
+      uri = URI.parse(url)
+
+      query =
+        if !is_nil(uri.query) do
+          "?" <> uri.query
+        else
+          "?"
+        end
+
+      uri.scheme <> "://" <> uri.host <> ":#{inspect(uri.port)}" <> uri.path <> query
+    end)
+  end
+
+  def format_urls(urls, _), do: urls
 end
-- 
2.49.0