zf

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

util.ex (6131B)


      1 defmodule Mint.Core.Util do
      2   @moduledoc false
      3 
      4   @unallowed_trailing_headers MapSet.new([
      5                                 "content-encoding",
      6                                 "content-length",
      7                                 "content-range",
      8                                 "content-type",
      9                                 "trailer",
     10                                 "transfer-encoding",
     11 
     12                                 # Control headers (https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7231.html#rfc.section.5.1)
     13                                 "cache-control",
     14                                 "expect",
     15                                 "host",
     16                                 "max-forwards",
     17                                 "pragma",
     18                                 "range",
     19                                 "te",
     20 
     21                                 # Conditionals (https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7231.html#rfc.section.5.2)
     22                                 "if-match",
     23                                 "if-none-match",
     24                                 "if-modified-since",
     25                                 "if-unmodified-since",
     26                                 "if-range",
     27 
     28                                 # Authentication/authorization (https://tools.ietf.org/html/rfc7235#section-5.3)
     29                                 "authorization",
     30                                 "proxy-authenticate",
     31                                 "proxy-authorization",
     32                                 "www-authenticate",
     33 
     34                                 # Cookie management (https://tools.ietf.org/html/rfc6265)
     35                                 "cookie",
     36                                 "set-cookie",
     37 
     38                                 # Control data (https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7231.html#rfc.section.7.1)
     39                                 "age",
     40                                 "cache-control",
     41                                 "expires",
     42                                 "date",
     43                                 "location",
     44                                 "retry-after",
     45                                 "vary",
     46                                 "warning"
     47                               ])
     48 
     49   # We have to do this if/else dance inside the macro because defguard
     50   # is not available in Elixir 1.5, and macro expansion would raise
     51   # when expanding the if even if we were on Elixir 1.5. This way, we
     52   # only expand to the defguard code if we are on Elixir 1.10 and on
     53   # (which is where this macro is supported).
     54   defmacro define_is_connection_message_guard do
     55     # TODO: Remove the conditional definition when we depend on Elixir 1.10+
     56     # TODO: Use is_struct/2 and map.field access when we depend on Elixir 1.11+
     57     if Version.match?(System.version(), ">= 1.10.0") do
     58       quote do
     59         @doc since: "1.1.0"
     60         defguard is_connection_message(conn, message)
     61                  when is_map(conn) and
     62                         is_tuple(message) and
     63                         is_map_key(conn, :__struct__) and
     64                         is_map_key(conn, :socket) and
     65                         is_atom(:erlang.map_get(:__struct__, conn)) and
     66                         elem(message, 1) == :erlang.map_get(:socket, conn) and
     67                         ((elem(message, 0) in [:ssl, :tcp] and tuple_size(message) == 3) or
     68                            (elem(message, 0) in [:ssl_closed, :tcp_closed] and
     69                               tuple_size(message) == 2) or
     70                            (elem(message, 0) in [:ssl_error, :tcp_error] and
     71                               tuple_size(message) == 3))
     72       end
     73     else
     74       quote do
     75         defmacro is_connection_message(_conn, _message) do
     76           raise ArgumentError,
     77                 "the is_connection_message/2 macro is only available with Elixir 1.10+"
     78         end
     79       end
     80     end
     81   end
     82 
     83   def hostname(opts, address) do
     84     case Keyword.fetch(opts, :hostname) do
     85       {:ok, hostname} ->
     86         hostname
     87 
     88       :error when is_binary(address) ->
     89         address
     90 
     91       :error ->
     92         raise ArgumentError, "the :hostname option is required when address is not a binary"
     93     end
     94   end
     95 
     96   def inet_opts(transport, socket) do
     97     with {:ok, opts} <- transport.getopts(socket, [:sndbuf, :recbuf, :buffer]),
     98          buffer = calculate_buffer(opts),
     99          :ok <- transport.setopts(socket, buffer: buffer) do
    100       :ok
    101     end
    102   end
    103 
    104   def scheme_to_transport(:http), do: Mint.Core.Transport.TCP
    105   def scheme_to_transport(:https), do: Mint.Core.Transport.SSL
    106   def scheme_to_transport(module) when is_atom(module), do: module
    107 
    108   defp calculate_buffer(opts) do
    109     Keyword.fetch!(opts, :buffer)
    110     |> max(Keyword.fetch!(opts, :sndbuf))
    111     |> max(Keyword.fetch!(opts, :recbuf))
    112   end
    113 
    114   # Adds a header to the list of headers unless it's nil or it's already there.
    115   def put_new_header(headers, name, value)
    116 
    117   def put_new_header(headers, _name, nil) do
    118     headers
    119   end
    120 
    121   def put_new_header(headers, name, value) do
    122     if List.keymember?(headers, name, 0) do
    123       headers
    124     else
    125       [{name, value} | headers]
    126     end
    127   end
    128 
    129   def put_new_header_lazy(headers, name, fun) do
    130     if List.keymember?(headers, name, 0) do
    131       headers
    132     else
    133       [{name, fun.()} | headers]
    134     end
    135   end
    136 
    137   # Lowercases an ASCII string more efficiently than
    138   # String.downcase/1.
    139   def downcase_ascii(string),
    140     do: for(<<char <- string>>, do: <<downcase_ascii_char(char)>>, into: "")
    141 
    142   def downcase_ascii_char(char) when char in ?A..?Z, do: char + 32
    143   def downcase_ascii_char(char) when char in 0..127, do: char
    144 
    145   # If the buffer is empty, reusing the incoming data saves
    146   # a potentially large allocation of memory.
    147   # This should be fixed in a subsequent OTP release.
    148   def maybe_concat(<<>>, data), do: data
    149   def maybe_concat(buffer, data) when is_binary(buffer), do: buffer <> data
    150 
    151   def find_unallowed_trailing_header(headers) do
    152     Enum.find(headers, fn {name, _value} -> name in @unallowed_trailing_headers end)
    153   end
    154 
    155   def remove_unallowed_trailing_headers(headers) do
    156     Enum.reject(headers, fn {name, _value} -> name in @unallowed_trailing_headers end)
    157   end
    158 end