adapter.ex (5139B)
1 defmodule Plug.Conn.Adapter do 2 @moduledoc """ 3 Specification of the connection adapter API implemented by webservers. 4 """ 5 alias Plug.Conn 6 7 @type http_protocol :: :"HTTP/1" | :"HTTP/1.1" | :"HTTP/2" | atom 8 @type payload :: term 9 @type peer_data :: %{ 10 address: :inet.ip_address(), 11 port: :inet.port_number(), 12 ssl_cert: binary | nil 13 } 14 15 @doc """ 16 Function used by adapters to create a new connection. 17 """ 18 def conn(adapter, method, uri, remote_ip, req_headers) do 19 %URI{path: path, host: host, port: port, query: qs, scheme: scheme} = uri 20 21 %Plug.Conn{ 22 adapter: adapter, 23 host: host, 24 method: method, 25 owner: self(), 26 path_info: split_path(path), 27 port: port, 28 remote_ip: remote_ip, 29 query_string: qs || "", 30 req_headers: req_headers, 31 request_path: path, 32 scheme: String.to_atom(scheme) 33 } 34 end 35 36 defp split_path(path) do 37 segments = :binary.split(path, "/", [:global]) 38 for segment <- segments, segment != "", do: segment 39 end 40 41 @doc """ 42 Sends the given status, headers and body as a response 43 back to the client. 44 45 If the request has method `"HEAD"`, the adapter should 46 not send the response to the client. 47 48 Webservers are advised to return `nil` as the sent_body, 49 as the body can no longer be manipulated. However, the 50 test implementation returns the actual body so it can 51 be used during testing. 52 """ 53 @callback send_resp( 54 payload, 55 status :: Conn.status(), 56 headers :: Conn.headers(), 57 body :: Conn.body() 58 ) :: 59 {:ok, sent_body :: binary | nil, payload} 60 61 @doc """ 62 Sends the given status, headers and file as a response 63 back to the client. 64 65 If the request has method `"HEAD"`, the adapter should 66 not send the response to the client. 67 68 Webservers are advised to return `nil` as the sent_body, 69 as the body can no longer be manipulated. However, the 70 test implementation returns the actual body so it can 71 be used during testing. 72 """ 73 @callback send_file( 74 payload, 75 status :: Conn.status(), 76 headers :: Conn.headers(), 77 file :: binary, 78 offset :: integer, 79 length :: integer | :all 80 ) :: {:ok, sent_body :: binary | nil, payload} 81 82 @doc """ 83 Sends the given status, headers as the beginning of 84 a chunked response to the client. 85 86 Webservers are advised to return `nil` as the sent_body, 87 as the body can no longer be manipulated. However, the 88 test implementation returns the actual body so it can 89 be used during testing. 90 """ 91 @callback send_chunked(payload, status :: Conn.status(), headers :: Conn.headers()) :: 92 {:ok, sent_body :: binary | nil, payload} 93 94 @doc """ 95 Sends a chunk in the chunked response. 96 97 If the request has method `"HEAD"`, the adapter should 98 not send the response to the client. 99 100 Webservers are advised to return `:ok` and not modify 101 any further state for each chunk. However, the test 102 implementation returns the actual body and payload so 103 it can be used during testing. 104 """ 105 @callback chunk(payload, body :: Conn.body()) :: 106 :ok | {:ok, sent_body :: binary, payload} | {:error, term} 107 108 @doc """ 109 Reads the request body. 110 111 Read the docs in `Plug.Conn.read_body/2` for the supported 112 options and expected behaviour. 113 """ 114 @callback read_req_body(payload, options :: Keyword.t()) :: 115 {:ok, data :: binary, payload} 116 | {:more, data :: binary, payload} 117 | {:error, term} 118 119 @doc """ 120 Push a resource to the client. 121 122 If the adapter does not support server push then `{:error, :not_supported}` 123 should be returned. 124 """ 125 @callback push(payload, path :: String.t(), headers :: Keyword.t()) :: :ok | {:error, term} 126 127 @doc """ 128 Send an informational response to the client. 129 130 If the adapter does not support inform, then `{:error, :not_supported}` 131 should be returned. 132 """ 133 @callback inform(payload, status :: Conn.status(), headers :: Keyword.t()) :: 134 :ok | {:error, term} 135 136 @doc """ 137 Attempt to upgrade the connection with the client. 138 139 If the adapter does not support the indicated upgrade, then `{:error, :not_supported}` should be 140 be returned. 141 142 If the adapter supports the indicated upgrade but is unable to proceed with it (due to 143 a negotiation error, invalid opts being passed to this function, or some other reason), then an 144 arbitrary error may be returned. Note that an adapter does not need to process the actual 145 upgrade within this function; it is a wholly supported failure mode for an adapter to attempt 146 the upgrade process later in the connection lifecycle and fail at that point. 147 """ 148 @callback upgrade(payload, protocol :: atom, opts :: term) :: {:ok, payload} | {:error, term} 149 150 @doc """ 151 Returns peer information such as the address, port and ssl cert. 152 """ 153 @callback get_peer_data(payload) :: peer_data() 154 155 @doc """ 156 Returns the HTTP protocol and its version. 157 """ 158 @callback get_http_protocol(payload) :: http_protocol 159 end