Skip to content

Commit

Permalink
Fix body read timeout issue. Using suggestion from phoenixframework/p…
Browse files Browse the repository at this point in the history
  • Loading branch information
endeepak committed Nov 11, 2015
1 parent 2ecb834 commit 4719255
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 4 deletions.
5 changes: 2 additions & 3 deletions lib/stub_on_web/endpoint.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@ defmodule StubOnWeb.Endpoint do
plug Plug.Logger

defp copy_req_body(conn, _) do
{:ok, body, _} = Plug.Conn.read_body(conn, length: 1_000_000_000)
Plug.Conn.put_private(conn, :raw_request_body, body)
Plug.Conn.put_private(conn, :copy_raw_body, true)
end

plug :copy_req_body

plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
parsers: [StubOnWeb.Parsers.URLENCODED, :multipart, StubOnWeb.Parsers.JSON],
pass: ["*/*"],
json_decoder: Poison

Expand Down
80 changes: 80 additions & 0 deletions lib/stub_on_web/parser_patch.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
defmodule StubOnWeb.Parsers.URLENCODED do
@moduledoc """
Parses urlencoded request body, and optionally copies the raw body
Copies raw body to `:raw_body` private assign when `:copy_raw_body`
private assign is true
"""

@behaviour Plug.Parsers
alias Plug.Conn

def parse(conn, "application", "x-www-form-urlencoded", _headers, opts) do
case Conn.read_body(conn, opts) do
{:ok, body, conn} ->
Plug.Conn.Utils.validate_utf8!(body, "urlencoded body")
decoded_body = Plug.Conn.Query.decode(body)
conn = if conn.private[:copy_raw_body] do Plug.Conn.put_private(conn, :raw_body, body) else conn end
{:ok, decoded_body, conn}
{:more, _data, conn} ->
{:error, :too_large, conn}
end
end

def parse(conn, _type, _subtype, _headers, _opts) do
{:next, conn}
end
end

defmodule StubOnWeb.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.
Copies raw body to `:raw_body` private assign when `:copy_raw_body`
private assign is true
"""

@behaviour Plug.Parsers
import Plug.Conn

def parse(conn, "application", subtype, _headers, opts) do
if subtype == "json" || String.ends_with?(subtype, "+json") do
decoder = Keyword.get(opts, :json_decoder) ||
raise ArgumentError, "JSON parser expects a :json_decoder option"
conn
|> read_body(opts)
|> decode(decoder)
else
{:next, conn}
end
end

def parse(conn, _type, _subtype, _headers, _opts) do
{:next, conn}
end

defp decode({:more, _, conn}, _decoder) do
{:error, :too_large, conn}
end

defp decode({:ok, "", conn}, _decoder) do
{:ok, %{}, conn}
end

defp decode({:ok, body, conn}, decoder) do
conn = if conn.private[:copy_raw_body] do Plug.Conn.put_private(conn, :raw_body, body) else conn end
case decoder.decode!(body) do
terms when is_map(terms) ->
{:ok, terms, conn}
terms ->
{:ok, %{"_json" => terms}, conn}
end
rescue
e -> raise Plug.Parsers.ParseError, exception: e
end
end
2 changes: 1 addition & 1 deletion web/models/stub_url.ex
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ defmodule StubOnWeb.StubUrl do

def _capture_call(stub_url, conn) do
request_headers = _get_request_headers(conn)
request_body = conn.private[:raw_request_body]
request_body = conn.private[:raw_body]
request_data = %{url: _get_url_from_conn(conn), body: request_body, method: conn.method, headers: request_headers}
response_headers = Enum.map(stub_url.response_headers, fn header -> %{name: header.name, value: header.value} end)
response_data = %{status: stub_url.response_status, headers: response_headers, body: stub_url.response_body}
Expand Down

0 comments on commit 4719255

Please sign in to comment.