postrank-labs / goliath

Goliath is a non-blocking Ruby web server framework

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

::Rack::Deflator throws exception when defined in a mapped API

wolfscaptain opened this issue · comments

Whenever ::Rack::Deflator is defined inside a mapped Goliath::API, it throws an exception about String#each not being defined.

For some reason when Goliath runs the main API with Deflator inside it, it sends the data correctly inside an array, e.g. ["HTML"], but when it is deined in a mapped API, it sends the string directly, so Rack::GzipStream#each fails.

Here's an example code:

class Mapped < Goliath::API
    use ::Rack::Deflater # if it's here, Goliath sends "Ok"

    def response(env)
        [200, {}, "Ok"]
    end
end

class MainAPI < Goliath::API
    map "whatever", Mapped do
        use ::Rack::Deflater # if it's only here and not in Mapped, Goliath sends ["Ok"]
    end
end

Your response entity should be something that responds to #each, e.g. an Array:

def response(env)
  [ 200, {}, [ "Ok" ] ]
end

Recently there has been some discussion on this in rack/rack#376.

It should also include a Content-Type header, btw. You might want to have a look at the Rack spec.

You didn't understand.

If I put "use ::Rack::Deflater" in the mapped API, Rack::GzipStream#each gets a string, but if I put it in the main API, it gets an array with the string inside it.
In both cases my return from response() is a string.

What I mean is: passing something that responds to #each as the response body is what the Rack spec requires. Goliath itself is a little more tolerant and happily takes a String instead. But if you mix Goliath stuff with Rack middleware, using an #each duck type is the least common denominator.

TL;DR Goliath is happy with Strings as response bodies, but Rack::Deflater expects an #each duck type and thus blows up.

Closing, cutting router from 1.0. Please reopen if this still occurs in generic setup.