From 1e320a741f55dcee7415c8a7936394f451dc6de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 31 Oct 2024 09:55:49 +0100 Subject: [PATCH] Deprecate owner --- lib/plug/adapters/test/conn.ex | 8 ++++++-- lib/plug/conn.ex | 15 +++++++-------- lib/plug/conn/adapter.ex | 15 ++++++++++++++- test/plug/conn_test.exs | 3 +-- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/lib/plug/adapters/test/conn.ex b/lib/plug/adapters/test/conn.ex index 235772c9..99a64483 100644 --- a/lib/plug/adapters/test/conn.ex +++ b/lib/plug/adapters/test/conn.ex @@ -1,5 +1,6 @@ defmodule Plug.Adapters.Test.Conn do @behaviour Plug.Conn.Adapter + @already_sent Plug.Conn.Adapter.already_sent() @moduledoc false ## Test helpers @@ -43,7 +44,6 @@ defmodule Plug.Adapters.Test.Conn do | adapter: {__MODULE__, state}, host: uri.host || conn.host || "www.example.com", method: method, - owner: owner, path_info: split_path(uri.path), port: uri.port || conn_port, remote_ip: conn.remote_ip || {127, 0, 0, 1}, @@ -88,7 +88,10 @@ defmodule Plug.Adapters.Test.Conn do do_send(state, status, headers, data) end - def send_chunked(state, _status, _headers), do: {:ok, "", %{state | chunks: ""}} + def send_chunked(%{owner: owner} = state, _status, _headers) do + send(owner, @already_sent) + {:ok, "", %{state | chunks: ""}} + end def chunk(%{method: "HEAD"} = state, _body), do: {:ok, "", state} @@ -98,6 +101,7 @@ defmodule Plug.Adapters.Test.Conn do end defp do_send(%{owner: owner, ref: ref} = state, status, headers, body) do + send(owner, @already_sent) send(owner, {ref, {status, headers, body}}) {:ok, body, state} end diff --git a/lib/plug/conn.ex b/lib/plug/conn.ex index fc2e7c4c..d813588d 100644 --- a/lib/plug/conn.ex +++ b/lib/plug/conn.ex @@ -95,7 +95,6 @@ defmodule Plug.Conn do ## Connection fields * `assigns` - shared user data as a map - * `owner` - the Elixir process that owns the connection * `halted` - the boolean status on whether the pipeline was halted * `secret_key_base` - a secret key used to verify and encrypt cookies. These features require manual field setup. Data must be kept in the @@ -118,12 +117,13 @@ defmodule Plug.Conn do ## Deprecated fields + * `owner` - the Elixir process that handles the request. + * `cookies`- the request cookies with the response cookies. + Use `get_cookies/1` instead. * `path_params` - the request path params, populated by routers such as `Plug.Router`. Use `conn.params` instead. * `req_cookies` - the decoded request cookies (without decrypting or verifying them). Use `get_req_header/2` or `get_cookies/1` instead. - * `cookies`- the request cookies with the response cookies. - Use `get_cookies/1` instead. * `resp_cookies`- the request cookies with the response cookies. Use `get_resp_cookies/1` instead. @@ -178,7 +178,6 @@ defmodule Plug.Conn do @type headers :: [{binary, binary}] @type host :: binary @type int_status :: non_neg_integer | nil - @type owner :: pid @type method :: binary @type query_param :: binary | %{optional(binary) => query_param} | [query_param] @type query_params :: %{optional(binary) => query_param} @@ -200,7 +199,7 @@ defmodule Plug.Conn do halted: halted, host: host, method: method, - owner: owner, + owner: pid | nil, params: params | Unfetched.t(), path_info: segments, path_params: query_params, @@ -451,7 +450,7 @@ defmodule Plug.Conn do {:ok, body, payload} = adapter.send_resp(payload, conn.status, conn.resp_headers, conn.resp_body) - send(owner, @already_sent) + owner && send(owner, @already_sent) %{conn | adapter: {adapter, payload}, resp_body: body, state: :sent} end @@ -502,7 +501,7 @@ defmodule Plug.Conn do {:ok, body, payload} = adapter.send_file(payload, conn.status, conn.resp_headers, file, offset, length) - send(owner, @already_sent) + owner && send(owner, @already_sent) %{conn | adapter: {adapter, payload}, state: :file, resp_body: body} end @@ -530,7 +529,7 @@ defmodule Plug.Conn do conn = %{conn | status: Plug.Conn.Status.code(status), resp_body: nil} conn = run_before_send(conn, :set_chunked) {:ok, body, payload} = adapter.send_chunked(payload, conn.status, conn.resp_headers) - send(owner, @already_sent) + owner && send(owner, @already_sent) %{conn | adapter: {adapter, payload}, state: :chunked, resp_body: body} end diff --git a/lib/plug/conn/adapter.ex b/lib/plug/conn/adapter.ex index 3c0c81ce..32b5f238 100644 --- a/lib/plug/conn/adapter.ex +++ b/lib/plug/conn/adapter.ex @@ -1,6 +1,13 @@ defmodule Plug.Conn.Adapter do @moduledoc """ Specification of the connection adapter API implemented by webservers. + + ## Implementation recommendations + + The `owner` field of `Plug.Conn` is deprecated and no longer needs to + be set by adapters. If you don't set the `owner` field, it is the + responsibility of the adapters to track the owner and send the + `already_sent/0` message below on any of the `send_*` callbacks. """ alias Plug.Conn @@ -12,6 +19,13 @@ defmodule Plug.Conn.Adapter do ssl_cert: binary | nil } + @doc """ + The message to send to the request process on send callbacks. + """ + def already_sent do + {:plug_conn, :sent} + end + @doc """ Function used by adapters to create a new connection. """ @@ -22,7 +36,6 @@ defmodule Plug.Conn.Adapter do adapter: adapter, host: host, method: method, - owner: self(), path_info: split_path(path), port: port, remote_ip: remote_ip, diff --git a/test/plug/conn_test.exs b/test/plug/conn_test.exs index 91db7c69..3115f88b 100644 --- a/test/plug/conn_test.exs +++ b/test/plug/conn_test.exs @@ -1439,8 +1439,7 @@ defmodule Plug.ConnTest do end conn = %Conn{ - adapter: {RaisesOnEmptyChunkAdapter, %{chunks: ""}}, - owner: self(), + adapter: {RaisesOnEmptyChunkAdapter, %{chunks: "", owner: self()}}, state: :unset }