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:
parent
dd53813e38
commit
3eedf9156c
8 changed files with 379 additions and 392 deletions
21
ChangeLog
21
ChangeLog
|
@ -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,
|
||||
|
|
|
@ -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'
|
|
@ -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
|
121
lib/net/http.rb
121
lib/net/http.rb
|
@ -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
177
lib/net/https.rb
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue