Hello friends,
I’ve been using my free time in the last month or so to learn Elixir in the hope of replacing a Node.js server I wrote for a side project. To really understand the workings of Plug, I wanted to setup an ultra simple Plug/Cowboy HTTP server and start from there. Eventually, I’m sure I’ll move on to Phoenix, but I was really attracted to the simplicity of Plug as a starting point.
I uploaded the simplest “broken” version of my code to this repo. You should be able to easily clone and run that with mix, and I’ll also show the core code below:
defmodule PlugCowboy2Http2 do
use Application
def start(_type, _args) do
children = [
{
Plug.Adapters.Cowboy2,
scheme: :http,
plug: PlugCowboy2Http2.Router
}
]
opts = [
strategy: :one_for_one,
name: PlugCowboy2Http2.Supervisor
]
{:ok, _} = Supervisor.start_link(children, opts)
end
end
defmodule PlugCowboy2Http2.Router do
use Plug.Router
plug(Plug.Logger)
plug(:match)
plug(:dispatch)
match _ do
send_resp(conn, 200, "Hello!")
end
end
When I navigate my browser (Chromium: 70.0.3538.16) to http://localhost:4000
I seem to always crash a process. The browser receives an ERR_CONNECTION_RESET
and the Elixir runtime prints the following message to console:
13:11:21.735 [error] Ranch protocol #PID<0.286.0> of listener PlugCowboy2Http2.Router.HTTP (cowboy_clear) terminated
** (exit) an exception was raised:
** (UndefinedFunctionError) function :cowboy_http.init/5 is undefined (module :cowboy_http is not available)
(cowboy) :cowboy_http.init(#PID<0.184.0>, PlugCowboy2Http2.Router.HTTP, #Port<0.5>, :ranch_tcp, %{env: %{dispatch: [{:, [], [{:, , Plug.Adapters.Cowboy2.Handler, {PlugCowboy2Http2.Router, }}]}]}, stream_handlers: [Plug.Adapters.Cowboy2.Stream]})
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
To add to the confusion, when I switch the :scheme
option to :https
and add a cert & key file, the server works perfectly. Can anyone show me where I’m going wrong?