Rainbows! Rack HTTP server user/dev discussion
 help / Atom feed
* issue between rainbows/unicorn 5.0.0 and rack on ruby >= 1.9.1
@ 2016-07-13 19:51 Kevin Mullican
  2016-07-13 20:24 ` Eric Wong
  0 siblings, 1 reply; 4+ messages in thread
From: Kevin Mullican @ 2016-07-13 19:51 UTC (permalink / raw)
  To: rainbows-public

Greetings,

We have run into a problem while trying to use rainbows/unicorn 5.0.0
on ruby >= 1.9.1. The issue is with rack. As of ruby 1.9.1, String no
longer responds to #each, however it seems that rainbows is still
sending a string body through rack. See:

rainbows-5.0.0/lib/rainbows/process_client.rb:51: in `write_response`

which enters rack at:

rainbows-5.0.0/lib/rainbows/response.rb:85:in `write_body_each'

Note that the rack spec specifically requires that body respond to
#each and yield a set of strings:

https://github.com/rack/rack/blob/25a549883b85fb33970b4a1530a365c0c9e51f95/SPEC#L245-L248

So, it seems that the onus is likely on rainbows to conform to the
rack spec in order to require it's use. One solution would be to wrap
the bare string in an array before it descends into rack.

Sincerely,
Kevin Mullican

^ permalink raw reply	[flat|threaded] 4+ messages in thread

* Re: issue between rainbows/unicorn 5.0.0 and rack on ruby >= 1.9.1
  2016-07-13 19:51 issue between rainbows/unicorn 5.0.0 and rack on ruby >= 1.9.1 Kevin Mullican
@ 2016-07-13 20:24 ` Eric Wong
  2016-07-14 16:13   ` Dan Kegel
  0 siblings, 1 reply; 4+ messages in thread
From: Eric Wong @ 2016-07-13 20:24 UTC (permalink / raw)
  To: Kevin Mullican; +Cc: rainbows-public

Kevin Mullican <kmullican@oblong.com> wrote:
> Greetings,
> 
> We have run into a problem while trying to use rainbows/unicorn 5.0.0
> on ruby >= 1.9.1. The issue is with rack. As of ruby 1.9.1, String no
> longer responds to #each, however it seems that rainbows is still
> sending a string body through rack. See:
> 
> rainbows-5.0.0/lib/rainbows/process_client.rb:51: in `write_response`
> 
> which enters rack at:
> 
> rainbows-5.0.0/lib/rainbows/response.rb:85:in `write_body_each'

That is all correct.

> Note that the rack spec specifically requires that body respond to
> #each and yield a set of strings:
> 
> https://github.com/rack/rack/blob/25a549883b85fb33970b4a1530a365c0c9e51f95/SPEC#L245-L248

Also correct.

> So, it seems that the onus is likely on rainbows to conform to the
> rack spec in order to require it's use. One solution would be to wrap
> the bare string in an array before it descends into rack.

Actually, I believe the onus is on the application to produce a
correct response body for the application server to use.
Testing your application with the Rack::Lint middleware enabled
should've detected such an error.

Application frameworks (e.g. Sinatra, Rails, etc) already produce
a response body which responds to #each out-of-the-box.

A brief scan of lib/rack/handlers/*.rb in rack.git reveals the
server handlers bundled with rack itself expect the body to
respond to #each, too.

^ permalink raw reply	[flat|threaded] 4+ messages in thread

* Re: issue between rainbows/unicorn 5.0.0 and rack on ruby >= 1.9.1
  2016-07-13 20:24 ` Eric Wong
@ 2016-07-14 16:13   ` Dan Kegel
  2016-07-14 22:17     ` Eric Wong
  0 siblings, 1 reply; 4+ messages in thread
From: Dan Kegel @ 2016-07-14 16:13 UTC (permalink / raw)
  To: Eric Wong; +Cc: Kevin Mullican, rainbows-public

On Wed, Jul 13, 2016 at 1:24 PM, Eric Wong <e@80x24.org> wrote:
> Actually, I believe the onus is on the application to produce a
> correct response body for the application server to use.

I work with Kevin, and helped track this down.  Neither of us use Ruby
much, hence our difficulty.
I'm posting a followup here in case others in a similar spot happen
across this thread.

One problem was in our rackup.ru (I'll show a bit more code than
needed, to be kind to newbies):

