zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

json.ex (3218B)


      1 defmodule Plug.Parsers.JSON do
      2   @moduledoc """
      3   Parses JSON request body.
      4 
      5   JSON documents that aren't maps (arrays, strings, numbers, etc) are parsed
      6   into a `"_json"` key to allow proper param merging.
      7 
      8   An empty request body is parsed as an empty map.
      9 
     10   ## Options
     11 
     12   All options supported by `Plug.Conn.read_body/2` are also supported here.
     13   They are repeated here for convenience:
     14 
     15     * `:length` - sets the maximum number of bytes to read from the request,
     16       defaults to 8_000_000 bytes
     17     * `:read_length` - sets the amount of bytes to read at one time from the
     18       underlying socket to fill the chunk, defaults to 1_000_000 bytes
     19     * `:read_timeout` - sets the timeout for each socket read, defaults to
     20       15_000ms
     21 
     22   So by default, `Plug.Parsers` will read 1_000_000 bytes at a time from the
     23   socket with an overall limit of 8_000_000 bytes.
     24   """
     25 
     26   @behaviour Plug.Parsers
     27 
     28   @impl true
     29   def init(opts) do
     30     {decoder, opts} = Keyword.pop(opts, :json_decoder)
     31     {body_reader, opts} = Keyword.pop(opts, :body_reader, {Plug.Conn, :read_body, []})
     32     decoder = validate_decoder!(decoder)
     33     {body_reader, decoder, opts}
     34   end
     35 
     36   defp validate_decoder!(nil) do
     37     raise ArgumentError, "JSON parser expects a :json_decoder option"
     38   end
     39 
     40   defp validate_decoder!({module, fun, args} = mfa)
     41        when is_atom(module) and is_atom(fun) and is_list(args) do
     42     arity = length(args) + 1
     43 
     44     if Code.ensure_compiled(module) != {:module, module} do
     45       raise ArgumentError,
     46             "invalid :json_decoder option. The module #{inspect(module)} is not " <>
     47               "loaded and could not be found"
     48     end
     49 
     50     if not function_exported?(module, fun, arity) do
     51       raise ArgumentError,
     52             "invalid :json_decoder option. The module #{inspect(module)} must " <>
     53               "implement #{fun}/#{arity}"
     54     end
     55 
     56     mfa
     57   end
     58 
     59   defp validate_decoder!(decoder) when is_atom(decoder) do
     60     validate_decoder!({decoder, :decode!, []})
     61   end
     62 
     63   defp validate_decoder!(decoder) do
     64     raise ArgumentError,
     65           "the :json_decoder option expects a module, or a three-element " <>
     66             "tuple in the form of {module, function, extra_args}, got: #{inspect(decoder)}"
     67   end
     68 
     69   @impl true
     70   def parse(conn, "application", subtype, _headers, {{mod, fun, args}, decoder, opts}) do
     71     if subtype == "json" or String.ends_with?(subtype, "+json") do
     72       apply(mod, fun, [conn, opts | args]) |> decode(decoder)
     73     else
     74       {:next, conn}
     75     end
     76   end
     77 
     78   def parse(conn, _type, _subtype, _headers, _opts) do
     79     {:next, conn}
     80   end
     81 
     82   defp decode({:ok, "", conn}, _decoder) do
     83     {:ok, %{}, conn}
     84   end
     85 
     86   defp decode({:ok, body, conn}, {module, fun, args}) do
     87     try do
     88       apply(module, fun, [body | args])
     89     rescue
     90       e -> raise Plug.Parsers.ParseError, exception: e
     91     else
     92       terms when is_map(terms) ->
     93         {:ok, terms, conn}
     94 
     95       terms ->
     96         {:ok, %{"_json" => terms}, conn}
     97     end
     98   end
     99 
    100   defp decode({:more, _, conn}, _decoder) do
    101     {:error, :too_large, conn}
    102   end
    103 
    104   defp decode({:error, :timeout}, _decoder) do
    105     raise Plug.TimeoutError
    106   end
    107 
    108   defp decode({:error, _}, _decoder) do
    109     raise Plug.BadRequestError
    110   end
    111 end