class Net::BufferedIO
:nodoc: internal use only
def LOG(msg)
def LOG(msg) return unless @debug_output @debug_output << msg + "\n" end
def LOG_off
def LOG_off @save_debug_out = @debug_output @debug_output = nil end
def LOG_on
def LOG_on @debug_output = @save_debug_out end
def close
def close @io.close end
def closed?
def closed? @io.closed? end
def eof?
def eof? @io.eof? end
def initialize(io, read_timeout: 60, write_timeout: 60, continue_timeout: nil, debug_output: nil)
def initialize(io, read_timeout: 60, write_timeout: 60, continue_timeout: nil, debug_output: nil) @io = io @read_timeout = read_timeout @write_timeout = write_timeout @continue_timeout = continue_timeout @debug_output = debug_output @rbuf = ''.b end
def inspect
def inspect "#<#{self.class} io=#{@io}>" end
def rbuf_consume(len)
def rbuf_consume(len) if len == @rbuf.size s = @rbuf @rbuf = ''.b else s = @rbuf.slice!(0, len) end @debug_output << %Q[-> #{s.dump}\n] if @debug_output s end
def rbuf_fill
def rbuf_fill tmp = @rbuf.empty? ? @rbuf : nil case rv = @io.read_nonblock(BUFSIZE, tmp, exception: false) when String return if rv.equal?(tmp) @rbuf << rv rv.clear return when :wait_readable (io = @io.to_io).wait_readable(@read_timeout) or raise Net::ReadTimeout.new(io) # continue looping when :wait_writable # OpenSSL::Buffering#read_nonblock may fail with IO::WaitWritable. # http://www.openssl.org/support/faq.html#PROG10 (io = @io.to_io).wait_writable(@read_timeout) or raise Net::ReadTimeout.new(io) # continue looping when nil raise EOFError, 'end of file reached' end while true end
def read(len, dest = ''.b, ignore_eof = false)
def read(len, dest = ''.b, ignore_eof = false) LOG "reading #{len} bytes..." read_bytes = 0 begin while read_bytes + @rbuf.size < len s = rbuf_consume(@rbuf.size) read_bytes += s.size dest << s rbuf_fill end s = rbuf_consume(len - read_bytes) read_bytes += s.size dest << s rescue EOFError raise unless ignore_eof end LOG "read #{read_bytes} bytes" dest end
def read_all(dest = ''.b)
def read_all(dest = ''.b) LOG 'reading all...' read_bytes = 0 begin while true s = rbuf_consume(@rbuf.size) read_bytes += s.size dest << s rbuf_fill end rescue EOFError ; end LOG "read #{read_bytes} bytes" dest end
def readline
def readline readuntil("\n").chop end
def readuntil(terminator, ignore_eof = false)
def readuntil(terminator, ignore_eof = false) begin until idx = @rbuf.index(terminator) rbuf_fill end return rbuf_consume(idx + terminator.size) rescue EOFError raise unless ignore_eof return rbuf_consume(@rbuf.size) end end
def write(*strs)
def write(*strs) writing { write0(*strs) } end
def write0(*strs)
def write0(*strs) @debug_output << strs.map(&:dump).join if @debug_output orig_written_bytes = @written_bytes strs.each_with_index do |str, i| need_retry = true case len = @io.write_nonblock(str, exception: false) when Integer @written_bytes += len len -= str.bytesize if len == 0 if strs.size == i+1 return @written_bytes - orig_written_bytes else need_retry = false # next string end elsif len < 0 str = str.byteslice(len, -len) else # len > 0 need_retry = false # next string end # continue looping when :wait_writable (io = @io.to_io).wait_writable(@write_timeout) or raise Net::WriteTimeout.new(io) # continue looping end while need_retry end end
def writeline(str)
def writeline(str) writing { write0 str + "\r\n" } end
def writing
def writing @written_bytes = 0 @debug_output << '<- ' if @debug_output yield @debug_output << "\n" if @debug_output bytes = @written_bytes @written_bytes = nil bytes end