Skip to content

IO#read_nonblock blocks sometimes for SSL Sockets #1129

@mohamedhafez

Description

@mohamedhafez

IO#read_nonblock blocks sometimes for SSL Sockets. Based on Aaron Patterson's monkey patch in http://gist.github.com/251244, I added some logging in Thread.current[] for debugging and monkey patched Net::BufferedIO#rbuf_fill to be:

def rbuf_fill
    Thread.current[:rbuf_fill_loops] = 0

    begin
      Thread.current[:rbuf_fill_loops] += 1
      Thread.current[:rbuf_fill_stage] = "pre read_nonblock #{Time.now}"
      @rbuf << @io.read_nonblock(BUFSIZE)
    rescue OpenSSL::SSL::SSLErrorReadable, Errno::EWOULDBLOCK, Errno::EAGAIN => e
      Thread.current[:rbuf_fill_stage] = "rescue"
      raise if e.is_a?(OpenSSL::SSL::SSLErrorReadable) && e.message != "read would block"
      Thread.current[:rbuf_fill_error] = "#{$!.class}: #{$!.message}"
      Thread.current[:rbuf_fill_stage] = "pre io select"
      retry if IO.select [@io], nil, nil, 30.0
      raise Timeout::Error, e.message
    end

    Thread.current[:rbuf_fill_stage] = nil
    Thread.current[:rbuf_fill_loops] = nil
    Thread.current[:rbuf_fill_error] = nil
    @rbuf
end

Usually it works great (I use Net::HTTP to scrape some sites, which in turn uses this method), but every now and then it hangs at the read_nonblock for SSL sockets. If you wrap the whole method in a Timeout::timeout set for 5 minutes or so, you can see that it rarely but occasionally goes off and that when you examine Thread.current[:rbuf_fill_stage] it reads "pre read_nonblock ..." with a timestamp approx 5 minutes before the timeout fired. Also, for the 10 or so cases I've observed so far, Thread.current[:rbuf_fill_loops] is always 2, and Thread.current[:rbuf_fill_error] is always "OpenSSL::SSL::SSLErrorReadable: read would block".

I'm using JRuby 1.7.3 in ruby 1.9 mode, I know there are later JRuby releases but none seem to have any patches related to read_nonblock so I figure this is still a bug even in those releases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions