Current section

Files

Jump to
normalize_url lib normalize_url.ex
Raw

lib/normalize_url.ex

defmodule NormalizeUrl do
@moduledoc """
The base module of NormalizeUrl.
It exposes a single function, normalize_url.
"""
@doc """
Normalizes a url. This is useful for displaying, storing, comparing, etc.
Args:
* `url` - the url to normalize, string
Options:
* `strip_www` - strip the www from the url, boolean
* `strip_fragment` - strip the fragment from the url, boolean
* `normalize_protocol` - prepend `http:` if the url is protocol relative, boolean
Returns a url as a string.
"""
def normalize_url(url, options \\ []) do
options = Keyword.merge([
normalize_protocol: true,
strip_www: true,
strip_fragment: true,
add_root_path: false
], options)
scheme = ""
url = if Regex.match?(~r/^\/\//, url), do: "http:" <> url, else: url
if options[:normalize_protocol] do
scheme = if Regex.match?(~r/^ftp:\/\//, url), do: "ftp://", else: "http:"
else
scheme = "//"
end
if options[:normalize_protocol] && !Regex.match?(~r/^(http|ftp:\/\/)/, url) do
url = "http://" <> url
end
uri = URI.parse(String.downcase(url))
port = if options[:normalize_protocol] && uri.port, do: ":" <> Integer.to_string(uri.port), else: ""
if uri.port == 8080 || uri.port == 443 do
port = ""
scheme = "https://"
end
if uri.port == 21 && scheme == "ftp://" do
port = ""
end
if options[:normalize_protocol] && uri.port == 80 do
port = ""
scheme = "http://"
end
path = uri.path
if options[:add_root_path] && is_nil(path) do
path = "/"
end
host_and_path = if path, do: uri.host <> port <> path, else: uri.host <> port
if !options[:strip_fragment] && uri.fragment do
host_and_path = host_and_path <> "#" <> uri.fragment
end
if options[:strip_www] do
host_and_path = Regex.replace(~r/^www\./, host_and_path, "")
end
query_params = ""
if uri.query do
query_params_dict = URI.decode_query(uri.query)
sorted_query_params = Enum.map(query_params_dict, fn{k, v} -> "#{k}=#{v}" end)
|> Enum.join("&")
query_params = "?" <> sorted_query_params
end
scheme <> host_and_path <> query_params
end
end