Current section
Files
Jump to
Current section
Files
lib/req_client/plugins/proxy.ex
defmodule ReqClient.Proxy do
@moduledoc """
Req proxy plugin
## Options
- proxy values:
- :none, false donot use proxy
- :env default, curl like environment
- {host, port, no_proxy} use this proxy
"""
require Logger
@no_proxy_hosts ["127.0.0.1", "localhost", "192.168."]
def attach(req, opts \\ []) do
req
|> Req.Request.register_options([:proxy, :verbose])
|> Req.merge(opts)
|> Req.Request.append_request_steps(add_env_proxy: &add_env_proxy/1)
end
@doc """
Add proxy connect_options from env settings
[connect_options: [proxy: {:http, "127.0.0.1", 1087, []}]]
"""
def add_env_proxy(req) do
default_proxy = should_enable_proxy(req)
proxying = Req.Request.get_option(req, :proxy, default_proxy)
use_env_proxy(req, proxying)
end
def use_env_proxy(req, false), do: req
def use_env_proxy(req, true) do
conn_opts = req.options[:connect_options] || []
proxy = Keyword.get(conn_opts, :proxy)
conn_opts =
if proxy do
# already set
conn_opts
else
get_env_proxy()
|> case do
nil ->
conn_opts
proxy ->
if verbose?(req) do
Logger.info("Using env-proxy: #{proxy |> inspect}")
end
Keyword.put(conn_opts, :proxy, proxy)
end
end
# put_in(request.options[key], value) ?
opts = req.options |> Map.put(:connect_options, conn_opts)
%{req | options: opts}
end
@doc """
Should use proxy when url is localhost or 127.0.0.1?
"""
def should_enable_proxy(req) do
host = req.url.host
env_hosts =
System.get_env("NO_PROXY", System.get_env("no_proxy", ""))
|> String.split(",")
|> Enum.map(&String.trim/1)
hosts = (@no_proxy_hosts ++ env_hosts) |> Enum.uniq()
disabled =
Enum.any?(hosts, fn h ->
String.contains?(host, h)
end)
if disabled && verbose?(req) do
Logger.info("disable proxy by no-proxy hosts: #{hosts |> inspect()}")
end
!disabled
end
def get_env_proxy(),
do: System.get_env("http_proxy", System.get_env("HTTP_PROXY")) |> parse_proxy()
def parse_proxy(nil), do: nil
def parse_proxy("http" <> _ = url), do: URI.parse(url) |> parse_proxy()
def parse_proxy(%URI{host: host, port: port, scheme: scheme}) do
{scheme |> String.to_atom(), host, port, []}
end
defdelegate verbose?(req), to: ReqClient.Verbose
end