2017-01-11 09:48:51 -05:00
|
|
|
# frozen_string_literal: true
|
2003-08-05 12:12:05 -04:00
|
|
|
#
|
|
|
|
# = net/protocol.rb
|
|
|
|
#
|
|
|
|
#--
|
2004-03-06 10:55:23 -05:00
|
|
|
# Copyright (c) 1999-2004 Yukihiro Matsumoto
|
|
|
|
# Copyright (c) 1999-2004 Minero Aoki
|
2003-08-05 12:12:05 -04:00
|
|
|
#
|
|
|
|
# written and maintained by Minero Aoki <aamine@loveruby.net>
|
|
|
|
#
|
|
|
|
# This program is free software. You can re-distribute and/or
|
|
|
|
# modify this program under the same terms as Ruby itself,
|
|
|
|
# Ruby Distribute License or GNU General Public License.
|
|
|
|
#
|
|
|
|
# $Id$
|
|
|
|
#++
|
|
|
|
#
|
|
|
|
# WARNING: This file is going to remove.
|
|
|
|
# Do not rely on the implementation written in this file.
|
|
|
|
#
|
1999-10-13 03:29:15 -04:00
|
|
|
|
2000-06-16 09:47:38 -04:00
|
|
|
require 'socket'
|
2001-02-06 06:14:51 -05:00
|
|
|
require 'timeout'
|
2015-04-15 16:11:23 -04:00
|
|
|
require 'io/wait'
|
2000-06-16 09:47:38 -04:00
|
|
|
|
2003-08-21 05:07:57 -04:00
|
|
|
module Net # :nodoc:
|
2000-06-16 09:47:38 -04:00
|
|
|
|
2003-08-05 12:12:05 -04:00
|
|
|
class Protocol #:nodoc: internal use only
|
2020-07-28 11:31:52 -04:00
|
|
|
VERSION = "0.1.0"
|
|
|
|
|
2003-05-02 11:19:20 -04:00
|
|
|
private
|
2004-03-06 10:55:23 -05:00
|
|
|
def Protocol.protocol_param(name, val)
|
2003-05-02 11:19:20 -04:00
|
|
|
module_eval(<<-End, __FILE__, __LINE__ + 1)
|
|
|
|
def #{name}
|
|
|
|
#{val}
|
|
|
|
end
|
|
|
|
End
|
|
|
|
end
|
2016-11-05 02:47:36 -04:00
|
|
|
|
|
|
|
def ssl_socket_connect(s, timeout)
|
|
|
|
if timeout
|
|
|
|
while true
|
|
|
|
raise Net::OpenTimeout if timeout <= 0
|
|
|
|
start = Process.clock_gettime Process::CLOCK_MONOTONIC
|
|
|
|
# to_io is required because SSLSocket doesn't have wait_readable yet
|
|
|
|
case s.connect_nonblock(exception: false)
|
|
|
|
when :wait_readable; s.to_io.wait_readable(timeout)
|
|
|
|
when :wait_writable; s.to_io.wait_writable(timeout)
|
|
|
|
else; break
|
|
|
|
end
|
|
|
|
timeout -= Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
|
|
|
end
|
|
|
|
else
|
|
|
|
s.connect
|
|
|
|
end
|
|
|
|
end
|
2003-05-02 11:19:20 -04:00
|
|
|
end
|
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
|
2000-03-31 08:02:40 -05:00
|
|
|
class ProtocolError < StandardError; end
|
|
|
|
class ProtoSyntaxError < ProtocolError; end
|
|
|
|
class ProtoFatalError < ProtocolError; end
|
|
|
|
class ProtoUnknownError < ProtocolError; end
|
|
|
|
class ProtoServerError < ProtocolError; end
|
|
|
|
class ProtoAuthError < ProtocolError; end
|
|
|
|
class ProtoCommandError < ProtocolError; end
|
|
|
|
class ProtoRetriableError < ProtocolError; end
|
|
|
|
ProtocRetryError = ProtoRetriableError
|
2012-04-11 17:20:51 -04:00
|
|
|
|
|
|
|
##
|
|
|
|
# OpenTimeout, a subclass of Timeout::Error, is raised if a connection cannot
|
|
|
|
# be created within the open_timeout.
|
|
|
|
|
2012-02-28 00:15:54 -05:00
|
|
|
class OpenTimeout < Timeout::Error; end
|
1999-12-17 10:00:13 -05:00
|
|
|
|
2012-04-11 17:20:51 -04:00
|
|
|
##
|
|
|
|
# ReadTimeout, a subclass of Timeout::Error, is raised if a chunk of the
|
|
|
|
# response cannot be read within the read_timeout.
|
|
|
|
|
2018-12-10 02:11:18 -05:00
|
|
|
class ReadTimeout < Timeout::Error
|
|
|
|
def initialize(io = nil)
|
|
|
|
@io = io
|
|
|
|
end
|
|
|
|
attr_reader :io
|
|
|
|
|
|
|
|
def message
|
|
|
|
msg = super
|
|
|
|
if @io
|
|
|
|
msg = "#{msg} with #{@io.inspect}"
|
|
|
|
end
|
|
|
|
msg
|
|
|
|
end
|
|
|
|
end
|
2012-04-11 17:20:51 -04:00
|
|
|
|
2018-06-06 04:03:47 -04:00
|
|
|
##
|
|
|
|
# WriteTimeout, a subclass of Timeout::Error, is raised if a chunk of the
|
2018-06-08 13:20:20 -04:00
|
|
|
# response cannot be written within the write_timeout. Not raised on Windows.
|
2018-06-06 04:03:47 -04:00
|
|
|
|
2018-12-10 02:11:18 -05:00
|
|
|
class WriteTimeout < Timeout::Error
|
|
|
|
def initialize(io = nil)
|
|
|
|
@io = io
|
|
|
|
end
|
|
|
|
attr_reader :io
|
|
|
|
|
|
|
|
def message
|
|
|
|
msg = super
|
|
|
|
if @io
|
|
|
|
msg = "#{msg} with #{@io.inspect}"
|
|
|
|
end
|
|
|
|
msg
|
|
|
|
end
|
|
|
|
end
|
2018-06-06 04:03:47 -04:00
|
|
|
|
aamine
* lib/net/protocol.rb, smtp.rb, pop.rb, http.rb: 1.1.26.
* lib/net/protocol.rb, smtp.rb, pop.rb, http.rb:
add module Net::NetPrivate and its inner classes
{Read,Write}Adapter, Command, Socket,
SMTPCommand, POP3Command, APOPCommand, HTTPCommand
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@826 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2000-07-12 02:04:40 -04:00
|
|
|
|
2004-03-06 12:08:21 -05:00
|
|
|
class BufferedIO #:nodoc: internal use only
|
2018-06-06 04:03:47 -04:00
|
|
|
def initialize(io, read_timeout: 60, write_timeout: 60, continue_timeout: nil, debug_output: nil)
|
2004-03-06 12:08:21 -05:00
|
|
|
@io = io
|
2016-11-14 02:53:32 -05:00
|
|
|
@read_timeout = read_timeout
|
2018-06-06 04:03:47 -04:00
|
|
|
@write_timeout = write_timeout
|
2016-11-14 02:53:32 -05:00
|
|
|
@continue_timeout = continue_timeout
|
|
|
|
@debug_output = debug_output
|
2018-01-07 19:34:42 -05:00
|
|
|
@rbuf = ''.b
|
1999-12-17 10:00:13 -05:00
|
|
|
end
|
|
|
|
|
2004-03-06 12:08:21 -05:00
|
|
|
attr_reader :io
|
|
|
|
attr_accessor :read_timeout
|
2018-06-06 04:03:47 -04:00
|
|
|
attr_accessor :write_timeout
|
* lib/net/http.rb, lib/net/protocol.rb: Allow to configure to wait
server returning '100 continue' response befor sending HTTP request
body. See NEWS for more detail. See #3622.
Original patch is made by Eric Hodel <drbrain@segment7.net>.
* test/net/http/test_http.rb: test it.
* NEWS: Add new feature.
On my env (Ubuntu 11.04 64bit),
9510 tests, 2203824 assertions, 0 failures, 0 errors, 29 skips
->
9514 tests, 2203836 assertions, 0 failures, 0 errors, 29 skips
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31860 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2011-05-31 04:10:42 -04:00
|
|
|
attr_accessor :continue_timeout
|
2004-03-06 12:08:21 -05:00
|
|
|
attr_accessor :debug_output
|
1999-12-17 10:00:13 -05:00
|
|
|
|
2004-03-06 12:08:21 -05:00
|
|
|
def inspect
|
|
|
|
"#<#{self.class} io=#{@io}>"
|
1999-12-17 10:00:13 -05:00
|
|
|
end
|
|
|
|
|
2011-01-05 19:24:45 -05:00
|
|
|
def eof?
|
|
|
|
@io.eof?
|
|
|
|
end
|
|
|
|
|
2001-12-30 14:18:45 -05:00
|
|
|
def closed?
|
2004-03-06 12:08:21 -05:00
|
|
|
@io.closed?
|
1999-12-17 10:00:13 -05:00
|
|
|
end
|
2000-11-16 09:03:20 -05:00
|
|
|
|
2004-03-06 12:08:21 -05:00
|
|
|
def close
|
|
|
|
@io.close
|
1999-12-17 10:00:13 -05:00
|
|
|
end
|
2000-11-16 09:03:20 -05:00
|
|
|
|
2004-03-06 12:08:21 -05:00
|
|
|
#
|
|
|
|
# Read
|
|
|
|
#
|
1999-12-17 10:00:13 -05:00
|
|
|
|
2001-02-06 06:14:51 -05:00
|
|
|
public
|
2000-11-16 09:03:20 -05:00
|
|
|
|
2018-01-07 19:34:42 -05:00
|
|
|
def read(len, dest = ''.b, ignore_eof = false)
|
2003-07-01 22:34:39 -04:00
|
|
|
LOG "reading #{len} bytes..."
|
|
|
|
read_bytes = 0
|
2001-01-16 02:57:43 -05:00
|
|
|
begin
|
2003-07-01 22:34:39 -04:00
|
|
|
while read_bytes + @rbuf.size < len
|
2017-05-22 03:36:00 -04:00
|
|
|
s = rbuf_consume(@rbuf.size)
|
2004-03-06 10:55:23 -05:00
|
|
|
read_bytes += s.size
|
2017-05-22 03:36:00 -04:00
|
|
|
dest << s
|
2001-02-07 12:17:51 -05:00
|
|
|
rbuf_fill
|
2001-01-16 02:57:43 -05:00
|
|
|
end
|
2017-05-22 03:36:00 -04:00
|
|
|
s = rbuf_consume(len - read_bytes)
|
2004-03-06 10:55:23 -05:00
|
|
|
read_bytes += s.size
|
2017-05-22 03:36:00 -04:00
|
|
|
dest << s
|
2001-01-16 02:57:43 -05:00
|
|
|
rescue EOFError
|
2003-07-01 22:34:39 -04:00
|
|
|
raise unless ignore_eof
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
2003-07-01 22:34:39 -04:00
|
|
|
LOG "read #{read_bytes} bytes"
|
2000-03-31 08:02:40 -05:00
|
|
|
dest
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
|
2018-01-07 19:34:42 -05:00
|
|
|
def read_all(dest = ''.b)
|
2003-07-01 22:34:39 -04:00
|
|
|
LOG 'reading all...'
|
|
|
|
read_bytes = 0
|
2000-01-21 07:52:24 -05:00
|
|
|
begin
|
2002-11-21 06:50:09 -05:00
|
|
|
while true
|
2017-05-22 03:36:00 -04:00
|
|
|
s = rbuf_consume(@rbuf.size)
|
2004-03-06 10:55:23 -05:00
|
|
|
read_bytes += s.size
|
2017-05-22 03:36:00 -04:00
|
|
|
dest << s
|
2001-02-07 12:17:51 -05:00
|
|
|
rbuf_fill
|
2000-01-21 07:52:24 -05:00
|
|
|
end
|
|
|
|
rescue EOFError
|
|
|
|
;
|
|
|
|
end
|
2003-07-01 22:34:39 -04:00
|
|
|
LOG "read #{read_bytes} bytes"
|
2000-03-31 08:02:40 -05:00
|
|
|
dest
|
2000-01-21 07:52:24 -05:00
|
|
|
end
|
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
def readuntil(terminator, ignore_eof = false)
|
2001-01-16 02:57:43 -05:00
|
|
|
begin
|
2003-07-01 22:34:39 -04:00
|
|
|
until idx = @rbuf.index(terminator)
|
2001-02-07 12:17:51 -05:00
|
|
|
rbuf_fill
|
2001-01-16 02:57:43 -05:00
|
|
|
end
|
2004-03-06 10:55:23 -05:00
|
|
|
return rbuf_consume(idx + terminator.size)
|
2001-01-16 02:57:43 -05:00
|
|
|
rescue EOFError
|
2003-07-01 22:34:39 -04:00
|
|
|
raise unless ignore_eof
|
2004-03-06 10:55:23 -05:00
|
|
|
return rbuf_consume(@rbuf.size)
|
2001-01-16 02:57:43 -05:00
|
|
|
end
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
2009-03-05 22:56:38 -05:00
|
|
|
|
1999-09-22 03:32:33 -04:00
|
|
|
def readline
|
2003-07-01 22:34:39 -04:00
|
|
|
readuntil("\n").chop
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
|
2003-07-01 22:34:39 -04:00
|
|
|
private
|
1999-09-22 03:32:33 -04:00
|
|
|
|
2007-03-18 22:27:08 -04:00
|
|
|
BUFSIZE = 1024 * 16
|
|
|
|
|
2001-02-07 12:17:51 -05:00
|
|
|
def rbuf_fill
|
2018-01-07 19:34:47 -05:00
|
|
|
tmp = @rbuf.empty? ? @rbuf : nil
|
|
|
|
case rv = @io.read_nonblock(BUFSIZE, tmp, exception: false)
|
2015-04-10 17:05:29 -04:00
|
|
|
when String
|
2018-01-07 19:34:47 -05:00
|
|
|
return if rv.equal?(tmp)
|
2017-05-21 19:52:08 -04:00
|
|
|
@rbuf << rv
|
|
|
|
rv.clear
|
|
|
|
return
|
2015-04-10 17:05:29 -04:00
|
|
|
when :wait_readable
|
2018-12-10 02:11:18 -05:00
|
|
|
(io = @io.to_io).wait_readable(@read_timeout) or raise Net::ReadTimeout.new(io)
|
2015-04-10 17:05:29 -04:00
|
|
|
# continue looping
|
|
|
|
when :wait_writable
|
2009-03-19 07:40:38 -04:00
|
|
|
# OpenSSL::Buffering#read_nonblock may fail with IO::WaitWritable.
|
|
|
|
# http://www.openssl.org/support/faq.html#PROG10
|
2018-12-10 02:11:18 -05:00
|
|
|
(io = @io.to_io).wait_writable(@read_timeout) or raise Net::ReadTimeout.new(io)
|
2015-04-10 17:05:29 -04:00
|
|
|
# continue looping
|
|
|
|
when nil
|
2017-01-11 21:19:17 -05:00
|
|
|
raise EOFError, 'end of file reached'
|
2015-04-10 17:05:29 -04:00
|
|
|
end while true
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
def rbuf_consume(len)
|
2018-01-04 21:22:23 -05:00
|
|
|
if len == @rbuf.size
|
|
|
|
s = @rbuf
|
2018-01-07 19:34:42 -05:00
|
|
|
@rbuf = ''.b
|
2018-01-04 21:22:23 -05:00
|
|
|
else
|
|
|
|
s = @rbuf.slice!(0, len)
|
|
|
|
end
|
2002-03-26 06:18:02 -05:00
|
|
|
@debug_output << %Q[-> #{s.dump}\n] if @debug_output
|
2004-03-06 10:55:23 -05:00
|
|
|
s
|
1999-12-17 10:00:13 -05:00
|
|
|
end
|
1999-09-22 03:32:33 -04:00
|
|
|
|
2004-03-06 12:08:21 -05:00
|
|
|
#
|
|
|
|
# Write
|
|
|
|
#
|
2001-12-30 14:18:45 -05:00
|
|
|
|
1999-09-22 03:32:33 -04:00
|
|
|
public
|
|
|
|
|
2018-01-13 21:44:53 -05:00
|
|
|
def write(*strs)
|
2000-06-27 09:36:17 -04:00
|
|
|
writing {
|
2018-01-19 07:15:56 -05:00
|
|
|
write0(*strs)
|
2000-06-27 09:36:17 -04:00
|
|
|
}
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
|
2010-12-12 20:04:37 -05:00
|
|
|
alias << write
|
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
def writeline(str)
|
2000-06-27 09:36:17 -04:00
|
|
|
writing {
|
2003-07-01 22:34:39 -04:00
|
|
|
write0 str + "\r\n"
|
2000-06-27 09:36:17 -04:00
|
|
|
}
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
|
2004-03-06 12:08:21 -05:00
|
|
|
private
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2018-01-13 21:44:53 -05:00
|
|
|
def write0(*strs)
|
|
|
|
@debug_output << strs.map(&:dump).join if @debug_output
|
2018-06-06 04:39:36 -04:00
|
|
|
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
|
2018-06-06 04:03:47 -04:00
|
|
|
len -= str.bytesize
|
|
|
|
if len == 0
|
|
|
|
if strs.size == i+1
|
2018-06-06 04:39:36 -04:00
|
|
|
return @written_bytes - orig_written_bytes
|
2018-06-06 04:03:47 -04:00
|
|
|
else
|
2018-06-06 04:39:36 -04:00
|
|
|
need_retry = false
|
|
|
|
# next string
|
2018-06-06 04:03:47 -04:00
|
|
|
end
|
|
|
|
elsif len < 0
|
2018-12-26 23:49:12 -05:00
|
|
|
str = str.byteslice(len, -len)
|
2018-06-06 04:03:47 -04:00
|
|
|
else # len > 0
|
2018-06-06 04:39:36 -04:00
|
|
|
need_retry = false
|
|
|
|
# next string
|
2018-06-06 04:03:47 -04:00
|
|
|
end
|
2018-06-06 04:39:36 -04:00
|
|
|
# continue looping
|
|
|
|
when :wait_writable
|
2018-12-10 02:11:18 -05:00
|
|
|
(io = @io.to_io).wait_writable(@write_timeout) or raise Net::WriteTimeout.new(io)
|
2018-06-06 04:39:36 -04:00
|
|
|
# continue looping
|
|
|
|
end while need_retry
|
|
|
|
end
|
2004-03-06 12:08:21 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Logging
|
|
|
|
#
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def LOG_off
|
|
|
|
@save_debug_out = @debug_output
|
|
|
|
@debug_output = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
def LOG_on
|
|
|
|
@debug_output = @save_debug_out
|
|
|
|
end
|
|
|
|
|
|
|
|
def LOG(msg)
|
|
|
|
return unless @debug_output
|
|
|
|
@debug_output << msg + "\n"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
class InternetMessageIO < BufferedIO #:nodoc: internal use only
|
2019-04-07 19:44:49 -04:00
|
|
|
def initialize(*, **)
|
2004-03-06 12:08:21 -05:00
|
|
|
super
|
|
|
|
@wbuf = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Read
|
|
|
|
#
|
|
|
|
|
|
|
|
def each_message_chunk
|
|
|
|
LOG 'reading message...'
|
|
|
|
LOG_off()
|
|
|
|
read_bytes = 0
|
|
|
|
while (line = readuntil("\r\n")) != ".\r\n"
|
|
|
|
read_bytes += line.size
|
2018-12-04 03:22:10 -05:00
|
|
|
yield line.delete_prefix('.')
|
2004-03-06 12:08:21 -05:00
|
|
|
end
|
|
|
|
LOG_on()
|
|
|
|
LOG "read message (#{read_bytes} bytes)"
|
|
|
|
end
|
2009-03-05 22:56:38 -05:00
|
|
|
|
2004-03-06 12:08:21 -05:00
|
|
|
# *library private* (cannot handle 'break')
|
|
|
|
def each_list_item
|
|
|
|
while (str = readuntil("\r\n")) != ".\r\n"
|
|
|
|
yield str.chop
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def write_message_0(src)
|
|
|
|
prev = @written_bytes
|
|
|
|
each_crlf_line(src) do |line|
|
2014-05-23 08:36:30 -04:00
|
|
|
write0 dot_stuff(line)
|
2004-03-06 12:08:21 -05:00
|
|
|
end
|
|
|
|
@written_bytes - prev
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Write
|
|
|
|
#
|
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
def write_message(src)
|
2003-07-01 22:34:39 -04:00
|
|
|
LOG "writing message from #{src.class}"
|
|
|
|
LOG_off()
|
2004-03-06 10:55:23 -05:00
|
|
|
len = writing {
|
|
|
|
using_each_crlf_line {
|
|
|
|
write_message_0 src
|
|
|
|
}
|
2003-07-01 22:34:39 -04:00
|
|
|
}
|
|
|
|
LOG_on()
|
|
|
|
LOG "wrote #{len} bytes"
|
|
|
|
len
|
|
|
|
end
|
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
def write_message_by_block(&block)
|
2003-07-01 22:34:39 -04:00
|
|
|
LOG 'writing message from block'
|
|
|
|
LOG_off()
|
2004-03-06 10:55:23 -05:00
|
|
|
len = writing {
|
|
|
|
using_each_crlf_line {
|
|
|
|
begin
|
|
|
|
block.call(WriteAdapter.new(self, :write_message_0))
|
|
|
|
rescue LocalJumpError
|
|
|
|
# allow `break' from writer block
|
|
|
|
end
|
|
|
|
}
|
2003-07-01 22:34:39 -04:00
|
|
|
}
|
|
|
|
LOG_on()
|
|
|
|
LOG "wrote #{len} bytes"
|
|
|
|
len
|
|
|
|
end
|
|
|
|
|
2002-02-19 07:33:52 -05:00
|
|
|
private
|
|
|
|
|
2014-05-23 08:36:30 -04:00
|
|
|
def dot_stuff(s)
|
|
|
|
s.sub(/\A\./, '..')
|
|
|
|
end
|
|
|
|
|
2001-12-13 14:15:21 -05:00
|
|
|
def using_each_crlf_line
|
2018-01-07 19:34:42 -05:00
|
|
|
@wbuf = ''.b
|
2004-03-06 10:55:23 -05:00
|
|
|
yield
|
|
|
|
if not @wbuf.empty? # unterminated last line
|
2014-05-23 08:36:30 -04:00
|
|
|
write0 dot_stuff(@wbuf.chomp) + "\r\n"
|
2004-03-06 10:55:23 -05:00
|
|
|
elsif @written_bytes == 0 # empty src
|
|
|
|
write0 "\r\n"
|
|
|
|
end
|
|
|
|
write0 ".\r\n"
|
|
|
|
@wbuf = nil
|
2000-06-27 09:36:17 -04:00
|
|
|
end
|
1999-09-22 03:32:33 -04:00
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
def each_crlf_line(src)
|
|
|
|
buffer_filling(@wbuf, src) do
|
2012-11-08 05:04:24 -05:00
|
|
|
while line = @wbuf.slice!(/\A[^\r\n]*(?:\n|\r(?:\n|(?!\z)))/)
|
2004-03-06 10:55:23 -05:00
|
|
|
yield line.chomp("\n") + "\r\n"
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
end
|
2000-02-21 10:27:49 -05:00
|
|
|
end
|
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
def buffer_filling(buf, src)
|
2000-02-21 10:27:49 -05:00
|
|
|
case src
|
2003-07-01 22:34:39 -04:00
|
|
|
when String # for speeding up.
|
2004-03-06 10:55:23 -05:00
|
|
|
0.step(src.size - 1, 1024) do |i|
|
|
|
|
buf << src[i, 1024]
|
2000-02-21 10:27:49 -05:00
|
|
|
yield
|
|
|
|
end
|
2003-07-01 22:34:39 -04:00
|
|
|
when File # for speeding up.
|
2004-03-06 10:55:23 -05:00
|
|
|
while s = src.read(1024)
|
|
|
|
buf << s
|
2000-02-21 10:27:49 -05:00
|
|
|
yield
|
|
|
|
end
|
2003-07-01 22:34:39 -04:00
|
|
|
else # generic reader
|
2007-03-04 19:17:38 -05:00
|
|
|
src.each do |str|
|
|
|
|
buf << str
|
2004-03-06 10:55:23 -05:00
|
|
|
yield if buf.size > 1024
|
2000-02-21 10:27:49 -05:00
|
|
|
end
|
2004-03-06 10:55:23 -05:00
|
|
|
yield unless buf.empty?
|
2000-02-21 10:27:49 -05:00
|
|
|
end
|
|
|
|
end
|
2002-02-19 07:33:52 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
|
2003-07-01 22:34:39 -04:00
|
|
|
#
|
|
|
|
# The writer adapter class
|
|
|
|
#
|
2002-02-19 07:33:52 -05:00
|
|
|
class WriteAdapter
|
2004-03-06 10:55:23 -05:00
|
|
|
def initialize(socket, method)
|
|
|
|
@socket = socket
|
|
|
|
@method_id = method
|
2002-02-19 07:33:52 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def inspect
|
2002-10-02 12:45:35 -04:00
|
|
|
"#<#{self.class} socket=#{@socket.inspect}>"
|
2002-02-19 07:33:52 -05:00
|
|
|
end
|
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
def write(str)
|
2003-07-01 22:34:39 -04:00
|
|
|
@socket.__send__(@method_id, str)
|
2002-02-19 07:33:52 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
alias print write
|
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
def <<(str)
|
2002-02-19 07:33:52 -05:00
|
|
|
write str
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
def puts(str = '')
|
|
|
|
write str.chomp("\n") + "\n"
|
2002-02-19 07:33:52 -05:00
|
|
|
end
|
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
def printf(*args)
|
2002-02-19 07:33:52 -05:00
|
|
|
write sprintf(*args)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2003-08-05 12:12:05 -04:00
|
|
|
class ReadAdapter #:nodoc: internal use only
|
2004-03-06 10:55:23 -05:00
|
|
|
def initialize(block)
|
2002-02-19 07:33:52 -05:00
|
|
|
@block = block
|
|
|
|
end
|
2000-03-31 08:02:40 -05:00
|
|
|
|
2002-02-19 07:33:52 -05:00
|
|
|
def inspect
|
2002-10-02 12:45:35 -04:00
|
|
|
"#<#{self.class}>"
|
2002-02-19 07:33:52 -05:00
|
|
|
end
|
|
|
|
|
2004-03-06 10:55:23 -05:00
|
|
|
def <<(str)
|
2002-11-21 06:50:09 -05:00
|
|
|
call_block(str, &@block) if @block
|
2002-02-19 07:33:52 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2003-07-01 22:34:39 -04:00
|
|
|
# This method is needed because @block must be called by yield,
|
|
|
|
# not Proc#call. You can see difference when using `break' in
|
|
|
|
# the block.
|
2004-03-06 10:55:23 -05:00
|
|
|
def call_block(str)
|
2002-02-19 07:33:52 -05:00
|
|
|
yield str
|
|
|
|
end
|
1999-12-17 10:00:13 -05:00
|
|
|
end
|
1999-09-22 03:32:33 -04:00
|
|
|
|
2003-07-01 22:05:35 -04:00
|
|
|
|
2003-08-05 12:12:05 -04:00
|
|
|
module NetPrivate #:nodoc: obsolete
|
2003-07-01 22:05:35 -04:00
|
|
|
Socket = ::Net::InternetMessageIO
|
|
|
|
end
|
|
|
|
|
1999-12-17 10:00:13 -05:00
|
|
|
end # module Net
|