transport_error.ex (2642B)
1 defmodule Mint.TransportError do 2 @moduledoc """ 3 Represents an error with the transport used by an HTTP connection. 4 5 A `Mint.TransportError` struct is an exception, so it can be raised as any 6 other exception. 7 8 ## Struct fields 9 10 This exception represents an error with the transport (TCP or SSL) used 11 by an HTTP connection. The exception struct itself is opaque, that is, 12 not all fields are public. The following are the public fields: 13 14 * `:reason` - a term representing the error reason. The value of this field 15 can be: 16 17 * `:timeout` - if there's a timeout in interacting with the socket. 18 19 * `:closed` - if the connection has been closed. 20 21 * `:protocol_not_negotiated` - if the ALPN protocol negotiation failed. 22 23 * `{:bad_alpn_protocol, protocol}` - when the ALPN protocol is not 24 one of the supported protocols, which are `http/1.1` and `h2`. 25 26 * `t::inet.posix/0` - if there's any other error with the socket, 27 such as `:econnrefused` or `:nxdomain`. 28 29 * `t::ssl.error_alert/0` - if there's an SSL error. 30 31 ## Message representation 32 33 If you want to convert an error reason to a human-friendly message (for example 34 for using in logs), you can use `Exception.message/1`: 35 36 iex> {:error, %Mint.TransportError{} = error} = Mint.HTTP.connect(:http, "nonexistent", 80) 37 iex> Exception.message(error) 38 "non-existing domain" 39 40 """ 41 42 reason_type = 43 quote do 44 :timeout 45 | :closed 46 | :protocol_not_negotiated 47 | {:bad_alpn_protocol, String.t()} 48 | :inet.posix() 49 end 50 51 reason_type = 52 if System.otp_release() >= "21" do 53 quote do: unquote(reason_type) | :ssl.error_alert() 54 else 55 reason_type 56 end 57 58 @type t() :: %__MODULE__{reason: unquote(reason_type) | term()} 59 60 defexception [:reason] 61 62 def message(%__MODULE__{reason: reason}) do 63 format_reason(reason) 64 end 65 66 ## Our reasons. 67 68 defp format_reason(:protocol_not_negotiated) do 69 "ALPN protocol not negotiated" 70 end 71 72 defp format_reason({:bad_alpn_protocol, protocol}) do 73 "bad ALPN protocol #{inspect(protocol)}, supported protocols are \"http/1.1\" and \"h2\"" 74 end 75 76 defp format_reason(:closed) do 77 "socket closed" 78 end 79 80 defp format_reason(:timeout) do 81 "timeout" 82 end 83 84 # :ssl.format_error/1 falls back to :inet.format_error/1 when the error is not an SSL-specific 85 # error (at least since OTP 19+), so we can just use that. 86 defp format_reason(reason) do 87 case :ssl.format_error(reason) do 88 'Unexpected error:' ++ _ -> inspect(reason) 89 message -> List.to_string(message) 90 end 91 end 92 end