Skip to content

Instantly share code, notes, and snippets.

@tomtaylor
Last active January 17, 2019 20:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomtaylor/c93b3156cfedcb354edc5c79a7d6abe7 to your computer and use it in GitHub Desktop.
Save tomtaylor/c93b3156cfedcb354edc5c79a7d6abe7 to your computer and use it in GitHub Desktop.
Redirect requests to the host of the url defined in your endpoint. Expects an upstream proxy to have set X-Forwarded-Proto and X-Forwarded-Port.
defmodule PoplarWeb.PlugCanonicalDomain do
import Plug.Conn
import Phoenix.Controller
alias Plug.Conn
def init(opts), do: opts
def call(conn, _opts) do
endpoint_url = endpoint_url_struct()
conn_url = conn_url_struct(conn)
case canonicalise(endpoint_url, conn_url) do
nil ->
conn
url ->
url_string = URI.to_string(url)
conn
|> put_status(:moved_permanently)
|> redirect(external: url_string)
|> halt()
end
end
def canonicalise(_endpoint_url = %URI{host: endpoint_host}, conn_url = %URI{host: conn_host})
when is_nil(endpoint_host) == false and is_nil(conn_host) == false and
endpoint_host != conn_host do
conn_url
|> Map.put(:host, endpoint_host)
end
def canonicalise(_, _), do: nil
defp endpoint_url_struct() do
PoplarWeb.Endpoint.struct_url()
end
def conn_url_struct(conn = %Conn{}) do
%URI{
host: conn.host,
path: conn.request_path,
scheme: forwarded_scheme(conn),
port: forwarded_port(conn),
query: clean_query(conn)
}
end
def forwarded_scheme(conn = %Conn{}) do
case get_req_header(conn, "x-forwarded-proto") do
[scheme] -> scheme
[] -> conn.scheme |> Atom.to_string()
end
end
def forwarded_port(conn = %Conn{}) do
case get_req_header(conn, "x-forwarded-port") do
[port] -> port |> String.to_integer()
[] -> conn.port
end
end
defp clean_query(conn = %Conn{}) do
case conn.query_string do
"" -> nil
q -> q
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment