Skip to content

Commit

Permalink
Handle providers listed with subdomains
Browse files Browse the repository at this point in the history
host_matches? previously would fail to match providers with URLs such
as http://www.twitter.com/. Generalized the regex to handle subdomains.
  • Loading branch information
neilberkman committed Dec 10, 2019
1 parent e11ab73 commit 934c6f4
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 29 deletions.
33 changes: 17 additions & 16 deletions lib/furlex/oembed.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,24 @@ defmodule Furlex.Oembed do
Soft fetch will fetch cached providers. Hard fetch requests
providers from oembed.com and purges the cache.
"""
@spec fetch_providers(Atom.t) :: {:ok, List.t} | {:error, Atom.t}
@spec fetch_providers(Atom.t()) :: {:ok, List.t()} | {:error, Atom.t()}
def fetch_providers(type \\ :soft)

def fetch_providers(:hard) do
case get("/providers.json") do
{:ok, %{body: providers}} ->
GenServer.cast __MODULE__, {:providers, providers}
GenServer.cast(__MODULE__, {:providers, providers})
{:ok, providers}

other ->
Logger.error "Could not fetch providers: #{inspect other}"
other ->
Logger.error("Could not fetch providers: #{inspect(other)}")
{:error, :fetch_error}
end
end

def fetch_providers(_soft) do
case GenServer.call(__MODULE__, :providers) do
nil -> fetch_providers(:hard)
nil -> fetch_providers(:hard)
providers -> {:ok, providers}
end
end
Expand All @@ -47,10 +49,10 @@ defmodule Furlex.Oembed do
iex> Oembed.endpoint_from_url "https://vimeo.com/88856141", %{"format" => "xml"}
{:ok, "https://vimeo.com/api/oembed.xml"}
"""
@spec endpoint_from_url(String.t, Map.t) :: {:ok, String.t} | {:error, Atom.t}
@spec endpoint_from_url(String.t(), Map.t()) :: {:ok, String.t()} | {:error, Atom.t()}
def endpoint_from_url(url, params \\ %{"format" => "json"}, opts \\ []) do
case provider_from_url(url, opts) do
nil ->
nil ->
{:error, :no_oembed_provider}

provider ->
Expand All @@ -60,39 +62,38 @@ defmodule Furlex.Oembed do

# Maps a url to a provider, or returns nil if no such provider exists
defp provider_from_url(url, opts) do
fetch_type =
if Keyword.get(opts, :skip_cache?, false), do: :hard, else: :soft
fetch_type = if Keyword.get(opts, :skip_cache?, false), do: :hard, else: :soft

{:ok, providers} = fetch_providers(fetch_type)

case URI.parse(url) do
%URI{host: nil} ->
%URI{host: nil} ->
nil

%URI{host: host} ->
Enum.find providers, &host_matches?(host, &1)
Enum.find(providers, &host_matches?(host, &1))
end
end

defp endpoint_from_provider(provider, params) do
[ endpoint | _] = provider["endpoints"]
[endpoint | _] = provider["endpoints"]

url = endpoint["url"]
url = endpoint["url"]
regex = ~r/{(.*?)}/
url = Regex.replace regex, url, fn _, key -> params[key] end
url = Regex.replace(regex, url, fn _, key -> params[key] end)

{:ok, url}
end

defp host_matches?(host, %{"provider_url" => provider_url}) do
Regex.match? ~r/https?:\/\/#{host}/, provider_url
Regex.match?(~r/https?:\/\/([a-zA-Z0-9]+\.)?#{host}/, provider_url)
end

## GenServer callbacks

@doc false
def start_link(opts \\ []) do
GenServer.start_link __MODULE__, nil, opts
GenServer.start_link(__MODULE__, nil, opts)
end

def init(state) do
Expand Down
15 changes: 14 additions & 1 deletion test/fixtures/providers.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
[
{
"provider_name": "Twitter",
"provider_url": "http:\/\/www.twitter.com/",
"endpoints": [
{
"schemes": [
"https:\/\/twitter.com\/*\/status\/*",
"https:\/\/*.twitter.com\/*\/status\/*"
],
"url": "https:\/\/publish.twitter.com\/oembed"
}
]
},
{
"provider_name": "VideoJug",
"provider_url": "http:\/\/www.videojug.com",
Expand Down Expand Up @@ -147,4 +160,4 @@
}
]
}
]
]
38 changes: 26 additions & 12 deletions test/furlex/oembed_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,49 @@ defmodule Furlex.OembedTest do

setup do
bypass = Bypass.open()
url = "http://localhost:#{bypass.port}"
config = Application.get_env :furlex, Oembed, []
url = "http://localhost:#{bypass.port}"
config = Application.get_env(:furlex, Oembed, [])

new_config = Keyword.put config, :oembed_host, url
Application.put_env :furlex, Oembed, new_config
new_config = Keyword.put(config, :oembed_host, url)
Application.put_env(:furlex, Oembed, new_config)

on_exit fn ->
Application.put_env :furlex, Oembed, config
on_exit(fn ->
Application.put_env(:furlex, Oembed, config)

:ok
end
end)

{:ok, bypass: bypass}
end

test "returns endpoint from url", %{bypass: bypass} do
Bypass.expect bypass, &handle/1
Bypass.expect(bypass, &handle/1)

assert {:error, :no_oembed_provider} ==
Oembed.endpoint_from_url("foobar")
Oembed.endpoint_from_url("foobar")

url = "https://vimeo.com/88856141"
url = "https://vimeo.com/88856141"
params = %{"format" => "json"}

{:ok, endpoint} = Oembed.endpoint_from_url(url, params, [skip_cache?: true])
{:ok, endpoint} = Oembed.endpoint_from_url(url, params, skip_cache?: true)

assert endpoint == "https://vimeo.com/api/oembed.json"
end

test "returns endpoint from url with subdomain", %{bypass: bypass} do
Bypass.expect(bypass, &handle/1)

assert {:error, :no_oembed_provider} ==
Oembed.endpoint_from_url("foobar")

url = "https://twitter.com/arshia__/status/1204481088422178817?s=20"
params = %{"format" => "json"}

{:ok, endpoint} = Oembed.endpoint_from_url(url, params, skip_cache?: true)

assert endpoint == "https://publish.twitter.com/oembed"
end

def handle(%{request_path: "/providers.json"} = conn) do
assert conn.method == "GET"

Expand All @@ -42,6 +56,6 @@ defmodule Furlex.OembedTest do
|> Path.join()
|> File.read!()

Plug.Conn.resp conn, 200, providers
Plug.Conn.resp(conn, 200, providers)
end
end

0 comments on commit 934c6f4

Please sign in to comment.