zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

conn.ex (4397B)


      1 defmodule Plug.Cowboy.Conn do
      2   @behaviour Plug.Conn.Adapter
      3   @moduledoc false
      4 
      5   def conn(req) do
      6     %{
      7       path: path,
      8       host: host,
      9       port: port,
     10       method: method,
     11       headers: headers,
     12       qs: qs,
     13       peer: {remote_ip, _}
     14     } = req
     15 
     16     %Plug.Conn{
     17       adapter: {__MODULE__, req},
     18       host: host,
     19       method: method,
     20       owner: self(),
     21       path_info: split_path(path),
     22       port: port,
     23       remote_ip: remote_ip,
     24       query_string: qs,
     25       req_headers: to_headers_list(headers),
     26       request_path: path,
     27       scheme: String.to_atom(:cowboy_req.scheme(req))
     28     }
     29   end
     30 
     31   @impl true
     32   def send_resp(req, status, headers, body) do
     33     headers = to_headers_map(headers)
     34     status = Integer.to_string(status) <> " " <> Plug.Conn.Status.reason_phrase(status)
     35     req = :cowboy_req.reply(status, headers, body, req)
     36     {:ok, nil, req}
     37   end
     38 
     39   @impl true
     40   def send_file(req, status, headers, path, offset, length) do
     41     %File.Stat{type: :regular, size: size} = File.stat!(path)
     42 
     43     length =
     44       cond do
     45         length == :all -> size
     46         is_integer(length) -> length
     47       end
     48 
     49     body = {:sendfile, offset, length, path}
     50     headers = to_headers_map(headers)
     51     req = :cowboy_req.reply(status, headers, body, req)
     52     {:ok, nil, req}
     53   end
     54 
     55   @impl true
     56   def send_chunked(req, status, headers) do
     57     headers = to_headers_map(headers)
     58     req = :cowboy_req.stream_reply(status, headers, req)
     59     {:ok, nil, req}
     60   end
     61 
     62   @impl true
     63   def chunk(req, body) do
     64     :cowboy_req.stream_body(body, :nofin, req)
     65   end
     66 
     67   @impl true
     68   def read_req_body(req, opts) do
     69     length = Keyword.get(opts, :length, 8_000_000)
     70     read_length = Keyword.get(opts, :read_length, 1_000_000)
     71     read_timeout = Keyword.get(opts, :read_timeout, 15_000)
     72 
     73     opts = %{length: read_length, period: read_timeout}
     74     read_req_body(req, opts, length, [])
     75   end
     76 
     77   defp read_req_body(req, opts, length, acc) when length >= 0 do
     78     case :cowboy_req.read_body(req, opts) do
     79       {:ok, data, req} -> {:ok, IO.iodata_to_binary([acc | data]), req}
     80       {:more, data, req} -> read_req_body(req, opts, length - byte_size(data), [acc | data])
     81     end
     82   end
     83 
     84   defp read_req_body(req, _opts, _length, acc) do
     85     {:more, IO.iodata_to_binary(acc), req}
     86   end
     87 
     88   @impl true
     89   def inform(req, status, headers) do
     90     :cowboy_req.inform(status, to_headers_map(headers), req)
     91   end
     92 
     93   @impl true
     94   def upgrade(req, :websocket, args) do
     95     case args do
     96       {handler, _state, cowboy_opts} when is_atom(handler) and is_map(cowboy_opts) ->
     97         :ok
     98 
     99       _ ->
    100         raise ArgumentError,
    101               "expected websocket upgrade on Cowboy to be on the format {handler :: atom(), arg :: term(), opts :: map()}, got: " <>
    102                 inspect(args)
    103     end
    104 
    105     {:ok, Map.put(req, :upgrade, {:websocket, args})}
    106   end
    107 
    108   def upgrade(_req, _protocol, _args), do: {:error, :not_supported}
    109 
    110   @impl true
    111   def push(req, path, headers) do
    112     opts =
    113       case {req.port, req.sock} do
    114         {:undefined, {_, port}} -> %{port: port}
    115         {port, _} when port in [80, 443] -> %{}
    116         {port, _} -> %{port: port}
    117       end
    118 
    119     :cowboy_req.push(path, to_headers_map(headers), req, opts)
    120   end
    121 
    122   @impl true
    123   def get_peer_data(%{peer: {ip, port}, cert: cert}) do
    124     %{
    125       address: ip,
    126       port: port,
    127       ssl_cert: if(cert == :undefined, do: nil, else: cert)
    128     }
    129   end
    130 
    131   @impl true
    132   def get_http_protocol(req) do
    133     :cowboy_req.version(req)
    134   end
    135 
    136   ## Helpers
    137 
    138   defp to_headers_list(headers) when is_list(headers) do
    139     headers
    140   end
    141 
    142   defp to_headers_list(headers) when is_map(headers) do
    143     :maps.to_list(headers)
    144   end
    145 
    146   defp to_headers_map(headers) when is_list(headers) do
    147     # Group set-cookie headers into a list for a single `set-cookie`
    148     # key since cowboy 2 requires headers as a map.
    149     Enum.reduce(headers, %{}, fn
    150       {key = "set-cookie", value}, acc ->
    151         case acc do
    152           %{^key => existing} -> %{acc | key => [value | existing]}
    153           %{} -> Map.put(acc, key, [value])
    154         end
    155 
    156       {key, value}, acc ->
    157         case acc do
    158           %{^key => existing} -> %{acc | key => existing <> ", " <> value}
    159           %{} -> Map.put(acc, key, value)
    160         end
    161     end)
    162   end
    163 
    164   defp split_path(path) do
    165     segments = :binary.split(path, "/", [:global])
    166     for segment <- segments, segment != "", do: segment
    167   end
    168 end