Page MenuHomePhorge

No OneTemporary

Size
4 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/tesla/middleware/compression.ex b/lib/tesla/middleware/compression.ex
new file mode 100644
index 0000000..75c41e3
--- /dev/null
+++ b/lib/tesla/middleware/compression.ex
@@ -0,0 +1,50 @@
+defmodule Tesla.Middleware.Compression do
+ def call(env, next, opts) do
+ env
+ |> compress(opts)
+ |> Tesla.run(next)
+ |> decompress()
+ end
+
+ def compressable?(body), do: is_binary(body)
+
+ def compress(env, opts) do
+ if compressable?(env.body) do
+ format = Keyword.get(opts || [], :format, "gzip")
+
+ env
+ |> Map.update!(:body, &compress_body(&1, format))
+ |> Tesla.Middleware.Headers.call([], %{"Content-Encoding" => format})
+ else
+ env
+ end
+ end
+
+ def compress_body(body, "gzip"), do: :zlib.gzip(body)
+ def compress_body(body, "deflate"), do: :zlib.zip(body)
+
+ def decompress(env) do
+ env
+ |> Map.update!(:body, &decompress_body(&1, env.headers["content-encoding"]))
+ end
+
+ def decompress_body(<<31, 139, 8, _ :: binary>> = body, "gzip"), do: :zlib.gunzip(body)
+ def decompress_body(body, "deflate"), do: :zlib.unzip(body)
+ def decompress_body(body, _content_encoding), do: body
+end
+
+defmodule Tesla.Middleware.CompressRequest do
+ def call(env, next, opts) do
+ env
+ |> Tesla.Middleware.Compression.compress(opts)
+ |> Tesla.run(next)
+ end
+end
+
+defmodule Tesla.Middleware.DecompressResponse do
+ def call(env, next, _opts) do
+ env
+ |> Tesla.run(next)
+ |> Tesla.Middleware.Compression.decompress()
+ end
+end
diff --git a/test/tesla/middleware/compression_test.exs b/test/tesla/middleware/compression_test.exs
new file mode 100644
index 0000000..8f47b36
--- /dev/null
+++ b/test/tesla/middleware/compression_test.exs
@@ -0,0 +1,98 @@
+defmodule CompressionTest do
+ use ExUnit.Case
+
+ use Tesla.Middleware.TestCase, middleware: Tesla.Middleware.Compression
+ use Tesla.Middleware.TestCase, middleware: Tesla.Middleware.CompressRequest
+ use Tesla.Middleware.TestCase, middleware: Tesla.Middleware.DecompressResponse
+
+
+ defmodule CompressionGzipRequestClient do
+ use Tesla
+
+ plug Tesla.Middleware.Compression
+
+ adapter fn (env) ->
+ {status, headers, body} = case env.url do
+ "/" ->
+ {200, %{'Content-Type' => 'text/plain'}, :zlib.gunzip(env.body)}
+ end
+
+ %{env | status: status, headers: headers, body: body}
+ end
+ end
+
+ test "compress request body (gzip)" do
+ assert CompressionGzipRequestClient.post("/", "compress request").body == "compress request"
+ end
+
+ defmodule CompressionDeflateRequestClient do
+ use Tesla
+
+ plug Tesla.Middleware.Compression, format: "deflate"
+
+ adapter fn (env) ->
+ {status, headers, body} = case env.url do
+ "/" ->
+ {200, %{'Content-Type' => 'text/plain'}, :zlib.unzip(env.body)}
+ end
+
+ %{env | status: status, headers: headers, body: body}
+ end
+ end
+
+ test "compress request body (deflate)" do
+ assert CompressionDeflateRequestClient.post("/", "compress request").body == "compress request"
+ end
+
+ defmodule CompressionResponseClient do
+ use Tesla
+
+ plug Tesla.Middleware.Compression
+
+ adapter fn (env) ->
+ {status, headers, body} = case env.url do
+ "/response-gzip" ->
+ {200, %{'Content-Type' => 'text/plain', 'Content-Encoding' => 'gzip'}, :zlib.gzip("decompressed gzip")}
+ "/response-deflate" ->
+ {200, %{'Content-Type' => 'text/plain', 'Content-Encoding' => 'deflate'}, :zlib.zip("decompressed deflate")}
+ "/response-identity" ->
+ {200, %{'Content-Type' => 'text/plain', 'Content-Encoding' => 'identity'}, "unchanged"}
+ end
+
+ %{env | status: status, headers: headers, body: body}
+ end
+ end
+
+ test "decompress response body (gzip)" do
+ assert CompressionResponseClient.get("/response-gzip").body == "decompressed gzip"
+ end
+
+ test "decompress response body (deflate)" do
+ assert CompressionResponseClient.get("/response-deflate").body == "decompressed deflate"
+ end
+
+ test "return unchanged response for unsupported content-encoding" do
+ assert CompressionResponseClient.get("/response-identity").body == "unchanged"
+ end
+
+ defmodule CompressRequestDecompressResponseClient do
+ use Tesla
+
+ plug Tesla.Middleware.CompressRequest
+ plug Tesla.Middleware.DecompressResponse
+
+ adapter fn (env) ->
+ {status, headers, body} = case env.url do
+ "/" ->
+ {200, %{'Content-Type' => 'text/plain', 'Content-Encoding' => 'gzip'}, env.body}
+ end
+
+ %{env | status: status, headers: headers, body: body}
+ end
+ end
+
+ test "CompressRequest / DecompressResponse work without options" do
+ alias CompressRequestDecompressResponseClient, as: CRDRClient
+ assert CRDRClient.post("/", "foo bar").body == "foo bar"
+ end
+end

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jan 21, 2:39 AM (1 d, 19 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55637
Default Alt Text
(4 KB)

Event Timeline