Skip to content

Commit

Permalink
merge conflict resolved by manually selecting the 'Plug.Builder' vs. …
Browse files Browse the repository at this point in the history
…Plug.Builder for formatting consistency compared to one mention previous.
  • Loading branch information
bradhanks committed Dec 23, 2023
2 parents 2ae5864 + b05cd27 commit 40a3caa
Show file tree
Hide file tree
Showing 19 changed files with 279 additions and 229 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ jobs:
elixir: 1.10.4
otp: 21.3
- pair:
elixir: 1.14.4
otp: 25.3
elixir: 1.15.6
otp: 26.0
lint: lint
steps:
- uses: actions/checkout@v3
Expand Down
24 changes: 21 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
# Changelog

## v1.15.0-dev
## v1.15.2 (2023-11-14)

### Enhancements

* Optimize query decoding by 15% to 45% - this removes the previously deprecated `:limit` MFA and `:include_unnamed_parts_at` from MULTIPART
* Add `:assign_as` option to `Plug.RequestId`
* Improve performance of `Plug.RequestId`
* Avoid clashes between Plug nodes
* Add specs to `Plug.BasicAuth`
* Fix a bug with non-string `_method` body parameters in `Plug.MethodOverride`

## v1.15.1 (2023-10-06)

### Enhancements

* Relax requirement on `plug_crypto`

## v1.15.0 (2023-10-01)

### Enhancements

* Add `Plug.Conn.get_session/3` for default value
* Allow `Plug.SSL.configure/1` to accept all :ssl options
* Optimize query decoding by 15% to 45% - this removes the previously deprecated `:limit` MFA and `:include_unnamed_parts_at` from MULTIPART. This may be backwards incompatible for applications that were relying on ambiguous arguments, such as `user[][key]=1&user[][key]=2`, which has unspecified parsing behaviour

## v1.14.2 (2023-03-23)

Expand Down Expand Up @@ -216,7 +234,7 @@ Require Elixir v1.10+.
* [Plug.Parsers] Add option to skip utf8 validation
* [Plug.Parsers] Make multipart support MFA for `:length` limit
* [Plug.Static] Accept MFA for `:header` option

### Notes
* When implementing the `Plug.Exception` protocol, if the new `actions` function is not implemented, a warning will printed during compilation.

Expand Down
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ There are two options at the moment:
```elixir
def deps do
[
{:bandit, "~> 0.6"}
{:bandit, "~> 1.0"}
]
end
```
Expand Down Expand Up @@ -75,7 +75,7 @@ and the `websocket_adapter` project for the WebSocket bits. Since we need differ
routes, we will use the built-in `Plug.Router` for that:

```elixir
Mix.install([:plug, :bandit, :websock_adapter])
Mix.install([:bandit, :websock_adapter])

defmodule EchoServer do
def init(options) do
Expand Down Expand Up @@ -146,12 +146,11 @@ On a production system, you likely want to start your Plug pipeline under your a
$ mix new my_app --sup
```

Add both `:plug` and `:plug_cowboy` as dependencies in your `mix.exs`:
Add `:plug_cowboy` (or `:bandit`) as a dependency to your `mix.exs`:

```elixir
def deps do
[
{:plug, "~> 1.14"},
{:plug_cowboy, "~> 2.0"}
]
end
Expand Down
13 changes: 10 additions & 3 deletions lib/plug/basic_auth.ex
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ defmodule Plug.BasicAuth do
strings with only alphanumeric characters and space
"""
def basic_auth(conn, options \\ []) do
@spec basic_auth(Plug.Conn.t(), [auth_option]) :: Plug.Conn.t()
when auth_option: {:username, String.t()} | {:password, String.t()} | {:realm, String.t()}
def basic_auth(%Plug.Conn{} = conn, options \\ []) when is_list(options) do
username = Keyword.fetch!(options, :username)
password = Keyword.fetch!(options, :password)

Expand All @@ -116,7 +118,8 @@ defmodule Plug.BasicAuth do
See the module docs for examples.
"""
def parse_basic_auth(conn) do
@spec parse_basic_auth(Plug.Conn.t()) :: {user :: String.t(), password :: String.t()} | :error
def parse_basic_auth(%Plug.Conn{} = conn) do
with ["Basic " <> encoded_user_and_pass] <- get_req_header(conn, "authorization"),
{:ok, decoded_user_and_pass} <- Base.decode64(encoded_user_and_pass),
[user, pass] <- :binary.split(decoded_user_and_pass, ":") do
Expand All @@ -134,6 +137,7 @@ defmodule Plug.BasicAuth do
put_req_header(conn, "authorization", encode_basic_auth("hello", "world"))
"""
@spec encode_basic_auth(String.t(), String.t()) :: String.t()
def encode_basic_auth(user, pass) when is_binary(user) and is_binary(pass) do
"Basic " <> Base.encode64("#{user}:#{pass}")
end
Expand All @@ -150,8 +154,11 @@ defmodule Plug.BasicAuth do
* `:realm` - the authentication realm. The value is not fully
sanitized, so do not accept user input as the realm and use
strings with only alphanumeric characters and space
"""
def request_basic_auth(conn, options \\ []) when is_list(options) do
@spec request_basic_auth(Plug.Conn.t(), [option]) :: Plug.Conn.t()
when option: {:realm, String.t()}
def request_basic_auth(%Plug.Conn{} = conn, options \\ []) when is_list(options) do
realm = Keyword.get(options, :realm, "Application")
escaped_realm = String.replace(realm, "\"", "")

Expand Down
23 changes: 23 additions & 0 deletions lib/plug/builder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,29 @@ defmodule Plug.Builder do
By implementing the Plug API, `Plug.Builder` guarantees this module is a plug
and can be handed to a web server or used as part of another pipeline.
## Conditional plugs
Sometimes you may want to conditionally invoke a Plug in a pipeline. For example,
you may want to invoke `Plug.Parsers` only under certain routes. This can be done
by wrapping the module plug in a function plug. Instead of:
plug Plug.Parsers, parsers: [:urlencoded, :multipart], pass: ["text/*"]
You can write:
plug :conditional_parser
defp conditional_parser(%Plug.Conn{path_info: ["noparser" | _]} = conn, _opts) do
conn
end
@parser Plug.Parsers.init(parsers: [:urlencoded, :multipart], pass: ["text/*"])
defp conditional_parser(conn, _opts) do
Plug.Parsers.call(conn, @parser)
end
The above will invoke `Plug.Parsers` on all routes, except the ones under `/noparser`
## Overriding the default Plug API functions
Both the `init/1` and `call/2` functions defined by `Plug.Builder` can be
Expand Down
Loading

0 comments on commit 40a3caa

Please sign in to comment.