Key already defined error
samsondav opened this issue · comments
Yesterday we suddenly started seeing a lot of these in production:
Elixir.MatchError: no match of right hand side value: {:error, {:key_already_defined_as, "format"}}
File "lib/ace/http1/parser.ex", line 226, in Ace.HTTP1.Parser.build_partial_request/2
File "lib/ace/http1/parser.ex", line 130, in Ace.HTTP1.Parser.pop_part/1
File "lib/ace/http1/parser.ex", line 49, in Ace.HTTP1.Parser.parse/3
File "lib/ace/http1/endpoint.ex", line 27, in Ace.HTTP1.Endpoint.handle_info/2
File "gen_server.erl", line 616, in :gen_server.try_dispatch/4
File "gen_server.erl", line 686, in :gen_server.handle_msg/6
File "gen_server.erl", line 636, in :gen_server.try_handle_call/4
File "gen_server.erl", line 665, in :gen_server.handle_msg/6
Module "Elixir.Ace.HTTP.Server", in Ace.HTTP.Server.init/1
Any clue?
This can be reproduced by hitting a URL where a parameter is dulplicated, for example ?foo=a&foo=b
, which falls through to this section of code in Raxx
The current behaviour is that this blows up, but the problem we have is that we will fail serving requests when third parties make mistakes. There's definitely an argument for that being the correct behaviour, but it might be useful to make this configurable, as there may be use cases where you just want to take the last value passed or treat it as a List (for example).
There's a relevant SO question which points out there is no defined standard for what should be done here, so for Raxx
it might be sensible to make this configurable.
Happy to help in making this configurable if that's an acceptable solution?
This has been raised in Ace
as that's where we've initially seen the issue, should we move this over to Raxx
?
Thanks for the context @seddy
I hadn't realised the nuances involved with query strings when I started raxx. There is also the question of handling nested queries or not? None of this is specified in https://tools.ietf.org/html/rfc7230.
I think the correct behaviour is for Raxx not to specify query parsing.
So my suggestion is as follows:
example.com/
has querynil
example.com/?
has query""
example.com/?anything
has query"anything"
I would then also add a fetch_query function to raxx
Raxx.fetch_query(request)
returns {:ok, map} or {:error, :malformed_query}
If anyone wanted to tackle this I think to get started all that is needed is to remove calls to URI2 and then add the function described above.
Fixed in versions 0.16.x