This repository has been archived by the owner on Oct 30, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhttp_intercept.ex
59 lines (50 loc) · 1.9 KB
/
http_intercept.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
defmodule HttpIntercept do
@moduledoc """
Outgoing HTTP request interceptor.
"""
use Agent
@doc """
Enables intercepting of all HTTP requests.
"""
def enable() do
# TODO: handle duplicate enable calls.
# TODO: can we globally replace HTTP-related modules without enforcing global mode?
{:ok, _pid} = Agent.start_link(fn -> [] end, name: __MODULE__)
Mimic.set_mimic_global()
HttpIntercept.Stubs.Httpc.maybe_enable()
HttpIntercept.Stubs.Hackney.maybe_enable()
# TODO: other HTTP clients.
end
@doc """
Adds a requets handler that matches the provided URL pattern.
"""
def add_handler(url_pattern, handler) do
# TODO: check if interception is enabled.
# TODO: document that we handle both strings and regexes for url_pattern.
Agent.update(__MODULE__, fn handlers -> handlers ++ [{url_pattern, handler}] end)
end
@doc false
def handle_request(method, url, headers, body) do
handlers = Agent.get(__MODULE__, fn handlers -> handlers end)
case Enum.find(handlers, fn {url_pattern, _handler} -> url =~ url_pattern end) do
{_url_pattern, handler} ->
call_handler(handler, method, url, headers, body)
nil ->
raise """
No handler was set up for the following outgoing HTTP request:
#{String.upcase(to_string(method))} #{url}
Make sure to call HttpIntercept.add_handler(<pattern>, handler) before any request is made.
#{length(handlers)} handler(s) registered.
"""
end
end
# TODO: support MFA and anonymous functions.
defp call_handler(module, method, url, headers, body) when is_atom(module) do
# Double-check that the handler is adhering to the interface.
# TODO: improve the checks.
case module.handle_request(method, url, headers, body) do
{:ok, status, headers, body} -> {:ok, status, headers, body}
{:error, reason} -> {:error, reason}
end
end
end