class AppendSlash
  def initialize(app, options={})
    @app = app
    @base = options[:base]
  end
  def call(env)
    if env['REQUEST_URI'] == @base
      [301, {
        'Content-Type' => 'text/html',
        'Location' =>  @base + '/'
        }, '']
    else
      @app.call(env)
    end
  end
end

The fix was to change
        }, '']
to
        }, ['']]

Likewise, in a few of our apps, we had to change

      [200, {
          'Content-Type' => 'text/plain',
          'Content-Length' => data.length.to_s
        }, data
      ]

to

      [200, {
          'Content-Type' => 'text/plain',
          'Content-Length' => data.length.to_s
        }, [data]
      ]

The question was also asked at https://github.com/rack/rack/issues/1096
so I'll follow up there, too.

Thanks!
- Dan

^ permalink raw reply	[flat|threaded] 4+ messages in thread

* Re: issue between rainbows/unicorn 5.0.0 and rack on ruby >= 1.9.1
  2016-07-14 16:13   ` Dan Kegel
@ 2016-07-14 22:17     ` Eric Wong
  0 siblings, 0 replies; 4+ messages in thread
From: Eric Wong @ 2016-07-14 22:17 UTC (permalink / raw)
  To: Dan Kegel; +Cc: Kevin Mullican, rainbows-public

Dan Kegel <dank@kegel.com> wrote:
> On Wed, Jul 13, 2016 at 1:24 PM, Eric Wong <e@80x24.org> wrote:
> > Actually, I believe the onus is on the application to produce a
> > correct response body for the application server to use.
> 
> I work with Kevin, and helped track this down.  Neither of us use Ruby
> much, hence our difficulty.
> I'm posting a followup here in case others in a similar spot happen
> across this thread.

Thanks for the followup!

> One problem was in our rackup.ru (I'll show a bit more code than
> needed, to be kind to newbies):
> 
> class AppendSlash
>   def initialize(app, options={})
>     @app = app
>     @base = options[:base]
>   end
>   def call(env)
>     if env['REQUEST_URI'] == @base
>       [301, {
>         'Content-Type' => 'text/html',
>         'Location' =>  @base + '/'
>         }, '']

Also in the interest of being kind to newbies; some minor
problems in the above example unrelated to your original problem:

* REQUEST_URI isn't actually part of the Rack spec,
  but many servers include it, so I guess it's fine in practice.

* Content-Length isn't specified for your 301 response;
  which might cause redirects to not terminate properly.
  This could confuse clients and/or cause Rainbows! to hit the
  keepalive_timeout (default 5s) and delay redirects by that
  time[*]

  According to Rack::Utils::STATUS_WITH_NO_ENTITY_BODY, only
  100-199, 204, 205, 304 response codes can get away without
  a Content-Length or "Transfer-Encoding: chunked" header

  Of course, you may be using the Rack::ContentLength/Rack::Chunked
  middlewares to generate the appropriate headers,
  but the code below indicates not...

>       [200, {
>           'Content-Type' => 'text/plain',
>           'Content-Length' => data.length.to_s
>         }, [data]
>       ]

If you're unsure about the encoding of `data',

           'Content-Length' => data.bytesize.to_s

would be safer for multi-byte responses.  String#bytesize
is available from 1.8.7 onwards.

However, if you're certain `data' is already a single-byte
encoding (binary/us-ascii) String#size could be a hair faster
since it's one of the few optimized dispatch instructions
in the mainline VM.



[*] in retrospect, this is probably major barrier to adoption
    of Rainbows! and yahns, since they take a stricter
    interpretation of Rack SPEC than most other servers.
    There've been several reports in the past of users
    forgetting to set content-length/chunked in responses
    and wondering why some responses take so long.

^ permalink raw reply	[flat|threaded] 4+ messages in thread

end of thread, back to index

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-13 19:51 issue between rainbows/unicorn 5.0.0 and rack on ruby >= 1.9.1 Kevin Mullican
2016-07-13 20:24 ` Eric Wong
2016-07-14 16:13   ` Dan Kegel
2016-07-14 22:17     ` Eric Wong

Rainbows! Rack HTTP server user/dev discussion

Archives are clonable:
	git clone --mirror https://bogomips.org/rainbows-public
	git clone --mirror http://ou63pmih66umazou.onion/rainbows-public

Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.lang.ruby.rainbows
	nntp://ou63pmih66umazou.onion/inbox.comp.lang.ruby.rainbows

 note: .onion URLs require Tor: https://www.torproject.org/
       or Tor2web: https://www.tor2web.org/

AGPL code for this site: git clone https://public-inbox.org/ public-inbox