Repository: keathley/finch
Pull request #33 (2020-04-24 21:16:55)

Allow Mint.connect/4 options to be configured


Patch:
diff --git a/lib/finch.ex b/lib/finch.ex
index 3f78d0d..519515a 100644
--- a/lib/finch.ex
+++ b/lib/finch.ex
@@ -80,17 +80,25 @@ defmodule Finch do
     "OPTIONS"
   ]
   @atom_to_method Enum.zip(@atom_methods, @methods) |> Enum.into(%{})
+  @default_pool_size 10
+  @default_pool_count 1
 
   @pool_config_schema [
     size: [
       type: :pos_integer,
       doc: "Number of connections to maintain in each pool.",
-      default: 10
+      default: @default_pool_size
     ],
     count: [
       type: :pos_integer,
       doc: "Number of pools to start.",
-      default: 1
+      default: @default_pool_count
+    ],
+    conn_opts: [
+      type: :keyword_list,
+      doc:
+        "These options are passed to `Mint.HTTP.connect/4` whenever a new connection is established. `:mode` is not configurable as Finch must control this setting. Typically these options are used to configure proxying, https settings, or connect timeouts.",
+      default: []
     ]
   ]
 
@@ -100,10 +108,12 @@ defmodule Finch do
   ## Options:
     * `:name` - The name of your Finch instance. This field is required.
 
-    * `:pools` - Configuration for your pools. You can provide a `:default` catch-all
-    configuration for any non specfied {scheme, host, port}, or configuration for any
-    URL that will be parsed into a {scheme, host, port}. See "Pool Configuration Options"
-    below.
+    * `:pools` - A map specifying the configuration for your pools. The keys should be URLs 
+    provided as binaries, or the atom `:default` to provide a catch-all configuration to be used
+    for any unspecified URLs. See "Pool Configuration Options" below for details on the possible
+    map values. Default value is `%{default: [size: #{@default_pool_size}, count: #{
+    @default_pool_count
+  }]}`.
 
   ### Pool Configuration Options
   #{NimbleOptions.docs(@pool_config_schema)}
@@ -234,7 +244,7 @@ defmodule Finch do
     %{
       size: valid[:size],
       count: valid[:count],
-      conn_opts: []
+      conn_opts: valid[:conn_opts]
     }
   end
 
diff --git a/lib/finch/conn.ex b/lib/finch/conn.ex
index 58e214e..95dd3e8 100644
--- a/lib/finch/conn.ex
+++ b/lib/finch/conn.ex
@@ -35,7 +35,7 @@ defmodule Finch.Conn do
     }
 
     start_time = Telemetry.start(:connect, meta)
-    conn_opts = Keyword.merge([mode: :passive], conn.opts)
+    conn_opts = Keyword.merge(conn.opts, mode: :passive)
 
     case HTTP.connect(conn.scheme, conn.host, conn.port, conn_opts) do
       {:ok, mint} ->


Test patch:
diff --git a/test/finch_test.exs b/test/finch_test.exs
index 01021ff..56ee50c 100644
--- a/test/finch_test.exs
+++ b/test/finch_test.exs
@@ -263,6 +263,32 @@ defmodule FinchTest do
     end
   end
 
+  describe "connection options" do
+    test "are passed through to the conn", %{bypass: bypass} do
+      expect_any(bypass)
+
+      start_supervised(
+        {Finch, name: H1Finch, pools: %{default: [conn_opts: [protocols: [:http1]]]}}
+      )
+
+      assert {:ok, _} = Finch.request(H1Finch, :get, endpoint(bypass))
+
+      stop_supervised(Finch)
+
+      start_supervised(
+        {Finch, name: H2Finch, pools: %{default: [conn_opts: [protocols: [:http2]]]}}
+      )
+
+      assert {:error, _} = Finch.request(H2Finch, :get, endpoint(bypass))
+    end
+
+    test "caller is unable to override mode", %{bypass: bypass} do
+      start_supervised({Finch, name: MyFinch, pools: %{default: [conn_opts: [mode: :active]]}})
+      expect_any(bypass)
+      assert {:ok, _} = Finch.request(MyFinch, :get, endpoint(bypass))
+    end
+  end
+
   describe "telemetry" do
     setup %{bypass: bypass} do
       Bypass.expect_once(bypass, "GET", "/", fn conn ->