diff --git a/lib/httparrot.ex b/lib/httparrot.ex index 6816597..72092dc 100644 --- a/lib/httparrot.ex +++ b/lib/httparrot.ex @@ -58,6 +58,16 @@ defmodule HTTParrot do certfile: priv_dir ++ '/ssl/server.crt', keyfile: priv_dir ++ '/ssl/server.key'], [env: [dispatch: dispatch], onresponse: &prettify_json/4]) end + + if unix_socket_supported? && Application.get_env(:httparrot, :unix_socket, false) do + {:ok, socket_path} = Application.fetch_env(:httparrot, :socket_path) + if File.exists?(socket_path), do: File.rm(socket_path) + IO.puts "Starting HTTParrot on unix socket #{socket_path}" + {:ok, _} = :cowboy.start_http(:http_unix, 100, + [port: 0, ip: {:local, socket_path}], + [env: [dispatch: dispatch], onresponse: &prettify_json/4]) + end + Supervisor.start_link([ worker(ConCache, [[ ttl_check: :timer.minutes(5), @@ -78,4 +88,11 @@ defmodule HTTParrot do req end end + + def unix_socket_supported? do + case {:os.type, Integer.parse("#{:erlang.system_info(:otp_release)}")} do + {{:unix, _}, {n, _}} when n >= 19 -> true + _ -> false + end + end end diff --git a/lib/httparrot/general_request_info.ex b/lib/httparrot/general_request_info.ex index c38e614..5e99f3f 100644 --- a/lib/httparrot/general_request_info.ex +++ b/lib/httparrot/general_request_info.ex @@ -3,9 +3,13 @@ defmodule HTTParrot.GeneralRequestInfo do {args, req} = :cowboy_req.qs_vals(req) {headers, req} = :cowboy_req.headers(req) {url, req} = :cowboy_req.url(req) - {{ip, _port}, req} = :cowboy_req.peer(req) + {{ip, port}, req} = :cowboy_req.peer(req) + + ip = case {ip, port} do + {:local, _} -> "" + _ -> :inet_parse.ntoa(ip) |> to_string + end - ip = :inet_parse.ntoa(ip) |> to_string args = group_by_keys(args) {[args: args, headers: headers, url: url, origin: ip], req} diff --git a/lib/httparrot/ip_handler.ex b/lib/httparrot/ip_handler.ex index 262f616..a78ebc1 100644 --- a/lib/httparrot/ip_handler.ex +++ b/lib/httparrot/ip_handler.ex @@ -10,9 +10,14 @@ defmodule HTTParrot.IPHandler do def get_json(req, state) do {{ip, _port}, req} = :cowboy_req.peer(req) + {response(ip), req, state} end + defp response(:local) do + [origin: ""] |> JSX.encode! + end + defp response(ip) do ip = :inet_parse.ntoa(ip) |> to_string [origin: ip] |> JSX.encode! diff --git a/mix.exs b/mix.exs index 399b527..284d59c 100644 --- a/mix.exs +++ b/mix.exs @@ -22,7 +22,8 @@ defmodule Httparrot.Mixfile do :exjsx, :con_cache ], mod: { HTTParrot, [] }, - env: [ http_port: 8080, ssl: true, https_port: 8433 ] ] + env: [ http_port: 8080, ssl: true, https_port: 8433, + unix_socket: true, socket_path: "httparrot.sock"] ] end defp deps do diff --git a/test/general_request_info_test.exs b/test/general_request_info_test.exs index b33be01..d604f5d 100644 --- a/test/general_request_info_test.exs +++ b/test/general_request_info_test.exs @@ -55,4 +55,18 @@ defmodule HTTParrot.GeneralRequestInfoTest do assert validate :cowboy_req end + + test "returns empty origin when using unix sockets" do + qs_vals = [{"a", "b"}] + headers = [header1: "value 1", header2: "value 2"] + url = "http://localhost/get?a=b" + expect(:cowboy_req, :qs_vals, 1, {qs_vals, :req2}) + expect(:cowboy_req, :headers, 1, {headers, :req3}) + expect(:cowboy_req, :url, 1, {url, :req4}) + expect(:cowboy_req, :peer, 1, {{:local, ""}, :req5}) + + assert retrieve(:req1) == {[args: %{"a" => "b"}, headers: headers, url: url, origin: ""], :req5} + + assert validate :cowboy_req + end end diff --git a/test/ip_handler_test.exs b/test/ip_handler_test.exs index 6486676..5963bb7 100644 --- a/test/ip_handler_test.exs +++ b/test/ip_handler_test.exs @@ -20,4 +20,14 @@ defmodule HTTParrot.IPHandlerTest do assert validate :cowboy_req assert validate JSX end + + test "returns empty when running over unix sockets" do + expect(:cowboy_req, :peer, 1, {{:local, ""}, :req2}) + expect(JSX, :encode!, [{[[origin: ""]], :json}]) + + assert get_json(:req1, :state) == {:json, :req2, :state} + + assert validate :cowboy_req + assert validate JSX + end end