summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authoraamine <aamine@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2000-03-23 21:56:16 +0000
committeraamine <aamine@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2000-03-23 21:56:16 +0000
commitbaa5bd16f78e1afb06dc32427429bc76cd2ea9a0 (patch)
tree654ed7a9c350258243174b61fe5fb09434070c7e /lib
parent2da1de6f6e2d4e0af9a9acf040573b64da853105 (diff)
protocol.rb/smtp.rb/pop.rb/http.rb 1.1.8
o http.rb: post, get2, post2, get_body git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_4@650 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r--lib/net/http.rb359
-rw-r--r--lib/net/pop.rb76
-rw-r--r--lib/net/protocol.rb136
-rw-r--r--lib/net/smtp.rb61
4 files changed, 285 insertions, 347 deletions
diff --git a/lib/net/http.rb b/lib/net/http.rb
index b908b8ae79..bdbcb82fd5 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -38,11 +38,14 @@ class HTTPBadResponse < HTTPError; end
== Methods
-: get( path, header = nil, ret = '' )
+: get( path, header = nil, dest = '' )
+: get( path, header = nil ) {|str| .... }
get data from "path" on connecting host.
- "header" is a Hash like { 'Accept' => '*/*', ... }.
- The data will be written to "ret" using "<<" method.
- This method returns response header (Hash) and "ret".
+ "header" must be a Hash like { 'Accept' => '*/*', ... }.
+ Data is written to "dest" by using "<<" method.
+ This method returns response header (Hash) and "dest".
+
+ If called as iterator, give a part String of entity body.
: head( path, header = nil )
get only header from "path" on connecting host.
@@ -53,6 +56,30 @@ class HTTPBadResponse < HTTPError; end
'content-type' => 'Content-Type: text/html',
... }
+: post( path, data, header = nil, dest = '' )
+: post( path, data, header = nil ) {|str| .... }
+ post "data"(must be String now) to "path" (and get entity body).
+ "header" must be a Hash like { 'Accept' => '*/*', ... }.
+ Data is written to "dest" by using "<<" method.
+ This method returns response header (Hash) and "dest".
+
+ If called as iterator, give a part String of entity body.
+
+ ATTENTION: entity body could be empty
+
+: get2( path, header = nil )
+ send GET request for "path".
+ "header" must be a Hash like { 'Accept' => '*/*', ... }.
+ This method returns response header (Hash).
+
+: get_body( dest = '' )
+: get_body {|str| .... }
+ gets entity body of forwarded 'get2' or 'post2' methods.
+ Data is written in "dest" by using "<<" method.
+ This method returns "dest".
+
+ If called as iterator, give a part String of entity body.
+
=end
class HTTP < Protocol
@@ -61,19 +88,71 @@ class HTTPBadResponse < HTTPError; end
protocol_param :command_type, '::Net::HTTPCommand'
- def get( path, u_header = nil, ret = '' )
+ def get( path, u_header = nil, dest = nil, &block )
u_header ||= {}
- header = connecting( u_header ) {
- @command.get ret, edit_path(path), u_header
+ if block then
+ dest = ReadAdapter.new( block )
+ ret = nil
+ else
+ dest = ret = ''
+ end
+ resp = nil
+ connecting( u_header ) {
+ @command.get edit_path(path), u_header
+ resp = @command.get_response
+ @command.try_get_body( resp, dest )
}
- return header, ret
+ return resp['http-header'], ret
end
- def head( path, u_header = nil )
+ def get2( path, u_header = {} )
+ only_header( :get, path, u_header )
+ end
+
+ def get_body( dest = '', &block )
+ if block then
+ dest = ReadAdapter.new( block )
+ end
+ @command.try_get_body @response, dest
+ ensure_termination @u_header
+
+ dest
+ end
+
+ def head( path, u_header = {} )
+ ret = only_header( :head, path, u_header )['http-header']
+ ensure_termination u_header
+ ret
+ end
+
+ def post( path, data, u_header = nil, dest = nil, &block )
u_header ||= {}
- header = connecting( u_header ) {
- @command.head edit_path(path), u_header
+ if block then
+ dest = ReadAdapter.new( block )
+ ret = nil
+ else
+ dest = ret = ''
+ end
+ resp = nil
+ connecting( u_header, true ) {
+ @command.post path, u_header, data
+ resp = @command.get_response
+ @command.try_get_body( resp, dest )
+ }
+
+ return resp['http-header'], ret
+ end
+
+ def post2( path, data, u_header = {} )
+ only_header :post, path, u_header, data
+ end
+
+ # not tested because I could not setup apache (__;;;
+ def put( path, src = nil, u_header = {}, &block )
+ u_header ||= u_header
+ connecting( u_header, true ) {
+ @command.put path, u_header, src, dest
}
header
@@ -83,30 +162,51 @@ class HTTPBadResponse < HTTPError; end
private
+ def only_header( mid, path, u_header, data = nil )
+ @u_header = u_header ? procheader(u_header) : {}
+ @response = nil
+ ensure_connection @u_header
+ if data then
+ @command.send mid, edit_path(path), @u_header, data
+ else
+ @command.send mid, edit_path(path), @u_header
+ end
+ @response = @command.get_response
+ @response['http-header']
+ end
+
+
# called when connecting
def do_finish
unless @socket.closed? then
- @command.head '/', { 'Connection' => 'Close' }
+ begin
+ @command.head '/', { 'Connection' => 'Close' }
+ rescue EOFError
+ end
end
end
- def connecting( u_header )
+ def connecting( u_header, putp = false )
u_header = procheader( u_header )
+ ensure_connection u_header
+ yield
+ ensure_termination u_header
+ end
+ def ensure_connection( u_header )
if not @socket then
u_header['Connection'] = 'Close'
start
elsif @socket.closed? then
@socket.reopen
end
+ end
- header = yield
-
+ def ensure_termination( u_header )
unless keep_alive? u_header then
@socket.close
end
-
- header
+ @u_header = @response = nil
end
def keep_alive?( header )
@@ -155,6 +255,20 @@ class HTTPBadResponse < HTTPError; end
HTTPSession = HTTP
+ class HTTPSuccessCode < SuccessCode; end
+ class HTTPCreatedCode < SuccessCode; end
+ class HTTPAcceptedCode < SuccessCode; end
+ class HTTPNoContentCode < SuccessCode; end
+ class HTTPResetContentCode < SuccessCode; end
+ class HTTPPartialContentCode < SuccessCode; end
+
+ class HTTPMultipleChoiceCode < RetryCode; end
+ class HTTPMovedPermanentlyCode < RetryCode; end
+ class HTTPMovedTemporarilyCode < RetryCode; end
+ class HTTPNotModifiedCode < RetryCode; end
+ class HTTPUseProxyCode < RetryCode; end
+
+
class HTTPCommand < Command
HTTPVersion = '1.1'
@@ -173,41 +287,26 @@ class HTTPBadResponse < HTTPError; end
attr_reader :http_version
- def get( ret, path, u_header = nil )
- header = get_response(
- sprintf( 'GET %s HTTP/%s', path, HTTPVersion ), u_header )
- if chunked? header then
- clen = read_chunked_body( ret )
- header.delete 'transfer-encoding'
- header[ 'content-length' ] = "Content-Length: #{clen}"
- else
- if clen = content_length( header ) then
- @socket.read clen, ret
- else
- @socket.read_all ret
- end
- end
-
- header
+ def get( path, u_header )
+ request sprintf('GET %s HTTP/%s', path, HTTPVersion), u_header
end
-
-
- def head( path, u_header = nil )
- get_response sprintf( 'HEAD %s HTTP/%s', path, HTTPVersion ), u_header
+
+ def head( path, u_header )
+ request sprintf('HEAD %s HTTP/%s', path, HTTPVersion), u_header
end
-
- # not work
- def post( path, u_header = nil )
- get_response sprintf( 'POST %s HTTP/%s', path, HTTPVersion ), u_header
+ def post( path, u_header, data )
+ request sprintf('POST %s HTTP/%s', path, HTTPVersion), u_header
+ @socket.write data
end
- # not work
- def put( path, u_header = nil )
- get_response sprintf( 'PUT %s HTTP/%s', path, HTTPVersion ), u_header
+ def put( path, u_header, src )
+ request sprintf('PUT %s HTTP/%s', path, HTTPVersion), u_header
+ @socket.write_bin src
end
+
# def delete
# def trace
@@ -215,19 +314,64 @@ class HTTPBadResponse < HTTPError; end
# def options
- private
-
-
- def get_response( line, u_header )
- @socket.writeline line
- write_header u_header
+ def get_response
rep = get_reply
- header = read_header
+ rep = get_reply while ContinueCode === rep
+ header = {}
+ while true do
+ line = @socket.readline
+ break if line.empty?
+ nm = /\A[^:]+/.match( line )[0].strip.downcase
+ header[nm] = line
+ end
+
+ rep['http-header'] = header
reply_must rep, SuccessCode
- header
+ rep
+ end
+
+ def get_body( rep, dest )
+ header = rep['http-header']
+ if chunked? header then
+ read_chunked( dest, header )
+ else
+ if clen = content_length( header ) then
+ @socket.read clen, dest
+ else
+ ###
+ ### "multipart/bytelenges" check should be done here ...
+ ###
+ @socket.read_all dest
+ end
+ end
+ end
+
+ def try_get_body( rep, dest )
+ rep = get_reply while ContinueCode === rep
+ return nil unless rep['body-exist']
+
+ get_body rep, dest
+ end
+
+
+ private
+
+
+ def request( req, u_header )
+ @socket.writeline req
+ if u_header then
+ header = @in_header.dup.update( u_header )
+ else
+ header = @in_header
+ end
+ header.each do |n,v|
+ @socket.writeline n + ': ' + v
+ end
+ @socket.writeline ''
end
+
def get_reply
str = @socket.readline
unless /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i === str then
@@ -237,78 +381,45 @@ class HTTPBadResponse < HTTPError; end
status = $2
discrip = $3
+ be = false
klass = case status[0]
when ?1 then
case status[2]
when ?0 then ContinueCode
- when ?1 then SuccessCode
+ when ?1 then HTTPSuccessCode
+ else UnknownCode
+ end
+ when ?2 then
+ case status[2]
+ when ?0 then be = true; HTTPSuccessCode
+ when ?1 then be = false; HTTPSuccessCode
+ when ?2 then be = true; HTTPSuccessCode
+ when ?3 then be = true; HTTPSuccessCode
+ when ?4 then be = false; HTTPNoContentCode
+ when ?5 then be = false; HTTPResetContentCode
+ when ?6 then be = true; HTTPPartialContentCode
+ else UnknownCode
+ end
+ when ?3 then
+ case status[2]
+ when ?0 then be = true; HTTPMultipleChoiceCode
+ when ?1 then be = true; HTTPMovedPermanentryCode
+ when ?2 then be = true; HTTPMovedTemporarilyCode
+ when ?3 then be = true; HTTPMovedPermanentryCode
+ when ?4 then be = false; HTTPNotModifiedCode
+ when ?5 then be = false; HTTPUseProxyCode
else UnknownCode
end
- when ?2 then SuccessCode
- when ?3 then RetryCode
when ?4 then ServerBusyCode
when ?5 then FatalErrorCode
else UnknownCode
end
- klass.new( status, discrip )
- end
-
-
- def content_length( header )
- unless str = header[ 'content-length' ] then
- return nil
- end
- unless /\Acontent-length:\s*(\d+)/i === str then
- raise HTTPBadResponse, "content-length format error"
- end
- $1.to_i
- end
-
- def chunked?( header )
- if str = header[ 'transfer-encoding' ] then
- if /\Atransfer-encoding:\s*chunked/i === str then
- return true
- end
- end
-
- false
+ code = klass.new( status, discrip )
+ code['body-exist'] = be
+ code
end
-
- def read_header
- header = {}
- while true do
- line = @socket.readline
- break if line.empty?
- /\A[^:]+/ === line
- nm = $&
- nm.strip!
- nm.downcase!
- header[ nm ] = line
- end
-
- header
- end
-
- def write_header( user )
- if user then
- header = @in_header.dup.update user
- else
- header = @in_header
- end
- header.each do |n,v|
- @socket.writeline n + ': ' + v
- end
- @socket.writeline ''
-
- if tmp = header['Connection'] then
- /close/i === tmp
- else
- false
- end
- end
-
- def read_chunked_body( ret )
+ def read_chunked( ret, header )
line = nil
len = nil
total = 0
@@ -328,7 +439,29 @@ class HTTPBadResponse < HTTPError; end
break if line.empty?
end
- total
+ header.delete 'transfer-encoding'
+ header[ 'content-length' ] = "Content-Length: #{total}"
+ end
+
+
+ def content_length( header )
+ unless str = header[ 'content-length' ] then
+ return nil
+ end
+ unless /\Acontent-length:\s*(\d+)/i === str then
+ raise HTTPBadResponse, "content-length format error"
+ end
+ $1.to_i
+ end
+
+ def chunked?( header )
+ if str = header[ 'transfer-encoding' ] then
+ if /\Atransfer-encoding:\s*chunked/i === str then
+ return true
+ end
+ end
+
+ false
end
end
diff --git a/lib/net/pop.rb b/lib/net/pop.rb
index 440f894f57..616f537f52 100644
--- a/lib/net/pop.rb
+++ b/lib/net/pop.rb
@@ -216,66 +216,6 @@ Net::POP3
APOPSession = APOP
-=begin
-
-== Net::POP3Command
-
-POP3 command class.
-
-=== Super Class
-
-Net::Command
-
-=== Class Methods
-
-: new( socket )
- This method creates new POP3Command object. 'socket' must be ProtocolSocket.
-
-
-=== Methods
-
-: auth( account, password )
- This method do POP authorization (no RPOP)
- In case of failed authorization, raises Protocol::ProtocolError exception.
-
-: list
- a list of mails which existing on server.
- The list is an array like "array[ number ] = size".
-
- ex:
-
- The list from server is
-
- 1 2452
- 2 3355
- 4 9842
- :
-
- then, an array is
-
- [ nil, 2452, 3355, nil, 9842, ... ]
-
-: quit
- This method ends POP using 'QUIT' commmand.
-
-: rset
- This method reset all changes done in current session,
- by sending 'RSET' command.
-
-: top( num, lines = 0 )
- This method gets all mail header and 'lines' lines body
- by sending 'TOP' command. 'num' is mail number.
-
- WARNING: the TOP command is 'Optional' in RFC1939 (POP3)
-
-: retr( num : Integer )
- This method gets a mail by 'RETR' command. 'num' is mail number.
-
-: dele( num : Integer )
- This method deletes a mail on server by 'DELE'.
-
-=end
-
class POP3Command < Command
@@ -371,22 +311,6 @@ Net::Command
end
-=begin
-
-== APOPCommand
-
-=== Super Class
-
-POP3Command
-
-=== Methods
-
-: auth( account, password )
- This method do authorization by sending 'APOP' command.
- If server is not APOP server, this raises Net::ProtoAuthError exception.
- On other errors, raises Net::ProtocolError.
-
-=end
class APOPCommand < POP3Command
diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb
index 1f1df17032..4d80153f2c 100644
--- a/lib/net/protocol.rb
+++ b/lib/net/protocol.rb
@@ -15,7 +15,7 @@ require 'socket'
module Net
- Version = '1.1.7'
+ Version = '1.1.8'
=begin
@@ -219,27 +219,6 @@ Object
Session = Protocol
-=begin
-
-== Net::Command
-
-=== Super Class
-
-Object
-
-=== Class Methods
-
-: new( socket )
- This method create new Command object. 'socket' must be ProtocolSocket.
- This method is abstract class.
-
-
-=== Methods
-
-: quit
- This method dispatch command which ends the protocol.
-
-=end
class Command
@@ -317,10 +296,26 @@ Object
def initialize( cod, mes )
@code = cod
@msg = mes
+ @data = nil
end
attr_reader :code, :msg
+ def []( key )
+ if @data then
+ @data[key]
+ else
+ nil
+ end
+ end
+
+ def []=( key, val )
+ unless h = @data then
+ @data = h = {}
+ end
+ h[key] = val
+ end
+
def error!( sending )
mes = <<MES
@@ -370,78 +365,6 @@ MES
end
-=begin
-
-== Net::ProtocolSocket
-
-=== Super Class
-
-Object
-
-=== Class Methods
-
-: new( address = 'localhost', port = nil )
- This create new ProtocolSocket object, and connect to server.
-
-
-=== Methods
-
-: close
- This method closes socket.
-
-: address, addr
- a FQDN address of server
-
-: ip_address, ipaddr
- an IP address of server
-
-: port
- connecting port number.
-
-: closed?
- true if ProtocolSokcet have been closed already
-
-
-: read( length )
- This method read 'length' bytes and return the string.
-
-: readuntil( target )
- This method read until find 'target'. Returns read string.
-
-: readline
- read until "\r\n" and returns it without "\r\n".
-
-: read_pendstr
- This method read until "\r\n.\r\n".
- At the same time, delete period at line head and final line ("\r\n.\r\n").
-
-: read_pendlist
-: read_pendlist{|line| .... }
- This method read until "\r\n.\r\n". This method resembles to 'read_pendstr',
- but 'read_pendlist' don't check period at line head, and returns array which
- each element is one line.
-
- When this method was called with block, evaluate it for each reading a line.
-
-
-: write( src )
- This method send 'src'. ProtocolSocket read strings from 'src' by 'each'
- iterator. This method returns written bytes.
-
-: writebin( src )
- This method send 'src'. ProtocolSokcet read string from 'src' by 'each'
- iterator. This method returns written bytes.
-
-: writeline( str )
- This method writes 'str'. There has not to be bare "\r" or "\n" in 'str'.
-
-: write_pendstr( src )
- This method writes 'src' as a mail.
- ProtocolSocket reads strings from 'src' by 'each' iterator.
- This returns written bytes.
-
-=end
-
class WriteAdapter
@@ -639,35 +562,30 @@ Object
public
- def writeline( str )
+ def write( str )
do_write_beg
do_write_do str
- do_write_do CRLF
do_write_fin
end
- def writebin( src )
+ def writeline( str )
do_write_beg
- if iterator? then
- yield WriteAdapter.new( self, :do_write_do )
- else
- src.each do |bin|
- do_write_do bin
- end
- end
+ do_write_do str
+ do_write_do CRLF
do_write_fin
end
- def write( src )
+ def write_bin( src, block = nil )
do_write_beg
- if iterator? then
- yield WriteAdapter.new( self, :write_inner )
+ if block then
+ block.call WriteAdapter.new( self, :do_write_do )
else
- write_inner src
+ src.each do |bin|
+ do_write_do bin
+ end
end
- each_crlf_line2( :i_w )
do_write_fin
end
diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb
index 2c387db43c..3fc6cc1b3f 100644
--- a/lib/net/smtp.rb
+++ b/lib/net/smtp.rb
@@ -74,15 +74,14 @@ Net::Protocol
protocol_param :command_type, '::Net::SMTPCommand'
- def sendmail( mailsrc, fromaddr, toaddrs, &block )
- @command.mailfrom fromaddr
- @command.rcpt toaddrs
- @command.data
- @command.write_mail( mailsrc, &block )
+ def sendmail( mailsrc, fromaddr, toaddrs )
+ do_ready fromaddr, toaddrs
+ @command.write_mail mailsrc
end
def ready( fromaddr, toaddrs, &block )
- sendmail nil, fromaddr, toaddrs, &block
+ do_ready fromaddr, toaddrs
+ @command.write_mail( &block )
end
@@ -92,6 +91,12 @@ Net::Protocol
private
+ def do_ready
+ @command.mailfrom fromaddr
+ @command.rcpt toaddrs
+ @command.data
+ end
+
def do_start( helodom = ENV['HOSTNAME'] )
unless helodom then
raise ArgumentError, "cannot get hostname"
@@ -111,48 +116,6 @@ Net::Protocol
SMTPSession = SMTP
-=begin
-
-== Net::SMTPCommand
-
-=== Super Class
-
-Net::Command
-
-=== Class Methods
-
-: new( socket )
- This method creates new SMTPCommand object, and open SMTP.
-
-
-=== Methods
-
-: helo( helo_domain )
- This method send "HELO" command and start SMTP.
- helo_domain is localhost's FQDN.
-
-: mailfrom( from_addr )
- This method sends "MAIL FROM" command.
- from_addr is your mail address (xxxx@xxxx)
-
-: rcpt( to_addrs )
- This method sends "RCPT TO" command.
- to_addrs is array of mail address (xxxx@xxxx) of destination.
-
-: data
- This method sends "DATA" command.
-
-: write_mail( mailsrc )
-: write_mail {|socket| ... }
- send 'mailsrc' as mail.
- SMTPCommand reads strings from 'mailsrc' by calling 'each' iterator.
- When iterator, SMTPCommand only stand by socket and pass it.
- (The socket will accepts only 'in_write' method in the block)
-
-: quit
- This method sends "QUIT" command and ends SMTP session.
-
-=end
class SMTPCommand < Command
@@ -189,7 +152,7 @@ Net::Command
end
- def write_mail( mailsrc, &block )
+ def write_mail( mailsrc = nil, &block )
@socket.write_pendstr mailsrc, &block
check_reply SuccessCode
end