From 5ffde91951a88abf4041b18269032fbc3d4a4576 Mon Sep 17 00:00:00 2001 From: Alessandro Mencarini Date: Fri, 12 Jan 2018 10:03:52 +0000 Subject: [PATCH] Add check for HTTP_PROXY env var If no proxy option is passed, this will check if a env var for proxies is set. If none is set everything will operate as usual. Fixes #305 --- .gitignore | 1 + lib/httpoison/base.ex | 30 ++++++++++++++--- test/httpoison_base_test.exs | 64 ++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index c0be748..1b82591 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ erl_crash.dump mix.lock /.idea *.iml +/.elixir_ls diff --git a/lib/httpoison/base.ex b/lib/httpoison/base.ex index b8052ed..605636e 100644 --- a/lib/httpoison/base.ex +++ b/lib/httpoison/base.ex @@ -401,8 +401,6 @@ defmodule HTTPoison.Base do recv_timeout = Keyword.get options, :recv_timeout stream_to = Keyword.get options, :stream_to async = Keyword.get options, :async - proxy = Keyword.get options, :proxy - proxy_auth = Keyword.get options, :proxy_auth ssl = Keyword.get options, :ssl follow_redirect = Keyword.get options, :follow_redirect max_redirect = Keyword.get options, :max_redirect @@ -411,8 +409,6 @@ defmodule HTTPoison.Base do hn_options = if timeout, do: [{:connect_timeout, timeout} | hn_options], else: hn_options hn_options = if recv_timeout, do: [{:recv_timeout, recv_timeout} | hn_options], else: hn_options - hn_options = if proxy, do: [{:proxy, proxy} | hn_options], else: hn_options - hn_options = if proxy_auth, do: [{:proxy_auth, proxy_auth} | hn_options], else: hn_options hn_options = if ssl, do: [{:ssl_options, ssl} | hn_options], else: hn_options hn_options = if follow_redirect, do: [{:follow_redirect, follow_redirect} | hn_options], else: hn_options hn_options = if max_redirect, do: [{:max_redirect, max_redirect} | hn_options], else: hn_options @@ -431,10 +427,34 @@ defmodule HTTPoison.Base do hn_options end + defp build_hackney_proxy_options(options, request_url) do + proxy = + if Keyword.has_key?(options, :proxy) do + Keyword.get(options, :proxy) + else + case URI.parse(request_url).scheme do + "http" -> System.get_env("HTTP_PROXY") || System.get_env("http_proxy") + "https" -> System.get_env("HTTPS_PROXY") || System.get_env("https_proxy") + _ -> nil + end + end + + proxy_auth = Keyword.get(options, :proxy_auth) + + hn_proxy_options = if proxy, do: [{:proxy, proxy}], else: [] + + hn_proxy_options = + if proxy_auth, do: [{:proxy_auth, proxy_auth} | hn_proxy_options], else: hn_proxy_options + + hn_proxy_options + end + + @doc false @spec request(atom, atom, binary, body, headers, any, fun, fun, fun) :: {:ok, Response.t | AsyncResponse.t} | {:error, Error.t} def request(module, method, request_url, request_body, request_headers, options, process_status_code, process_headers, process_response_body) do - hn_options = build_hackney_options(module, options) + hn_proxy_options = build_hackney_proxy_options(options, request_url) + hn_options = hn_proxy_options ++ build_hackney_options(module, options) case do_request(method, request_url, request_headers, request_body, hn_options) do {:ok, status_code, headers} -> response(process_status_code, process_headers, process_response_body, status_code, headers, "", request_url) diff --git a/test/httpoison_base_test.exs b/test/httpoison_base_test.exs index ff63460..897c617 100644 --- a/test/httpoison_base_test.exs +++ b/test/httpoison_base_test.exs @@ -146,6 +146,70 @@ defmodule HTTPoisonBaseTest do assert validate :hackney end + test "having http_proxy env variable set on http requests" do + expect(System, :get_env, [{["HTTP_PROXY"], "proxy"}]) + + expect(:hackney, :request, [ + {[:post, "http://localhost", [], "body", [proxy: "proxy"]], {:ok, 200, "headers", :client}} + ]) + + expect(:hackney, :body, 1, {:ok, "response"}) + + assert HTTPoison.post!("localhost", "body") == + %HTTPoison.Response{ + status_code: 200, + headers: "headers", + body: "response", + request_url: "http://localhost" + } + + assert validate(:hackney) + end + + test "having https_proxy env variable set on https requests" do + expect(System, :get_env, [{["HTTPS_PROXY"], "proxy"}]) + + expect(:hackney, :request, [ + {[:post, "https://localhost", [], "body", [proxy: "proxy"]], {:ok, 200, "headers", :client}} + ]) + + expect(:hackney, :body, 1, {:ok, "response"}) + + assert HTTPoison.post!("https://localhost", "body") == + %HTTPoison.Response{ + status_code: 200, + headers: "headers", + body: "response", + request_url: "https://localhost" + } + + assert validate(:hackney) + end + + test "having https_proxy env variable set on http requests" do + expect(System, :get_env, [ + {["HTTPS_PROXY"], "proxy"}, + {["HTTP_PROXY"], nil}, + {["http_proxy"], nil} + ]) + + expect(:hackney, :request, [ + {[:post, "http://localhost", [], "body", []], {:ok, 200, "headers", :client}} + ]) + + expect(:hackney, :body, 1, {:ok, "response"}) + + assert HTTPoison.post!("localhost", "body") == + %HTTPoison.Response{ + status_code: 200, + headers: "headers", + body: "response", + request_url: "http://localhost" + } + + assert validate(:hackney) + end + test "passing ssl option" do expect(:hackney, :request, [{[:post, "http://localhost", [], "body", [ssl_options: [certfile: "certs/client.crt"]]], {:ok, 200, "headers", :client}}])