Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F115849
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/tesla/middleware/follow_redirects.ex b/lib/tesla/middleware/follow_redirects.ex
index 6948e89..da3b87e 100644
--- a/lib/tesla/middleware/follow_redirects.ex
+++ b/lib/tesla/middleware/follow_redirects.ex
@@ -1,79 +1,80 @@
defmodule Tesla.Middleware.FollowRedirects do
@behaviour Tesla.Middleware
@moduledoc """
Follow 3xx redirects
### Example
```
defmodule MyClient do
use Tesla
plug Tesla.Middleware.FollowRedirects, max_redirects: 3 # defaults to 5
end
```
### Options
- `:max_redirects` - limit number of redirects (default: `5`)
"""
@max_redirects 5
@redirect_statuses [301, 302, 303, 307, 308]
@doc false
def call(env, next, opts \\ []) do
max = Keyword.get(opts || [], :max_redirects, @max_redirects)
redirect(env, next, max)
end
defp redirect(env, next, left) when left == 0 do
case Tesla.run(env, next) do
{:ok, %{status: status} = env} when not (status in @redirect_statuses) ->
{:ok, env}
{:ok, _env} ->
{:error, {__MODULE__, :too_many_redirects}}
error ->
error
end
end
defp redirect(env, next, left) do
case Tesla.run(env, next) do
{:ok, %{status: status} = res} when status in @redirect_statuses ->
case Tesla.get_header(res, "location") do
nil ->
{:ok, res}
location ->
location = parse_location(location, res)
%{env | status: res.status}
|> new_request(location)
|> redirect(next, left - 1)
end
other ->
other
end
end
# The 303 (See Other) redirect was added in HTTP/1.1 to indicate that the originally
# requested resource is not available, however a related resource (or another redirect)
# available via GET is available at the specified location.
# https://tools.ietf.org/html/rfc7231#section-6.4.4
defp new_request(%{status: 303} = env, location), do: %{env | url: location, method: :get}
defp new_request(env, location), do: %{env | url: location}
- defp parse_location("/" <> _rest = location, env) do
+ defp parse_location("https://" <> _rest = location, _env), do: location
+ defp parse_location("http://" <> _rest = location, _env), do: location
+
+ defp parse_location(location, env) do
env.url
|> URI.parse()
|> URI.merge(location)
|> URI.to_string()
end
-
- defp parse_location(location, _env), do: location
end
diff --git a/test/tesla/middleware/follow_redirects_test.exs b/test/tesla/middleware/follow_redirects_test.exs
index 6188dcb..23a4cbf 100644
--- a/test/tesla/middleware/follow_redirects_test.exs
+++ b/test/tesla/middleware/follow_redirects_test.exs
@@ -1,171 +1,182 @@
defmodule Tesla.Middleware.FollowRedirectsTest do
use ExUnit.Case
defmodule Client do
use Tesla
plug Tesla.Middleware.FollowRedirects
adapter fn env ->
{status, headers, body} =
case env.url do
"http://example.com/0" ->
{200, [{"content-type", "text/plain"}], "foo bar"}
"http://example.com/" <> n ->
next = String.to_integer(n) - 1
{301, [{"location", "http://example.com/#{next}"}], ""}
end
{:ok, %{env | status: status, headers: headers, body: body}}
end
end
test "redirects if default max redirects isn't exceeded" do
assert {:ok, env} = Client.get("http://example.com/5")
assert env.status == 200
end
test "raise error when redirect default max redirects is exceeded" do
assert {:error, {Tesla.Middleware.FollowRedirects, :too_many_redirects}} ==
Client.get("http://example.com/6")
end
defmodule CustomMaxRedirectsClient do
use Tesla
plug Tesla.Middleware.FollowRedirects, max_redirects: 1
adapter fn env ->
{status, headers, body} =
case env.url do
"http://example.com/0" ->
{200, [{"content-type", "text/plain"}], "foo bar"}
"http://example.com/" <> n ->
next = String.to_integer(n) - 1
{301, [{"location", "http://example.com/#{next}"}], ""}
end
{:ok, %{env | status: status, headers: headers, body: body}}
end
end
alias CustomMaxRedirectsClient, as: CMRClient
test "redirects if custom max redirects isn't exceeded" do
assert {:ok, env} = CMRClient.get("http://example.com/1")
assert env.status == 200
end
test "raise error when custom max redirects is exceeded" do
assert {:error, {Tesla.Middleware.FollowRedirects, :too_many_redirects}} ==
CMRClient.get("http://example.com/2")
end
defmodule RelativeLocationClient do
use Tesla
plug Tesla.Middleware.FollowRedirects
adapter fn env ->
{status, headers, body} =
case env.url do
"https://example.com/pl" ->
{200, [{"content-type", "text/plain"}], "foo bar"}
"http://example.com" ->
{301, [{"location", "https://example.com"}], ""}
"https://example.com" ->
{301, [{"location", "/pl"}], ""}
"https://example.com/" ->
{301, [{"location", "/pl"}], ""}
"https://example.com/article" ->
{301, [{"location", "/pl"}], ""}
+
+ "https://example.com/one/two" ->
+ {301, [{"location", "three"}], ""}
+
+ "https://example.com/one/three" ->
+ {200, [{"content-type", "text/plain"}], "foo bar baz"}
end
{:ok, %{env | status: status, headers: headers, body: body}}
end
end
alias RelativeLocationClient, as: RLClient
test "supports relative address in location header" do
assert {:ok, env} = RLClient.get("http://example.com")
assert env.status == 200
end
test "doesn't create double slashes inside new url" do
assert {:ok, env} = RLClient.get("https://example.com/")
assert env.url == "https://example.com/pl"
end
test "rewrites URLs to their root" do
assert {:ok, env} = RLClient.get("https://example.com/article")
assert env.url == "https://example.com/pl"
end
+ test "rewrites URLs relative to the original URL" do
+ assert {:ok, env} = RLClient.get("https://example.com/one/two")
+ assert env.url == "https://example.com/one/three"
+ end
+
defmodule CustomRewriteMethodClient do
use Tesla
plug Tesla.Middleware.FollowRedirects
adapter fn env ->
{status, headers, body} =
case env.url do
"http://example.com/0" ->
{200, [{"content-type", "text/plain"}], "foo bar"}
"http://example.com/" <> n ->
next = String.to_integer(n) - 1
{303, [{"location", "http://example.com/#{next}"}], ""}
end
{:ok, %{env | status: status, headers: headers, body: body}}
end
end
alias CustomRewriteMethodClient, as: CRMClient
test "rewrites method to get for 303 requests" do
assert {:ok, env} = CRMClient.post("http://example.com/1", "")
assert env.method == :get
end
defmodule CustomPreservesRequestClient do
use Tesla
plug Tesla.Middleware.FollowRedirects
adapter fn env ->
{status, headers, body} =
case env.url do
"http://example.com/0" ->
{200, env.headers, env.body}
"http://example.com/" <> n ->
next = String.to_integer(n) - 1
{301, [{"location", "http://example.com/#{next}"}], ""}
end
{:ok, %{env | status: status, headers: headers, body: body}}
end
end
alias CustomPreservesRequestClient, as: CPRClient
test "Preserves original request" do
assert {:ok, env} =
CPRClient.post(
"http://example.com/1",
"Body data",
headers: [{"X-Custom-Header", "custom value"}]
)
assert env.body == "Body data"
assert env.headers == [{"X-Custom-Header", "custom value"}]
end
end
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Nov 29, 8:35 AM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41183
Default Alt Text
(7 KB)
Attached To
Mode
R28 tesla
Attached
Detach File
Event Timeline
Log In to Comment