Skip to content

Instantly share code, notes, and snippets.

@OleMchls
Last active May 1, 2017 19:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save OleMchls/9795e83ebffcb8773ef2304b496b1023 to your computer and use it in GitHub Desktop.
Save OleMchls/9795e83ebffcb8773ef2304b496b1023 to your computer and use it in GitHub Desktop.
elixirconfeu2017.snips
defmodule PlugWithCustomCall do
  use Plug.Builder
  plug Plug.Logger
  plug Plug.Head

  def call(conn, opts) do
    super(conn, opts) # calls Plug.Logger and Plug.Head
    assign(conn, :called_all_plugs, true)
  end
end
defmodule HelloPhoenix.Router do
  use HelloPhoenix.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", HelloPhoenix do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
  end

  # Other scopes may use custom stacks.
  # scope "/api", HelloPhoenix do
  #   pipe_through :api
  # end
end
def start(_type, [plug]) do
  {:ok, socket} = :gen_tcp.listen(port,
                    [:binary, packet: :line, active: false, reuseaddr: true])
  Logger.info "Accepting connections on port #{port}"
  opts = plug.init(%{})
  Task.start_link(fn -> loop_acceptor(socket, {plug, opts}) end)
  {:ok, self()}
end
defp loop_acceptor(socket, plug) do
  {:ok, client} = :gen_tcp.accept(socket)
  
  serve(client, %Request{})
  |> respond(plug, client)
  :gen_tcp.close(client)
  
  loop_acceptor(socket, plug)
end
%Stupify.Request{
  awaiting: :statusline,
  headers: [],
  statusline: ""
}
defp serve(socket, %Request{awaiting: :response} = req), do: req
defp serve(socket, req) do
  req = socket
  |> read_line()
  |> parse(req)

  serve(socket, req)
end
defp parse(data, %Request{awaiting: :statusline} = req) do
  %{req | statusline: data, awaiting: :headers}
end

defp parse("", %Request{awaiting: :headers} = req) do
  %{req | awaiting: :response}
end

defp parse(data, %Request{awaiting: :headers} = req) do
  %{req | headers: [parse_header(data) | req.headers] , awaiting: :headers}
end
defp respond(req, {plug, opts}, socket) do
  Request.build_conn(req, socket)
  |> plug.call(opts)
end
# ther 
%Plug.Conn{}
def build_conn(%Stupify.Request{} = req, socket) do
  { verb, path, version } = parse_statusline(req.statusline)
  headers = Enum.into(req.headers, %{})
  IO.inspect %Plug.Conn{
    host: headers["host"],
    method: verb,
    request_path: path,
    req_headers: headers,
    scheme: :http,
    adapter: {Stupify, socket},
    owner: self()
  }
end
def send_resp(%Conn{adapter: {adapter, payload}, state: :set, owner: owner} = conn) do
  adapter.send_resp(payload, conn.status, conn.resp_headers, conn.resp_body)
end
defmodule Plug.Conn do
  # ...
  def send_resp(socket, status, headers, body) do
    reason = Plug.Conn.Status.reason_phrase(status)
    write_line("HTTP/1.1 #{status} #{reason}", socket)
    send_headers headers, socket
    write_line("", socket)
    write_line(body, socket)
   {:ok, nil, socket}
  end
end
defmodule Plug.Conn.Adapter do
  @callback send_resp(payload, Conn.status, Conn.headers, Conn.body) ::
              {:ok, sent_body :: binary | nil, payload}

  @callback send_file(payload, Conn.status, Conn.headers, file :: binary,
                        offset :: integer, length :: integer | :all) ::
              {:ok, sent_body :: binary | nil, payload}

  @callback send_chunked(payload, Conn.status, Conn.headers) ::
              {:ok, sent_body :: binary | nil, payload}

  @callback chunk(payload, Conn.status) ::
              :ok | {:ok, sent_body :: binary, payload} | {:error, term}

  @callback read_req_body(payload, options :: Keyword.t) ::
              {:ok, data :: binary, payload} |
              {:more, data :: binary, payload} |
              {:error, term}

  @callback parse_req_multipart(payload, options :: Keyword.t, fun) ::
              {:ok, Conn.params, payload} | {:more, Conn.params, payload}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment