[macruby-changes] [4083] MacRuby/trunk/lib/net/http.rb
source_changes at macosforge.org
source_changes at macosforge.org
Wed May 12 18:29:29 PDT 2010
Revision: 4083
http://trac.macosforge.org/projects/ruby/changeset/4083
Author: lsansonetti at apple.com
Date: 2010-05-12 18:29:27 -0700 (Wed, 12 May 2010)
Log Message:
-----------
backporting latest net/http from ruby trunk
Modified Paths:
--------------
MacRuby/trunk/lib/net/http.rb
Modified: MacRuby/trunk/lib/net/http.rb
===================================================================
--- MacRuby/trunk/lib/net/http.rb 2010-05-13 00:46:18 UTC (rev 4082)
+++ MacRuby/trunk/lib/net/http.rb 2010-05-13 01:29:27 UTC (rev 4083)
@@ -4,28 +4,29 @@
# Copyright (c) 1999-2007 Yukihiro Matsumoto
# Copyright (c) 1999-2007 Minero Aoki
# Copyright (c) 2001 GOTOU Yuuzou
-#
+#
# Written and maintained by Minero Aoki <aamine at loveruby.net>.
# HTTPS support added by GOTOU Yuuzou <gotoyuzo at notwork.org>.
#
# This file is derived from "http-access.rb".
#
# Documented by Minero Aoki; converted to RDoc by William Webber.
-#
+#
# This program is free software. You can re-distribute and/or
# modify this program under the same terms of ruby itself ---
# Ruby Distribution License or GNU General Public License.
#
-# See Net::HTTP for an overview and examples.
-#
+# See Net::HTTP for an overview and examples.
+#
# NOTE: You can find Japanese version of this document here:
# http://www.ruby-lang.org/ja/man/html/net_http.html
-#
+#
#--
-# $Id: http.rb 18805 2008-08-24 03:21:36Z naruse $
-#++
+# $Id$
+#++
require 'net/protocol'
+autoload :OpenSSL, 'openssl'
require 'uri'
module Net #:nodoc:
@@ -36,29 +37,29 @@
# :startdoc:
# == What Is This Library?
- #
+ #
# This library provides your program functions to access WWW
# documents via HTTP, Hyper Text Transfer Protocol version 1.1.
- # For details of HTTP, refer [RFC2616]
+ # For details of HTTP, refer to [RFC2616]
# (http://www.ietf.org/rfc/rfc2616.txt).
- #
+ #
# == Examples
- #
+ #
# === Getting Document From WWW Server
- #
+ #
# Example #1: Simple GET+print
- #
+ #
# require 'net/http'
# Net::HTTP.get_print 'www.example.com', '/index.html'
- #
+ #
# Example #2: Simple GET+print by URL
- #
+ #
# require 'net/http'
# require 'uri'
# Net::HTTP.get_print URI.parse('http://www.example.com/index.html')
- #
+ #
# Example #3: More generic GET+print
- #
+ #
# require 'net/http'
# require 'uri'
#
@@ -69,7 +70,7 @@
# puts res.body
#
# Example #4: More generic GET+print
- #
+ #
# require 'net/http'
#
# url = URI.parse('http://www.example.com/index.html')
@@ -78,9 +79,9 @@
# http.request(req)
# }
# puts res.body
- #
+ #
# === Posting Form Data
- #
+ #
# require 'net/http'
# require 'uri'
#
@@ -112,15 +113,15 @@
# res = Net::HTTP.post_form(URI.parse('http://www.example.com/search.cgi'),
# {'q' => ['ruby', 'perl'], 'max' => '50'})
# puts res.body
- #
+ #
# === Accessing via Proxy
- #
+ #
# Net::HTTP.Proxy creates http proxy class. It has same
# methods of Net::HTTP but its instances always connect to
# proxy, instead of given host.
- #
+ #
# require 'net/http'
- #
+ #
# proxy_addr = 'your.proxy.host'
# proxy_port = 8080
# :
@@ -128,20 +129,20 @@
# # always connect to your.proxy.addr:8080
# :
# }
- #
+ #
# Since Net::HTTP.Proxy returns Net::HTTP itself when proxy_addr is nil,
# there's no need to change code if there's proxy or not.
- #
+ #
# There are two additional parameters in Net::HTTP.Proxy which allow to
# specify proxy user name and password:
- #
+ #
# Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user = nil, proxy_pass = nil)
- #
+ #
# You may use them to work with authorization-enabled proxies:
- #
+ #
# require 'net/http'
# require 'uri'
- #
+ #
# proxy_host = 'your.proxy.host'
# proxy_port = 8080
# uri = URI.parse(ENV['http_proxy'])
@@ -154,16 +155,16 @@
#
# Note that net/http never rely on HTTP_PROXY environment variable.
# If you want to use proxy, set it explicitly.
- #
+ #
# === Following Redirection
- #
+ #
# require 'net/http'
# require 'uri'
- #
+ #
# def fetch(uri_str, limit = 10)
- # # You should choose better exception.
+ # # You should choose better exception.
# raise ArgumentError, 'HTTP redirect too deep' if limit == 0
- #
+ #
# response = Net::HTTP.get_response(URI.parse(uri_str))
# case response
# when Net::HTTPSuccess then response
@@ -172,25 +173,25 @@
# response.error!
# end
# end
- #
+ #
# print fetch('http://www.ruby-lang.org')
- #
+ #
# Net::HTTPSuccess and Net::HTTPRedirection is a HTTPResponse class.
# All HTTPResponse objects belong to its own response class which
# indicate HTTP result status. For details of response classes,
# see section "HTTP Response Classes".
- #
+ #
# === Basic Authentication
- #
+ #
# require 'net/http'
- #
+ #
# Net::HTTP.start('www.example.com') {|http|
# req = Net::HTTP::Get.new('/secret-page.html')
# req.basic_auth 'account', 'password'
# response = http.request(req)
# print response.body
# }
- #
+ #
# === HTTP Request Classes
#
# Here is HTTP request class hierarchy.
@@ -220,7 +221,7 @@
# HTTPUnknownResponse
# HTTPInformation # 1xx
# HTTPContinue # 100
- # HTTPSwitchProtocl # 101
+ # HTTPSwitchProtocol # 101
# HTTPSuccess # 2xx
# HTTPOK # 200
# HTTPCreated # 201
@@ -263,28 +264,28 @@
# HTTPServiceUnavailable # 503
# HTTPGatewayTimeOut # 504
# HTTPVersionNotSupported # 505
- #
+ #
# == Switching Net::HTTP versions
- #
+ #
# You can use net/http.rb 1.1 features (bundled with Ruby 1.6)
# by calling HTTP.version_1_1. Calling Net::HTTP.version_1_2
# allows you to use 1.2 features again.
- #
+ #
# # example
# Net::HTTP.start {|http1| ...(http1 has 1.2 features)... }
- #
+ #
# Net::HTTP.version_1_1
# Net::HTTP.start {|http2| ...(http2 has 1.1 features)... }
- #
+ #
# Net::HTTP.version_1_2
# Net::HTTP.start {|http3| ...(http3 has 1.2 features)... }
- #
+ #
# This function is NOT thread-safe.
#
class HTTP < Protocol
# :stopdoc:
- Revision = %q$Revision: 18805 $.split[1]
+ Revision = %q$Revision$.split[1]
HTTPVersion = '1.1'
@newimpl = true
begin
@@ -338,7 +339,7 @@
#
# Get body from target and output it to +$stdout+. The
# target can either be specified as (+uri+), or as
- # (+host+, +path+, +port+ = 80); so:
+ # (+host+, +path+, +port+ = 80); so:
#
# Net::HTTP.get_print URI.parse('http://www.example.com/index.html')
#
@@ -358,7 +359,7 @@
# Send a GET request to the target and return the response
# as a string. The target can either be specified as
# (+uri+), or as (+host+, +path+, +port+ = 80); so:
- #
+ #
# print Net::HTTP.get(URI.parse('http://www.example.com/index.html'))
#
# or:
@@ -372,7 +373,7 @@
# Send a GET request to the target and return the response
# as a Net::HTTPResponse object. The target can either be specified as
# (+uri+), or as (+host+, +path+, +port+ = 80); so:
- #
+ #
# res = Net::HTTP.get_response(URI.parse('http://www.example.com/index.html'))
# print res.body
#
@@ -442,15 +443,51 @@
BufferedIO
end
- # creates a new Net::HTTP object and opens its TCP connection and
- # HTTP session. If the optional block is given, the newly
- # created Net::HTTP object is passed to it and closed when the
+ # call-seq:
+ # HTTP.start(address, port, p_addr, p_port, p_user, p_pass, &block)
+ # HTTP.start(address, port=nil, p_addr=nil, p_port=nil, p_user=nil, p_pass=nil, opt, &block)
+ #
+ # creates a new Net::HTTP object and opens its TCP connection and
+ # HTTP session.
+ #
+ # Argments are following:
+ # _address_ :: hostname or IP address of the server
+ # _port_ :: port of the server
+ # _p_addr_ :: address of proxy
+ # _p_port_ :: port of proxy
+ # _p_user_ :: user of proxy
+ # _p_pass_ :: pass of proxy
+ # _opt_ :: optional hash
+ #
+ # _opt_ sets following values by its accessor.
+ # The keys are ca_file, ca_path, cert, cert_store, ciphers,
+ # close_on_empty_response, key, open_timeout, read_timeout, ssl_timeout,
+ # ssl_version, use_ssl, verify_callback, verify_depth and verify_mode.
+ # If you set :use_ssl as true, you can use https and default value of
+ # verify_mode is set as OpenSSL::SSL::VERIFY_PEER.
+ #
+ # If the optional block is given, the newly
+ # created Net::HTTP object is passed to it and closed when the
# block finishes. In this case, the return value of this method
# is the return value of the block. If no block is given, the
# return value of this method is the newly created Net::HTTP object
# itself, and the caller is responsible for closing it upon completion.
- def HTTP.start(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil, &block) # :yield: +http+
- new(address, port, p_addr, p_port, p_user, p_pass).start(&block)
+ def HTTP.start(address, *arg, &block) # :yield: +http+
+ arg.pop if opt = Hash.try_convert(arg[-1])
+ port, p_addr, p_port, p_user, p_pass = *arg
+ port = https_default_port if !port && opt && opt[:use_ssl]
+ http = new(address, port, p_addr, p_port, p_user, p_pass)
+
+ if opt
+ opt = {verify_mode: OpenSSL::SSL::VERIFY_PEER}.update(opt) if opt[:use_ssl]
+ http.methods.grep(/\A(\w+)=\z/) do |meth|
+ key = $1.to_sym
+ opt.key?(key) or next
+ http.__send__(meth, opt[key])
+ end
+ end
+
+ http.start(&block)
end
class << HTTP
@@ -544,11 +581,37 @@
# returns true if use SSL/TLS with HTTP.
def use_ssl?
- false # redefined in net/https
+ @use_ssl
end
+ # 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)
+ if started? and @use_ssl != flag
+ raise IOError, "use_ssl value changed, but session already started"
+ end
+ @use_ssl = flag
+ end
+
+ SSL_ATTRIBUTES = %w(
+ ssl_version key cert ca_file ca_path cert_store ciphers
+ verify_mode verify_callback verify_depth ssl_timeout
+ )
+ attr_accessor(*SSL_ATTRIBUTES)
+
+ # return the X.509 certificates the server presented.
+ def peer_cert
+ if not use_ssl? or not @socket
+ return nil
+ end
+ @socket.io.peer_cert
+ end
+
# Opens TCP connection and HTTP session.
- #
+ #
# When this method is called with block, gives a HTTP object
# to the block and closes the TCP connection / HTTP session
# after the block executed.
@@ -582,8 +645,11 @@
D "opened"
if use_ssl?
ssl_parameters = Hash.new
+ iv_list = instance_variables
SSL_ATTRIBUTES.each do |name|
- if value = instance_variable_get("@#{name}")
+ ivname = "@#{name}".intern
+ if iv_list.include?(ivname) and
+ value = instance_variable_get(ivname)
ssl_parameters[name] = value
end
end
@@ -652,9 +718,9 @@
# Arguments are address/port of proxy host and username/password
# if authorization on proxy server is required.
# You can replace the HTTP class with created proxy class.
- #
+ #
# If ADDRESS is nil, this method returns self (Net::HTTP).
- #
+ #
# # Example
# proxy_class = Net::HTTP::Proxy('proxy.example.com', 8080)
# :
@@ -662,7 +728,7 @@
# # connecting proxy.foo.org:8080
# :
# }
- #
+ #
def HTTP.Proxy(p_addr, p_port = nil, p_user = nil, p_pass = nil)
return self unless p_addr
delta = ProxyDelta
@@ -762,14 +828,14 @@
# and it defaults to an empty hash.
# If +initheader+ doesn't have the key 'accept-encoding', then
# a value of "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" is used,
- # so that gzip compression is used in preference to deflate
- # compression, which is used in preference to no compression.
+ # so that gzip compression is used in preference to deflate
+ # compression, which is used in preference to no compression.
# Ruby doesn't have libraries to support the compress (Lempel-Ziv)
# compression, so that is not supported. The intent of this is
# to reduce bandwidth by default. If this routine sets up
# compression, then it does the decompression also, removing
# the header as well to prevent confusion. Otherwise
- # it leaves the body as it found it.
+ # it leaves the body as it found it.
#
# In version 1.1 (ruby 1.6), this method returns a pair of objects,
# a Net::HTTPResponse object and the entity body string.
@@ -784,7 +850,7 @@
# +dest+ argument is obsolete.
# It still works but you must not use it.
#
- # In version 1.1, this method might raise an exception for
+ # In version 1.1, this method might raise an exception for
# 3xx (redirect). In this case you can get a HTTPResponse object
# by "anException.response".
#
@@ -795,7 +861,7 @@
#
# # version 1.2 (bundled with Ruby 1.8 or later)
# response = http.get('/index.html')
- #
+ #
# # using block
# File.open('result.txt', 'w') {|f|
# http.get('/~foo/') do |str|
@@ -824,7 +890,7 @@
r.delete("content-encoding")
when "identity"
; # nothing needed
- else
+ else
; # Don't do anything dramatic, unless we need to later
end
else
@@ -842,21 +908,21 @@
# Gets only the header from +path+ on the connected-to host.
# +header+ is a Hash like { 'Accept' => '*/*', ... }.
- #
+ #
# This method returns a Net::HTTPResponse object.
- #
- # In version 1.1, this method might raise an exception for
+ #
+ # In version 1.1, this method might raise an exception for
# 3xx (redirect). On the case you can get a HTTPResponse object
# by "anException.response".
# In version 1.2, this method never raises an exception.
- #
+ #
# response = nil
# Net::HTTP.start('some.www.server', 80) {|http|
# response = http.head('/index.html')
# }
# p response['content-type']
#
- def head(path, initheader = nil)
+ def head(path, initheader = nil)
res = request(Head.new(path, initheader))
res.value unless @newimpl
res
@@ -864,11 +930,11 @@
# Posts +data+ (must be a String) to +path+. +header+ must be a Hash
# like { 'Accept' => '*/*', ... }.
- #
+ #
# In version 1.1 (ruby 1.6), this method returns a pair of objects, a
# Net::HTTPResponse object and an entity body string.
# In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse object.
- #
+ #
# If called with a block, yields each fragment of the
# entity body in turn as a string as it are read from
# the socket. Note that in this case, the returned response
@@ -876,18 +942,18 @@
#
# +dest+ argument is obsolete.
# It still works but you must not use it.
- #
- # In version 1.1, this method might raise an exception for
+ #
+ # In version 1.1, this method might raise an exception for
# 3xx (redirect). In this case you can get an HTTPResponse object
# by "anException.response".
# In version 1.2, this method never raises exception.
- #
+ #
# # version 1.1
# response, body = http.post('/cgi-bin/search.rb', 'query=foo')
- #
+ #
# # version 1.2
# response = http.post('/cgi-bin/search.rb', 'query=foo')
- #
+ #
# # using block
# File.open('result.txt', 'w') {|f|
# http.post('/cgi-bin/search.rb', 'query=foo') do |str|
@@ -980,21 +1046,21 @@
# Sends a GET request to the +path+ and gets a response,
# as an HTTPResponse object.
- #
+ #
# When called with a block, yields an HTTPResponse object.
# The body of this response will not have been read yet;
# the caller can process it using HTTPResponse#read_body,
# if desired.
#
# Returns the response.
- #
+ #
# This method never raises Net::* exceptions.
- #
+ #
# response = http.request_get('/index.html')
# # The entity body is already read here.
# p response['content-type']
# puts response.body
- #
+ #
# # using block
# http.request_get('/index.html') {|response|
# p response['content-type']
@@ -1011,9 +1077,9 @@
# as an HTTPResponse object.
#
# Returns the response.
- #
+ #
# This method never raises Net::* exceptions.
- #
+ #
# response = http.request_head('/index.html')
# p response['content-type']
#
@@ -1023,21 +1089,21 @@
# Sends a POST request to the +path+ and gets a response,
# as an HTTPResponse object.
- #
+ #
# When called with a block, yields an HTTPResponse object.
# The body of this response will not have been read yet;
# the caller can process it using HTTPResponse#read_body,
# if desired.
#
# Returns the response.
- #
+ #
# This method never raises Net::* exceptions.
- #
+ #
# # example
# response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...')
# p response.status
# puts response.body # body is already read
- #
+ #
# # using block
# http.request_post('/cgi-bin/nice.rb', 'datadatadata...') {|response|
# p response.status
@@ -1065,7 +1131,7 @@
# This method also sends DATA string if DATA is given.
#
# Returns a HTTPResponse object.
- #
+ #
# This method never raises Net::* exceptions.
#
# response = http.send_request('GET', '/index.html')
@@ -1079,14 +1145,14 @@
# Sends an HTTPRequest object REQUEST to the HTTP server.
# This method also sends DATA string if REQUEST is a post/put request.
# Giving DATA for get/head request causes ArgumentError.
- #
+ #
# When called with a block, yields an HTTPResponse object.
# The body of this response will not have been read yet;
# the caller can process it using HTTPResponse#read_body,
# if desired.
#
# Returns a HTTPResponse object.
- #
+ #
# This method never raises Net::* exceptions.
#
def request(req, body = nil, &block) # :yield: +response+
@@ -1121,6 +1187,10 @@
}
end_transport req, res
res
+ rescue => exception
+ D "Conn close because of error #{exception}"
+ @socket.close unless @socket.closed?
+ raise exception
end
def begin_transport(req)
@@ -1289,15 +1359,17 @@
end
# Returns the header field corresponding to the case-insensitive key.
- # Returns the default value +args+, or the result of the block, or nil,
- # if there's no header field named key. See Hash#fetch
+ # Returns the default value +args+, or the result of the block, or
+ # raises an IndexErrror if there's no header field named +key+
+ # See Hash#fetch
def fetch(key, *args, &block) #:yield: +key+
a = @header.fetch(key.downcase, *args, &block)
- a.join(', ')
+ a.kind_of?(Array) ? a.join(', ') : a
end
# Iterates for each header names and values.
def each_header #:yield: +key+, +value+
+ block_given? or return enum_for(__method__)
@header.each do |k,va|
yield k, va.join(', ')
end
@@ -1307,13 +1379,15 @@
# Iterates for each header names.
def each_name(&block) #:yield: +key+
+ block_given? or return enum_for(__method__)
@header.each_key(&block)
end
alias each_key each_name
# Iterates for each capitalized header names.
- def each_capitalized_name(&block) #:yield: +key+
+ def each_capitalized_name #:yield: +key+
+ block_given? or return enum_for(__method__)
@header.each_key do |k|
yield capitalize(k)
end
@@ -1321,6 +1395,7 @@
# Iterates for each header values.
def each_value #:yield: +value+
+ block_given? or return enum_for(__method__)
@header.each_value do |va|
yield va.join(', ')
end
@@ -1343,6 +1418,7 @@
# As for #each_header, except the keys are provided in capitalized form.
def each_capitalized
+ block_given? or return enum_for(__method__)
@header.each do |k,v|
yield capitalize(k), v.join(', ')
end
@@ -1418,7 +1494,7 @@
raise HTTPHeaderSyntaxError, 'wrong Content-Length format'
len.to_i
end
-
+
def content_length=(len)
unless len
@header.delete 'content-length'
@@ -1428,7 +1504,7 @@
end
# Returns "true" if the "transfer-encoding" header is present and
- # set to "chunked". This is an HTTP/1.1 feature, allowing the
+ # set to "chunked". This is an HTTP/1.1 feature, allowing the
# the content to be sent in "chunks" without at the outset
# stating the entire content length.
def chunked?
@@ -1444,13 +1520,13 @@
return nil unless @header['content-range']
m = %r<bytes\s+(\d+)-(\d+)/(\d+|\*)>i.match(self['Content-Range']) or
raise HTTPHeaderSyntaxError, 'wrong Content-Range format'
- m[1].to_i .. m[2].to_i + 1
+ m[1].to_i .. m[2].to_i
end
# The length of the range represented in Content-Range: header.
def range_length
r = content_range() or return nil
- r.end - r.begin
+ r.end - r.begin + 1
end
# Returns a content type string such as "text/html".
@@ -1469,7 +1545,7 @@
return nil unless @header['content-type']
self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip
end
-
+
# Returns a content type string such as "html".
# This method returns nil if Content-Type: header field does not exist
# or sub-type is not given (e.g. "Content-Type: text").
@@ -1512,7 +1588,7 @@
# http.form_data = {"q" => "ruby", "lang" => "en"}
# http.form_data = {"q" => ["ruby", "perl"], "lang" => "en"}
# http.set_form_data({"q" => "ruby", "lang" => "en"}, ';')
- #
+ #
def set_form_data(params, sep = '&')
self.body = params.map {|k, v| encode_kvpair(k, v) }.flatten.join(sep)
self.content_type = 'application/x-www-form-urlencoded'
@@ -1521,7 +1597,7 @@
alias form_data= set_form_data
def encode_kvpair(k, vs)
- Array(vs).map {|v| "#{urlencode(k)}=#{urlencode(v.to_s)}" }
+ Array(vs).map {|v| "#{urlencode(k.to_s)}=#{urlencode(v.to_s)}" }
end
private :encode_kvpair
@@ -1688,14 +1764,14 @@
buf << "\r\n"
sock.write buf
end
-
+
end
- #
+ #
# HTTP request class. This class wraps request header and entity path.
# You *must* use its subclass, Net::HTTP::Get, Post, Head.
- #
+ #
class HTTPRequest < HTTPGenericRequest
# Creates HTTP request object.
@@ -1835,17 +1911,17 @@
# HTTP response class. This class wraps response header and entity.
# Mixes in the HTTPHeader module, which provides access to response
# header values both via hash-like methods and individual readers.
- # Note that each possible HTTP response code defines its own
+ # Note that each possible HTTP response code defines its own
# HTTPResponse subclass. These are listed below.
# All classes are
# defined under the Net module. Indentation indicates inheritance.
- #
+ #
# xxx HTTPResponse
- #
+ #
# 1xx HTTPInformation
- # 100 HTTPContinue
+ # 100 HTTPContinue
# 101 HTTPSwitchProtocol
- #
+ #
# 2xx HTTPSuccess
# 200 HTTPOK
# 201 HTTPCreated
@@ -1854,7 +1930,7 @@
# 204 HTTPNoContent
# 205 HTTPResetContent
# 206 HTTPPartialContent
- #
+ #
# 3xx HTTPRedirection
# 300 HTTPMultipleChoice
# 301 HTTPMovedPermanently
@@ -1863,7 +1939,7 @@
# 304 HTTPNotModified
# 305 HTTPUseProxy
# 307 HTTPTemporaryRedirect
- #
+ #
# 4xx HTTPClientError
# 400 HTTPBadRequest
# 401 HTTPUnauthorized
@@ -1883,7 +1959,7 @@
# 415 HTTPUnsupportedMediaType
# 416 HTTPRequestedRangeNotSatisfiable
# 417 HTTPExpectationFailed
- #
+ #
# 5xx HTTPServerError
# 500 HTTPInternalServerError
# 501 HTTPNotImplemented
@@ -1891,7 +1967,7 @@
# 503 HTTPServiceUnavailable
# 504 HTTPGatewayTimeOut
# 505 HTTPVersionNotSupported
- #
+ #
# xxx HTTPUnknownResponse
#
class HTTPResponse
@@ -2145,19 +2221,26 @@
end
def each_response_header(sock)
+ key = value = nil
while true
line = sock.readuntil("\n", true).sub(/\s+\z/, '')
break if line.empty?
- m = /\A([^:]+):\s*/.match(line) or
- raise HTTPBadResponse, 'wrong header line format'
- yield m[1], m.post_match
+ if line[0] == ?\s or line[0] == ?\t and value
+ value << ' ' unless value.empty?
+ value << line.strip
+ else
+ yield key, value if key
+ key, value = line.strip.split(/\s*:\s*/, 2)
+ raise HTTPBadResponse, 'wrong header line format' if value.nil?
+ end
end
+ yield key, value if key
end
end
# next is to fix bug in RDoc, where the private inside class << self
# spills out.
- public
+ public
include HTTPHeader
@@ -2190,7 +2273,7 @@
# To allow Net::HTTP 1.1 style assignment
# e.g.
# response, body = Net::HTTP.get(....)
- #
+ #
def to_ary
warn "net/http.rb: warning: Net::HTTP v1.1 style assignment found at #{caller(1)[0]}; use `response = http.get(...)' instead." if $VERBOSE
res = self.dup
@@ -2350,8 +2433,12 @@
raise HTTPBadResponse, "wrong chunk size line: #{line}"
len = hexlen.hex
break if len == 0
- @socket.read len, dest; total += len
- @socket.read 2 # \r\n
+ begin
+ @socket.read len, dest
+ ensure
+ total += len
+ @socket.read 2 # \r\n
+ end
end
until @socket.readline.empty?
# none
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100512/2c71e492/attachment-0001.html>
More information about the macruby-changes
mailing list