1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* lib/net/http.rb: spin off https code again.

* lib/net/https.rb: new file.
* ext/openssl/lib/net/https.rb: removed.  moved to net/https with modifications.
* ext/openssl/lib/net/protocol.rb: removed.  merged with net/http.
* lib/net/protocol.rb: new class BufferedIO.
* lib/net/protocol.rb: InternetMessageIO < BufferedIO.
* lib/net/protocol.rb: BufferedIO.new takes an IO.
* lib/net/smtp.rb: follow InternetMessageIO's change.
* lib/net/pop.rb: ditto.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5908 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
aamine 2004-03-06 17:08:21 +00:00
parent dd53813e38
commit 3eedf9156c
8 changed files with 379 additions and 392 deletions

View file

@ -1,3 +1,24 @@
Sun Mar 7 02:06:07 2004 Minero Aoki <aamine@loveruby.net>
* lib/net/http.rb: spin off https code again.
* lib/net/https.rb: new file.
* ext/openssl/lib/net/https.rb: removed. moved to net/https with
slight modifications.
* ext/openssl/lib/net/protocol.rb: removed. merged with net/http.
* lib/net/protocol.rb: new class BufferedIO.
* lib/net/protocol.rb: InternetMessageIO < BufferedIO.
* lib/net/protocol.rb: BufferedIO.new takes an IO.
* lib/net/smtp.rb: follow InternetMessageIO's change.
* lib/net/pop.rb: ditto.
Sun Mar 7 00:55:03 2004 Minero Aoki <aamine@loveruby.net>
* lib/net/protocol.rb: remove method: InternetMessageIO#address,

View file

