wojtekmach / req

Req is a batteries-included HTTP client for Elixir.

Home Page:https://hexdocs.pm/req

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`FunctionClauseError` due to mismatch of `ref` argument in `Req.Steps.finch_parse_message/2`

crkent opened this issue · comments

System details

Req version: 0.5.0
Elixir version: 1.16.3
OTP version: 26
OS: macOS 14.5

Issue

Collecting the following Stream (edited from an original form to provide minimal context) results in the following FunctionClauseError within the Req.Steps module (message is redacted, slightly, to protect the innocent).

    Stream.resource(
      fn -> {Req.get!(request, into: :self), {[], 0}} end,
      fn
        :halt -> {:halt, nil}
        {response, {acc, byte_size}} ->
          case Req.parse_message(response, receive do message -> message end) do
            {:ok, [{:data, data}]} ->
              acc = [data | acc]
              byte_size = :erlang.iolist_size(data) + byte_size
              if(byte_size > 5_000_000, do: {[acc], {response, {[], 0}}}, else: {[], {response, {acc, byte_size}}})
            {:ok, [:done]} -> {[acc], :halt}
            {:error, reason} -> raise "Error"
          end
      end,
      fn _ -> nil end
    )
** (FunctionClauseError) no function clause matching in Req.Steps.finch_parse_message/2    
    
    The following arguments were given to Req.Steps.finch_parse_message/2:
    
        # 1
        {Finch.HTTP1.Pool, #PID<0.1532.0>}
    
        # 2
        {{Finch.HTTP1.Pool, #PID<0.1339.0>},
         {:data, "<REDACTED>"}}
    
    Attempted function clauses (showing 4 out of 4):
    
        defp finch_parse_message(ref, {ref, {:data, data}})
        defp finch_parse_message(ref, {ref, :done})
        defp finch_parse_message(ref, {ref, {:trailers, trailers}})
        defp finch_parse_message(ref, {ref, {:error, reason}})
    
    (req 0.5.0) Req.Steps.finch_parse_message/2
    ...
    ...

It appears that the match error is due to some impurity in the way that the ref argument to Req.Steps.finch_parse_message/2 is obtained. This impurity appears to result in a difference between the two PIDs.

Expected behaviour

I believe that, when collected within a single process, the following Stream should run without error.

Thank you for the report. This is very unexpected indeed. If you have a way to reproduce it, it would be a great help, ideally a "Mix.install script" with Req and, say, Bandit.

Thank you for the report. This is very unexpected indeed. If you have a way to reproduce it, it would be a great help, ideally a "Mix.install script" with Req and, say, Bandit.

Minimal reproducible example

I omitted Bandit and used a simple url that is utilized in the Req documentation.

Setup

Mix.install([{:req, "== 0.5.1"}])

Error producing evaluation

request =
  Req.new(
    url: "https://github.com/elixir-lang/elixir/releases/download/v1.15.4/elixir-otp-26.zip"
  )

resource =
  Stream.resource(
    fn -> {Req.get!(request, into: :self), {[], 0}} end,
    fn
      :halt ->
        {:halt, nil}

      {response, {acc, byte_size}} ->
        case Req.parse_message(
               response,
               receive do
                 message -> message
               end
             ) do
          {:ok, [{:data, data}]} ->
            acc = [data | acc]
            byte_size = :erlang.iolist_size(data) + byte_size

            if(byte_size > 5_000_000,
              do: {[acc], {response, {[], 0}}},
              else: {[], {response, {acc, byte_size}}}
            )

          {:ok, [:done]} ->
            {[acc], :halt}

          {:error, reason} ->
            raise "Error"
        end
    end,
    fn _ -> nil end
  )

resource |> Enum.take(1)

Output


12:35:45.065 [debug] redirecting to https://objects.githubusercontent.com/github-production-release-asset-2e65be/1234714/35ca722a-7fc3-402e-8636-532b07322a9e?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=releaseassetproduction%2F20240627%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240627T183545Z&X-Amz-Expires=300&X-Amz-Signature=d831212fe78d04b391002ebddd33ac99bf43f420918793ccd8eb6c99759bccda&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=1234714&response-content-disposition=attachment%3B%20filename%3Delixir-otp-26.zip&response-content-type=application%2Foctet-stream

** (FunctionClauseError) no function clause matching in Req.Steps.finch_parse_message/2    
    
    The following arguments were given to Req.Steps.finch_parse_message/2:
    
        # 1
        {Finch.HTTP1.Pool, #PID<0.1066.0>}
    
        # 2
        {{Finch.HTTP1.Pool, #PID<0.1041.0>},
         {:data,
          <<80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 81, 78, 242, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 28,
            0, 98, 105, 110, 47, 85, 84, 9, 0, 3, 106, 96, 182, 100, 128, 96, 182, ...>>}}
    
    Attempted function clauses (showing 4 out of 4):
    
        defp finch_parse_message(ref, {ref, {:data, data}})
        defp finch_parse_message(ref, {ref, :done})
        defp finch_parse_message(ref, {ref, {:trailers, trailers}})
        defp finch_parse_message(ref, {ref, {:error, reason}})
    
    (req 0.5.1) lib/req/steps.ex:1013: Req.Steps.finch_parse_message/2
    #cell:amhewdr7w47z3ujd:8: (file)
    #cell:amhewdr7w47z3ujd:1: (file)

Thank you for reproduction, it was extremely helpful. I just submitted fix to main, could you give it a go?

Works perfectly! Thank you!