Closed tleish closed 1 year ago
It seems like in development you were using HTTP/1 and in production maybe HTTP/2.
Your header key/values are not strings. However, this should be normalised internally, so I'll investigate what is going on.
I have not had a chance to look into this much yet, but I can confirm one fix would be to ensure your hash keys and values are strings. However, this might be an oversight on my part, so I'd suggest holding off until I can take a closer look, which I'll endeavour to do so this week.
Ah, based on your tip the second error must be coming from this header key/value:
{
...
'X-Started-At': Time.now.to_f
}
which explains
NoMethodError: undefined method `split' for 1590246023.4250834:Float
I also have a different header for another call which includes:
{
...
'Accept': 'application/json',
}
Would this have caused the previous error of:
Caused by NoMethodError: undefined method `bytesize' for :accept:Symbol
The error shows accept
symbol in lower case, while the code declared it in upper.
I’m in bed but yes that key is probably a symbol, please use a string and report back. I’m planning to add specs for these cases tomorrow so I can review the details and lock down the semantics.
FYI, updated header key/values to all be strings and I no longer receive the prior reported errors. You can close this issue, unless you want to leave it open in order to update the client library to handle non-string key/values.
Yeah, at the very least it should probably issue a warning. I'm going to leave it open for now.
FYI, as an easy fix I added the following in a wrapper clas:
headers.transform_keys(&:to_s).transform_values(&:to_s)
Okay.
So, enforcing this is not free.
It's also not obvious what should be enforced.
HTTP/1 is relatively flexible.
HTTP/2 is less flexible.
The best option might be to put this into Protocol::HTTP::Headers::Merged
which should mitigate the issue:
# @yield [String, String] header key (lower case) and value (as string).
def each(&block)
@all.each do |headers|
headers.each do |key, value|
yield key.to_s.downcase, value.to_s
end
end
end
This turns everything into a normal form.
However, this imposes a cost to all users, even if they do the right thing.
The spec looks something like this:
context 'with headers' do
let(:server) do
Async::HTTP::Server.for(endpoint, protocol) do |request|
Protocol::HTTP::Response[200, [], request.headers.inspect]
end
end
it 'fails when headers are not strings' do
response = client.get("/", {foo: 'bar'})
expect(response).to be_success
end
end
Should we expect this to pass?
The other option is to enable verbose logging of headers but only when debug logging is turned on. This could pick up issues before they happen.
There is a performance cost to this fix, but it might be unavoidable and in practice is probably undetectable. That being said, we could consider adding a warning to this code path because honestly, header keys should always be lower case strings, and header values should always be strings.
Released in protocol-http v0.23.2
.
We were having success with falcon in development, then we deployed to aws in a docker environment and ran into the following async-http client error.
Thinking it might be because we are a bit out of date, we upgraded falcon and async-http to the latest and now have new errors:
I'm not sure if the upgrade resolved the old issue and added a new one, or if it hit this error before hitting the next error.