@ -1,102 +0,0 @@
=begin
= $RCSfile$ -- SSL/TLS enhancement for Net::HTTP.
= Info
'OpenSSL for Ruby 2' project
Copyright (C) 2001 GOTOU Yuuzou <gotoyuzo@notwork.org>
All rights reserved.
= Licence
This program is licenced under the same licence as Ruby.
(See the file 'LICENCE'.)
= Requirements
This program requires Net 1.2.0 or higher version.
You can get it from RAA or Ruby's CVS repository.
= Version
$Id$
2001/11/06: Contiributed to Ruby/OpenSSL project.
== class Net::HTTP
== Example
Simple HTTP client is here:
require 'net/http'
host, port, path = "localhost", 80, "/"
if %r!http://(.*?)(?::(\d+))?(/.*)! =~ ARGV[0]
host = $1
port = $2.to_i if $2
path = $3
end
h = Net::HTTP.new(host, port)
h.request_get(path) {|res| print res.body }
It can be replaced by follow one:
require 'net/https'
host, port, path = "localhost", 80, "/"
if %r!(https?)://(.*?)(?::(\d+))?(/.*)! =~ ARGV[0]
scheme = $1
host = $2
port = $3 ? $3.to_i : ((scheme == "http") ? 80 : 443)
path = $4
end
h = Net::HTTP.new(host, port)
h.use_ssl = true if scheme == "https" # enable SSL/TLS
h.request_get(path) {|res| print res.body }
=== Instance Methods
: use_ssl
returns ture if use SSL/TLS with HTTP.
: use_ssl=((|true_or_false|))
sets use_ssl.
: peer_cert
return the X.509 certificates the server presented.
: key=((|key|))
Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
(This method is appeared in Michal Rokos's OpenSSL extention.)
: key_file=((|path|))
Sets a private key file to use in PEM format.
: cert=((|cert|))
Sets an OpenSSL::X509::Certificate object as client certificate.
(This method is appeared in Michal Rokos's OpenSSL extention.)
: cert_file=((|path|))
Sets pathname of a X.509 certification file in PEM format.
: ca_file=((|path|))
Sets path of a CA certification file in PEM format.
The file can contrain several CA certificats.
: ca_path=((|path|))
Sets path of a CA certification directory containing certifications
in PEM format.
: verify_mode=((|mode|))
Sets the flags for server the certification verification at
begining of SSL/TLS session.
OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER is acceptable.
: verify_callback=((|proc|))
Sets the verify callback for the server certification verification.
: verify_depth=((|num|))
Sets the maximum depth for the certificate chain verification.
: cert_store=((|store|))
Sets the X509::Store to verify peer certificate.
=end
# HTTPS implementation is merged in to net/http.
require 'net/http'

View file

@ -1,56 +0,0 @@
=begin
= $RCSfile$ -- SSL/TLS enhancement for Net.
= Info
'OpenSSL for Ruby 2' project
Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
All rights reserved.
= Licence
This program is licenced under the same licence as Ruby.
(See the file 'LICENCE'.)
= Requirements
This program requires Net 1.2.0 or higher version.
You can get it from RAA or Ruby's CVS repository.
= Version
$Id$
2001/11/06: Contiributed to Ruby/OpenSSL project.
=end
require 'net/protocol'
require 'forwardable'
require 'openssl'
module Net
class SSLIO < InternetMessageIO
extend Forwardable
def_delegators(:@ssl_context,
:key=, :cert=, :key_file=, :cert_file=,
:ca_file=, :ca_path=,
:verify_mode=, :verify_callback=, :verify_depth=,
:timeout=, :cert_store=)
def initialize(addr, port, otime = nil, rtime = nil, dout = nil)
super
@ssl_context = OpenSSL::SSL::SSLContext.new()
end
def ssl_connect()
unless @ssl_context.verify_mode
warn "warning: peer certificate won't be verified in this SSL session."
@ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
@socket = OpenSSL::SSL::SSLSocket.new(@socket, @ssl_context)
@socket.sync_close = true
@socket.connect
end
def peer_cert
@socket.peer_cert
end
end
end

View file

@ -1,10 +1,11 @@
#
# = net/http.rb
#
# Copyright (c) 1999-2003 Yukihiro Matsumoto
# Copyright (c) 1999-2003 Minero Aoki
# Copyright (C) 1999-2003 Yukihiro Matsumoto
# Copyright (C) 1999-2003 Minero Aoki
#
# Written & maintained by Minero Aoki <aamine@loveruby.net>.
# Written and maintained by Minero Aoki <aamine@loveruby.net>.
# HTTPS support added by GOTOU Yuuzou <gotoyuzo@notwork.org>.
#
# This file is derived from "http-access.rb".
#
@ -25,11 +26,6 @@
require 'net/protocol'
require 'uri'
begin
require 'net/protocols'
rescue LoadError
end
module Net # :nodoc:
@ -355,30 +351,16 @@ module Net # :nodoc:
def initialize(address, port = nil)
@address = address
@port = (port || HTTP.default_port)
@curr_http_version = HTTPVersion
@seems_1_0_server = false
@close_on_empty_response = false
@socket = nil
@started = false
@open_timeout = 30
@read_timeout = 60
@debug_output = nil
# ssl
@use_ssl = false
@key = nil
@cert = nil
@ca_file = nil
@ca_path = nil
@verify_mode = nil
@verify_callback = nil
@verify_depth = nil
@ssl_timeout = nil
@cert_store = nil
@peer_cert = nil
@ssl_context = nil
end
def inspect
@ -432,29 +414,9 @@ module Net # :nodoc:
# returns true if use SSL/TLS with HTTP.
def use_ssl?
@use_ssl
false # redefined in net/https
end
alias use_ssl use_ssl? #:nodoc:
# turn on/off SSL.
# This flag must be set before starting session.
# If you change use_ssl value after session started,
# a Net::HTTP object raises IOError.
def use_ssl=(flag)
flag = (flag ? true : false)
raise IOError, "use_ssl value changed but session already started" if started? and @use_ssl != flag
@use_ssl = flag
end
attr_writer :key, :cert
attr_writer :ca_file, :ca_path
attr_writer :verify_mode, :verify_callback, :verify_depth
attr_writer :cert_store, :ssl_timeout
attr_reader :peer_cert
alias timeout= ssl_timeout= # for backward compatibility
# Opens TCP connection and HTTP session.
#
# When this method is called with block, gives a HTTP object
@ -479,39 +441,35 @@ module Net # :nodoc:
end
def do_start
if use_ssl?
require 'net/protocols'
sockclass = SSLIO
else
sockclass = InternetMessageIO
end
@socket = sockclass.open(conn_address(), conn_port(),
@open_timeout, @read_timeout, @debug_output)
if use_ssl?
if proxy?
@socket.writeline sprintf('CONNECT %s:%s HTTP/%s',
@address, @port, HTTP_VERSION)
@socket.writeline ''
res = HTTPResponse.read_new(@socket)
res.value
end
@socket.key = @key if @key
@socket.cert = @cert if @cert
@socket.ca_file = @ca_file
@socket.ca_path = @ca_path
@socket.verify_mode = @verify_mode
@socket.verify_callback = @verify_callback
@socket.verify_depth = @verify_depth
@socket.timeout = @ssl_timeout
@socket.cert_store = @cert_store
@socket.ssl_connect
@peer_cert = @socket.peer_cert
end
on_connect
connect
@started = true
end
private :do_start
def connect
s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) }
if use_ssl?
unless @ssl_context.verify_mode
warn "warning: peer certificate won't be verified in this SSL session"
@ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
s.sync_close = true
s.connect
end
@socket = BufferedIO.new(s)
@socket.read_timeout = @read_timeout
@socket.debug_output = @debug_output
if use_ssl? and proxy?
@socket.writeline sprintf('CONNECT %s:%s HTTP/%s',
@address, @port, HTTP_VERSION)
@socket.writeline ''
HTTPResponse.read_new(@socket).value
end
on_connect
end
private :connect
def on_connect
end
private :on_connect
@ -966,7 +924,7 @@ module Net # :nodoc:
req.exec @socket, @curr_http_version, edit_path(req.path), body
begin
res = HTTPResponse.read_new(@socket)
end while HTTPContinue === res
end while res.kind_of?(HTTPContinue)
res.reading_body(@socket, req.response_body_permitted?) {
yield res if block_given?
}
@ -979,8 +937,7 @@ module Net # :nodoc:
def begin_transport(req)
if @socket.closed?
@socket.reopen @open_timeout
on_connect
connect
end
if @seems_1_0_server
req['connection'] = 'close'
@ -1042,6 +999,7 @@ module Net # :nodoc:
HTTPSession = HTTP
#
# Header module.
#
@ -1219,6 +1177,7 @@ module Net # :nodoc:
end
#
# Parent of HTTPRequest class. Do not use this directly; use
# a subclass of HTTPRequest.
@ -1319,7 +1278,6 @@ module Net # :nodoc:
class HTTP
class Get < HTTPRequest
METHOD = 'GET'
REQUEST_HAS_BODY = false
@ -1397,7 +1355,6 @@ module Net # :nodoc:
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
end
end
@ -1717,9 +1674,7 @@ module Net # :nodoc:
'505' => HTTPVersionNotSupported
}
class << self
class << HTTPResponse
def read_new(sock) #:nodoc: internal use only
httpv, code, msg = read_status_line(sock)
res = response_class(code).new(httpv, code, msg)
@ -1730,7 +1685,6 @@ module Net # :nodoc:
res[k] = v
end
end
res
end
@ -1758,7 +1712,6 @@ module Net # :nodoc:
yield m[1], m.post_match
end
end
end
# next is to fix bug in RDoc, where the private inside class << self
@ -1825,7 +1778,7 @@ module Net # :nodoc:
# Raises HTTP error if the response is not 2xx.
def value
error! unless HTTPSuccess === self
error! unless self.kind_of?(HTTPSuccess)
end
#

