zf

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

negotiate.ex (3792B)


      1 defmodule Mint.Negotiate do
      2   @moduledoc false
      3 
      4   import Mint.Core.Util
      5 
      6   alias Mint.{
      7     HTTP1,
      8     HTTP2,
      9     TransportError
     10   }
     11 
     12   @default_protocols [:http1, :http2]
     13   @transport_opts [alpn_advertised_protocols: ["http/1.1", "h2"]]
     14 
     15   def connect(scheme, address, port, opts \\ []) do
     16     {protocols, opts} = Keyword.pop(opts, :protocols, @default_protocols)
     17 
     18     case Enum.sort(protocols) do
     19       [:http1] ->
     20         HTTP1.connect(scheme, address, port, opts)
     21 
     22       [:http2] ->
     23         HTTP2.connect(scheme, address, port, opts)
     24 
     25       [:http1, :http2] ->
     26         transport_connect(scheme, address, port, opts)
     27     end
     28   end
     29 
     30   def upgrade(proxy_scheme, transport_state, scheme, hostname, port, opts) do
     31     {protocols, opts} = Keyword.pop(opts, :protocols, @default_protocols)
     32 
     33     case Enum.sort(protocols) do
     34       [:http1] ->
     35         HTTP1.upgrade(proxy_scheme, transport_state, scheme, hostname, port, opts)
     36 
     37       [:http2] ->
     38         HTTP2.upgrade(proxy_scheme, transport_state, scheme, hostname, port, opts)
     39 
     40       [:http1, :http2] ->
     41         transport_upgrade(proxy_scheme, transport_state, scheme, hostname, port, opts)
     42     end
     43   end
     44 
     45   def initiate(transport, transport_state, hostname, port, opts),
     46     do: alpn_negotiate(transport, transport_state, hostname, port, opts)
     47 
     48   defp transport_connect(:http, address, port, opts) do
     49     # HTTP1 upgrade is not supported
     50     HTTP1.connect(:http, address, port, opts)
     51   end
     52 
     53   defp transport_connect(:https, address, port, opts) do
     54     connect_negotiate(:https, address, port, opts)
     55   end
     56 
     57   defp connect_negotiate(scheme, address, port, opts) do
     58     transport = scheme_to_transport(scheme)
     59     hostname = Mint.Core.Util.hostname(opts, address)
     60 
     61     transport_opts =
     62       opts
     63       |> Keyword.get(:transport_opts, [])
     64       |> Keyword.merge(@transport_opts)
     65       |> Keyword.put(:hostname, hostname)
     66 
     67     with {:ok, transport_state} <- transport.connect(address, port, transport_opts) do
     68       alpn_negotiate(scheme, transport_state, hostname, port, opts)
     69     end
     70   end
     71 
     72   defp transport_upgrade(
     73          proxy_scheme,
     74          transport_state,
     75          :http,
     76          hostname,
     77          port,
     78          opts
     79        ) do
     80     # HTTP1 upgrade is not supported
     81     HTTP1.upgrade(proxy_scheme, transport_state, :http, hostname, port, opts)
     82   end
     83 
     84   defp transport_upgrade(
     85          proxy_scheme,
     86          transport_state,
     87          :https,
     88          hostname,
     89          port,
     90          opts
     91        ) do
     92     connect_upgrade(proxy_scheme, transport_state, :https, hostname, port, opts)
     93   end
     94 
     95   defp connect_upgrade(proxy_scheme, transport_state, new_scheme, hostname, port, opts) do
     96     transport = scheme_to_transport(new_scheme)
     97 
     98     transport_opts =
     99       opts
    100       |> Keyword.get(:transport_opts, [])
    101       |> Keyword.merge(@transport_opts)
    102 
    103     case transport.upgrade(transport_state, proxy_scheme, hostname, port, transport_opts) do
    104       {:ok, transport_state} ->
    105         alpn_negotiate(new_scheme, transport_state, hostname, port, opts)
    106 
    107       {:error, reason} ->
    108         {:error, %TransportError{reason: reason}}
    109     end
    110   end
    111 
    112   defp alpn_negotiate(scheme, socket, hostname, port, opts) do
    113     transport = scheme_to_transport(scheme)
    114 
    115     case transport.negotiated_protocol(socket) do
    116       {:ok, "http/1.1"} ->
    117         HTTP1.initiate(scheme, socket, hostname, port, opts)
    118 
    119       {:ok, "h2"} ->
    120         HTTP2.initiate(scheme, socket, hostname, port, opts)
    121 
    122       {:error, %TransportError{reason: :protocol_not_negotiated}} ->
    123         # Assume HTTP1 if ALPN is not supported
    124         HTTP1.initiate(scheme, socket, hostname, port, opts)
    125 
    126       {:ok, protocol} ->
    127         {:error, %TransportError{reason: {:bad_alpn_protocol, protocol}}}
    128 
    129       {:error, %TransportError{} = error} ->
    130         {:error, error}
    131     end
    132   end
    133 end