Packages
plug
1.7.0
1.20.3
1.20.2
1.20.1
retired
1.20.0
retired
1.19.5
1.19.4
1.19.3
1.19.2
1.19.1
1.19.0
1.18.5
1.18.4
1.18.3
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.6
1.16.5
1.16.4
1.16.3
1.16.2
1.16.1
1.16.0
1.15.6
1.15.5
1.15.4
1.15.3
1.15.2
1.15.1
1.15.0
1.14.2
1.14.1
1.14.0
1.13.6
1.13.5
1.13.4
1.13.3
1.13.2
1.13.1
retired
1.13.0
retired
1.12.1
1.12.0
1.11.1
1.11.0
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.0
1.8.3
1.8.2
1.8.1
1.8.0
1.7.2
1.7.1
1.7.0
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.5.0-rc.2
1.5.0-rc.1
1.5.0-rc.0
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.0
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc.0
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.14.0
0.13.1
0.13.0
0.12.2
0.12.1
0.12.0
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.0
0.5.3
0.5.2
0.5.1
0.5.0
0.4.4
0.4.3
0.4.2
0.4.1
Compose web applications with functions
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/plug/parsers/json.ex
defmodule Plug.Parsers.JSON do
@moduledoc """
Parses JSON request body.
JSON arrays are parsed into a `"_json"` key to allow
proper param merging.
An empty request body is parsed as an empty map.
## Options
All options supported by `Plug.Conn.read_body/2` are also supported here.
They are repeated here for convenience:
* `:length` - sets the maximum number of bytes to read from the request,
defaults to 8_000_000 bytes
* `:read_length` - sets the amount of bytes to read at one time from the
underlying socket to fill the chunk, defaults to 1_000_000 bytes
* `:read_timeout` - sets the timeout for each socket read, defaults to
15_000ms
So by default, `Plug.Parsers` will read 1_000_000 bytes at a time from the
socket with an overall limit of 8_000_000 bytes.
"""
@behaviour Plug.Parsers
def init(opts) do
{decoder, opts} = Keyword.pop(opts, :json_decoder)
{body_reader, opts} = Keyword.pop(opts, :body_reader, {Plug.Conn, :read_body, []})
validate_decoder!(decoder)
{body_reader, decoder, opts}
end
defp validate_decoder!(nil) do
raise ArgumentError, "JSON parser expects a :json_decoder option"
end
defp validate_decoder!({module, fun, args})
when is_atom(module) and is_atom(fun) and is_list(args) do
arity = length(args) + 1
unless Code.ensure_compiled?(module) and function_exported?(module, fun, arity) do
raise ArgumentError,
"invalid :json_decoder option. Undefined function " <>
Exception.format_mfa(module, fun, arity)
end
end
defp validate_decoder!(decoder) when is_atom(decoder) do
unless Code.ensure_compiled?(decoder) do
raise ArgumentError,
"invalid :json_decoder option. The module #{inspect(decoder)} is not " <>
"loaded and could not be found"
end
unless function_exported?(decoder, :decode!, 1) do
raise ArgumentError,
"invalid :json_decoder option. The module #{inspect(decoder)} must " <>
"implement decode!/1"
end
end
defp validate_decoder!(decoder) do
raise ArgumentError,
"the :json_decoder option expects a module, or a three-element " <>
"tuple in the form of {module, function, extra_args}, got: #{inspect(decoder)}"
end
def parse(conn, "application", subtype, _headers, {{mod, fun, args}, decoder, opts}) do
if subtype == "json" or String.ends_with?(subtype, "+json") do
apply(mod, fun, [conn, opts | args]) |> decode(decoder)
else
{:next, conn}
end
end
def parse(conn, _type, _subtype, _headers, _opts) do
{:next, conn}
end
defp decode({:ok, "", conn}, _decoder) do
{:ok, %{}, conn}
end
defp decode({:ok, body, conn}, decoder) do
case apply_mfa_or_module(body, decoder) do
terms when is_map(terms) ->
{:ok, terms, conn}
terms ->
{:ok, %{"_json" => terms}, conn}
end
rescue
e -> raise Plug.Parsers.ParseError, exception: e
end
defp decode({:more, _, conn}, _decoder) do
{:error, :too_large, conn}
end
defp decode({:error, :timeout}, _decoder) do
raise Plug.TimeoutError
end
defp decode({:error, _}, _decoder) do
raise Plug.BadRequestError
end
defp apply_mfa_or_module(body, decoder) when is_atom(decoder) do
decoder.decode!(body)
end
defp apply_mfa_or_module(body, {module_name, function_name, extra_args}) do
apply(module_name, function_name, [body | extra_args])
end
end