177
lib/net/https.rb Normal file
View file

@ -0,0 +1,177 @@
=begin
= $RCSfile$ -- SSL/TLS enhancement for Net::HTTP.
== Info
'OpenSSL for Ruby 2' project
Copyright (C) 2001 GOTOU Yuuzou <gotoyuzo@notwork.org>
All rights reserved.
== Licence
This program is licenced under the same licence as Ruby.
(See the file 'LICENCE'.)
== Requirements
This program requires Net 1.2.0 or higher version.
You can get it from RAA or Ruby's CVS repository.
== Version
$Id$
2001-11-06: Contiributed to Ruby/OpenSSL project.
2004-03-06: Some code is merged in to net/http.
== Example
Here is a simple HTTP client:
require 'net/http'
require 'uri'
uri = URI.parse(ARGV[0] || 'http://localhost/')
http = Net::HTTP.new(uri.host, uri.port)
http.start {
http.request_get(uri.path) {|res|
print res.body
}
}
It can be replaced by the following code:
require 'net/https'
require 'uri'
uri = URI.parse(ARGV[0] || 'https://localhost/')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if uri.scheme == "https" # enable SSL/TLS
http.start {
http.request_get(uri.path) {|res|
print res.body
}
}
== class Net::HTTP
=== Instance Methods
: use_ssl?
returns true if use SSL/TLS with HTTP.
: use_ssl=((|true_or_false|))
sets use_ssl.
: peer_cert
return the X.509 certificates the server presented.
: key, key=((|key|))
Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
(This method is appeared in Michal Rokos's OpenSSL extention.)
: key_file, key_file=((|path|))
Sets a private key file to use in PEM format.
: cert, cert=((|cert|))
Sets an OpenSSL::X509::Certificate object as client certificate
(This method is appeared in Michal Rokos's OpenSSL extention).
: cert_file, cert_file=((|path|))
Sets pathname of a X.509 certification file in PEM format.
: ca_file, ca_file=((|path|))
Sets path of a CA certification file in PEM format.
The file can contrain several CA certificats.
: ca_path, ca_path=((|path|))
Sets path of a CA certification directory containing certifications
in PEM format.
: verify_mode, verify_mode=((|mode|))
Sets the flags for server the certification verification at
begining of SSL/TLS session.
OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER is acceptable.
: verify_callback, verify_callback=((|proc|))
Sets the verify callback for the server certification verification.
: verify_depth, verify_depth=((|num|))
Sets the maximum depth for the certificate chain verification.
: cert_store, cert_store=((|store|))
Sets the X509::Store to verify peer certificate.
: ssl_timeout, ssl_timeout=((|sec|))
Sets the SSL timeout seconds.
=end
require 'net/http'
require 'openssl'
module Net
class HTTP
remove_method :use_ssl?
def use_ssl?
@use_ssl
end
alias use_ssl use_ssl? # for backward compatibility
# Turn on/off SSL.
# This flag must be set before starting session.
# If you change use_ssl value after session started,
# a Net::HTTP object raises IOError.
def use_ssl=(flag)
flag = (flag ? true : false)
raise IOError, "use_ssl value changed but session already started" \
if started? and @use_ssl != flag
if flag and not @ssl_context
@ssl_context = OpenSSL::SSL::SSLContext.new
end
@use_ssl = flag
end
def self.ssl_context_accessor(name)
module_eval(<<-End, __FILE__, __LINE__ + 1)
def #{name}
return nil unless @ssl_context
@ssl_context.#{name}
end
def #{name}=(val)
@ssl_context ||= OpenSSL::SSL::SSLContext.new
@ssl_context.#{name} = val
end
End
end
ssl_context_accessor :key
ssl_context_accessor :cert
ssl_context_accessor :ca_file
ssl_context_accessor :ca_path
ssl_context_accessor :verify_mode
ssl_context_accessor :verify_callback
ssl_context_accessor :verify_depth
ssl_context_accessor :cert_store
def ssl_timeout
return nil unless @ssl_context
@ssl_context.timeout
end
def ssl_timeout=(sec)
raise ArgumentError, 'Net::HTTP#ssl_timeout= called but use_ssl=false' \
unless use_ssl?
@ssl_context ||= OpenSSL::SSL::SSLContext.new
@ssl_context.timeout = sec
end
alias timeout= ssl_timeout= # for backward compatibility
def peer_cert
return nil if not use_ssl? or not @socket
@socket.io.peer_cert
end
end
end

View file

@ -1,17 +1,17 @@
# = net/pop.rb
#
#--
# Copyright (c) 1999-2003 Yukihiro Matsumoto
# Copyright (c) 1999-2003 Minero Aoki
# Copyright (c) 1999-2004 Yukihiro Matsumoto
# Copyright (c) 1999-2004 Minero Aoki
#
# written & maintained by Minero Aoki <aamine@loveruby.net>
# 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.
# Ruby Distribute License.
#
# NOTE: You can find Japanese version of this document in
# the doc/net directory of the standard ruby interpreter package.
# NOTE: You can find Japanese version of this document at:
# http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=net%2Fpop.rb
#
# $Id$
#++
@ -168,6 +168,7 @@
require 'net/protocol'
require 'digest/md5'
require 'timeout'
module Net
@ -424,8 +425,12 @@ module Net
end
def do_start( account, password )
@socket = self.class.socket_type.open(@address, @port,
@open_timeout, @read_timeout, @debug_output)
@socket = InternetMessageIO.new(timeout(@open_timeout) {
TCPSocket.open(@address, @port)
})
logging "POP session started: #{@address}:#{@port} (#{@apop ? 'APOP' : 'POP'})"
@socket.read_timeout = @read_timeout
@socket.debug_output = @debug_output
on_connect
@command = POP3Command.new(@socket)
if apop?
@ -558,6 +563,10 @@ module Net
end
end
def logging(msg)
@debug_output << msg if @debug_output
end
end # class POP3
# class aliases

View file

@ -46,61 +46,33 @@ module Net # :nodoc:
ProtocRetryError = ProtoRetriableError
class InternetMessageIO #:nodoc: internal use only
class << self
alias open new
end
def initialize(addr, port, open_timeout = nil, read_timeout = nil, debug_output = nil)
@address = addr
@port = port
@read_timeout = read_timeout
@debug_output = debug_output
@socket = nil
@rbuf = nil # read buffer
@wbuf = nil # write buffer
connect open_timeout
LOG 'opened'
end
def connect(open_timeout)
LOG "opening connection to #{@address}..."
timeout(open_timeout) {
@socket = TCPsocket.new(@address, @port)
}
@rbuf = ''
end
private :connect
def close
if @socket
@socket.close
LOG 'closed'
else
LOG 'close call for already closed socket'
end
@socket = nil
class BufferedIO #:nodoc: internal use only
def initialize(io)
@io = io
@read_timeout = 60
@debug_output = nil
@rbuf = ''
end
def reopen(open_timeout = nil)
LOG 'reopening...'
close
connect open_timeout
LOG 'reopened'
attr_reader :io
attr_accessor :read_timeout
attr_accessor :debug_output
def inspect
"#<#{self.class} io=#{@io}>"
end
def closed?
not @socket
@io.closed?
end
def inspect
"#<#{self.class} #{closed?() ? 'closed' : 'opened'}>"
def close
@io.close
end
###
### READ
###
#
# Read
#
public
@ -154,6 +126,90 @@ module Net # :nodoc:
readuntil("\n").chop
end
private
def rbuf_fill
until IO.select([@io], nil, nil, @read_timeout)
raise TimeoutError, "socket read timeout (#{@read_timeout} sec)"
end
@rbuf << @io.sysread(1024)
end
def rbuf_consume(len)
s = @rbuf.slice!(0, len)
@debug_output << %Q[-> #{s.dump}\n] if @debug_output
s
end
#
# Write
#
public
def write(str)
writing {
write0 str
}
end
def writeline(str)
writing {
write0 str + "\r\n"
}
end
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
def write0(str)
@debug_output << str.dump if @debug_output
len = @io.write(str)
@written_bytes += len
len
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
def initialize(io)
super
@wbuf = nil
end
#
# Read
#
def each_message_chunk
LOG 'reading message...'
LOG_off()
@ -173,38 +229,17 @@ module Net # :nodoc:
end
end
private
def rbuf_fill
until IO.select([@socket], nil, nil, @read_timeout)
raise TimeoutError, "socket read timeout (#{@read_timeout} sec)"
def write_message_0(src)
prev = @written_bytes
each_crlf_line(src) do |line|
write0 line.sub(/\A\./, '..')
end
@rbuf << @socket.sysread(1024)
@written_bytes - prev
end
def rbuf_consume(len)
s = @rbuf.slice!(0, len)
@debug_output << %Q[-> #{s.dump}\n] if @debug_output
s
end
###
### WRITE
###
public
def write(str)
writing {
write0 str
}
end
def writeline(str)
writing {
write0 str + "\r\n"
}
end
#
# Write
#
def write_message(src)
LOG "writing message from #{src.class}"
@ -238,42 +273,6 @@ module Net # :nodoc:
private
def writing
@written_bytes = 0
@debug_output << '<- ' if @debug_output
yield
@socket.flush
@debug_output << "\n" if @debug_output
bytes = @written_bytes
@written_bytes = nil
bytes
end
def write0(str)
@debug_output << str.dump if @debug_output
len = @socket.write(str)
@written_bytes += len
len
end
#
# Reads string from src calling :each, and write to @socket.
# Escapes '.' on the each line head.
#
def write_message_0(src)
prev = @written_bytes
each_crlf_line(src) do |line|
if line[0] == ?.
then write0 '.' + line
else write0 line
end
end
@written_bytes - prev
end
#
# setup @wbuf for each_crlf_line.
#
def using_each_crlf_line
@wbuf = ''
yield
@ -315,26 +314,6 @@ module Net # :nodoc:
yield unless buf.empty?
end
end
###
### DEBUG
###
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

View file

@ -1,17 +1,16 @@
# = net/smtp.rb
#
#
#--
# Copyright (c) 1999-2003 Yukihiro Matsumoto
# Copyright (c) 1999-2003 Minero Aoki
# Copyright (C) 1999-2004 Yukihiro Matsumoto
# Copyright (C) 1999-2004 Minero Aoki
#
# written & maintained by Minero Aoki <aamine@loveruby.net>
# 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.
# modify this program under the same terms as Ruby itself.
#
# NOTE: You can find Japanese version of this document in
# the doc/net directory of the standard ruby interpreter package.
# NOTE: You can find Japanese version of this document at:
# http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=net%2Fsmtp.rb
#
# $Id$
#++
@ -120,7 +119,7 @@
require 'net/protocol'
require 'digest/md5'
require 'timeout'
module Net # :nodoc:
@ -343,9 +342,12 @@ module Net # :nodoc:
raise IOError, 'SMTP session already started' if @started
check_auth_args user, secret, authtype if user or secret
@socket = InternetMessageIO.open(@address, @port,
@open_timeout, @read_timeout,
@debug_output)
@socket = InternetMessageIO.new(timeout(@open_timeout) {
TCPSocket.open(@address, @port)
})
logging "SMTP session opened: #{@address}:#{@port}"
@socket.read_timeout = @read_timeout
@socket.debug_output = @debug_output
check_response(critical { recv_response() })
begin
if @esmtp
@ -629,6 +631,10 @@ module Net # :nodoc:
end
end
def logging(msg)
@debug_output << msg if @debug_output
end
end # class SMTP
SMTPSession = SMTP