Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 154 additions & 80 deletions lib/net/http.rb

Large diffs are not rendered by default.

50 changes: 26 additions & 24 deletions lib/net/http/generic_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class Net::HTTPGenericRequest

def initialize(m, reqbody, resbody, uri_or_path, initheader = nil) # :nodoc:
@method = m
@request_has_body = reqbody
@response_has_body = resbody
@request_has_body = reqbody ? true : false
@response_has_body = resbody ? true : false

if URI === uri_or_path then
raise ArgumentError, "not an HTTP URI" unless URI::HTTP === uri_or_path
Expand All @@ -36,10 +36,10 @@ def initialize(m, reqbody, resbody, uri_or_path, initheader = nil) # :nodoc:
if Net::HTTP::HAVE_ZLIB then
if !initheader ||
!initheader.keys.any? { |k|
%w[accept-encoding range].include? k.downcase
%w[accept-encoding range].include? k.to_s.downcase
} then
@decode_content = true if @response_has_body
initheader = initheader ? initheader.dup : {}
initheader = initheader ? initheader.dup : {} #: Hash[String | Symbol, untyped]
initheader["accept-encoding"] =
"gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
end
Expand All @@ -48,7 +48,9 @@ def initialize(m, reqbody, resbody, uri_or_path, initheader = nil) # :nodoc:
initialize_http_header initheader
self['Accept'] ||= '*/*'
self['User-Agent'] ||= 'Ruby'
self['Host'] ||= @uri.authority if @uri
if (uri = @uri)
self['Host'] ||= uri.authority
end
@body = nil
@body_stream = nil
@body_data = nil
Expand Down Expand Up @@ -129,7 +131,7 @@ def pretty_print(q)
# they want to handle it.

def []=(key, val) # :nodoc:
@decode_content = false if key.downcase == 'accept-encoding'
@decode_content = false if key.to_s.downcase == 'accept-encoding'

super key, val
end
Expand Down Expand Up @@ -218,20 +220,20 @@ def set_body_internal(str) #:nodoc: internal use only
#

def exec(sock, ver, path) #:nodoc: internal use only
if @body
send_request_with_body sock, ver, path, @body
elsif @body_stream
send_request_with_body_stream sock, ver, path, @body_stream
elsif @body_data
send_request_with_body_data sock, ver, path, @body_data
if body = @body
send_request_with_body sock, ver, path, body
elsif body_stream = @body_stream
send_request_with_body_stream sock, ver, path, body_stream
elsif body_data = @body_data
send_request_with_body_data sock, ver, path, body_data
else
write_header sock, ver, path
end
end

def update_uri(addr, port, ssl) # :nodoc: internal use only
# reflect the connection and @path to @uri
return unless @uri
uri = @uri or return

if ssl
scheme = 'https'
Expand All @@ -243,19 +245,19 @@ def update_uri(addr, port, ssl) # :nodoc: internal use only

if host = self['host']
host = URI.parse("//#{host}").host # Remove a port component from the existing Host header
elsif host = @uri.host
elsif host = uri.host
else
host = addr
end
# convert the class of the URI
if @uri.is_a?(klass)
@uri.host = host
@uri.port = port
if uri.is_a?(klass)
uri.host = host
uri.port = port
else
@uri = klass.new(
scheme, @uri.userinfo,
scheme, uri.userinfo,
host, port, nil,
@uri.path, nil, @uri.query, nil)
uri.path, nil, uri.query, nil)
end
end

Expand All @@ -266,13 +268,13 @@ def update_uri(addr, port, ssl) # :nodoc: internal use only
class Chunker #:nodoc:
def initialize(sock)
@sock = sock
@prev = nil
end

def write(buf)
def write(*buf)
# avoid memcpy() of buf, buf can huge and eat memory bandwidth
rv = buf.bytesize
@sock.write("#{rv.to_s(16)}\r\n", buf, "\r\n")
chunk = buf.join
rv = chunk.bytesize
@sock.write("#{rv.to_s(16)}\r\n", chunk, "\r\n")
rv
end

Expand Down Expand Up @@ -314,7 +316,7 @@ def send_request_with_body_data(sock, ver, path, params)
opt = @form_option.dup
require 'securerandom' unless defined?(SecureRandom)
opt[:boundary] ||= SecureRandom.urlsafe_base64(40)
self.set_content_type(self.content_type, boundary: opt[:boundary])
self.set_content_type(self.content_type.to_s, boundary: opt[:boundary])
if chunked?
write_header sock, ver, path
encode_multipart_form_data(sock, params, opt)
Expand Down
70 changes: 44 additions & 26 deletions lib/net/http/header.rb
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ module Net::HTTPHeader
MAX_FIELD_LENGTH = 65536

def initialize_http_header(initheader) #:nodoc:
@header = {}
@header = {} #: Hash[String, Array[String]]
return unless initheader
initheader.each do |key, value|
warn "net/http: duplicated HTTP header: #{key}", uplevel: 3 if key?(key) and $VERBOSE
Expand All @@ -202,7 +202,7 @@ def initialize_http_header(initheader) #:nodoc:
if value.count("\r\n") > 0
raise ArgumentError, "header #{key} has field value #{value.inspect}, this cannot include CR/LF"
end
@header[key.downcase.to_s] = [value]
@header[key.to_s.downcase] = [value]
end
end
end
Expand All @@ -224,7 +224,7 @@ def size #:nodoc: obsolete
# Note that some field values may be retrieved via convenience methods;
# see {Getters}[rdoc-ref:Net::HTTPHeader@Getters].
def [](key)
a = @header[key.downcase.to_s] or return nil
a = @header[String(key).downcase] or return nil
a.join(', ')
end

Expand All @@ -241,7 +241,7 @@ def [](key)
# see {Setters}[rdoc-ref:Net::HTTPHeader@Setters].
def []=(key, val)
unless val
@header.delete key.downcase.to_s
@header.delete String(key).downcase
return val
end
set_field(key, val)
Expand All @@ -261,7 +261,7 @@ def []=(key, val)
# req.get_fields('Foo') # => ["bar", "baz", "baz", "bam"]
#
def add_field(key, val)
stringified_downcased_key = key.downcase.to_s
stringified_downcased_key = String(key).downcase
if @header.key?(stringified_downcased_key)
append_field_value(@header[stringified_downcased_key], val)
else
Expand All @@ -273,15 +273,15 @@ def add_field(key, val)
private def set_field(key, val)
case val
when Enumerable
ary = []
ary = [] #: Array[String]
append_field_value(ary, val)
@header[key.downcase.to_s] = ary
@header[String(key).downcase] = ary
else
val = val.to_s # for compatibility use to_s instead of to_str
if val.b.count("\r\n") > 0
raise ArgumentError, 'header field value cannot include CR/LF'
end
@header[key.downcase.to_s] = [val]
@header[String(key).downcase] = [val]
end
end

Expand All @@ -308,7 +308,7 @@ def add_field(key, val)
# res.get_fields('Nosuch') # => nil
#
def get_fields(key)
stringified_downcased_key = key.downcase.to_s
stringified_downcased_key = String(key).downcase
return nil unless @header[stringified_downcased_key]
@header[stringified_downcased_key].dup
end
Expand Down Expand Up @@ -343,7 +343,17 @@ def get_fields(key)
# res.fetch('Nosuch') # Raises KeyError.
#
def fetch(key, *args, &block) #:yield: +key+
a = @header.fetch(key.downcase.to_s, *args, &block)
key = String(key).downcase
a = if (value = @header[key])
value
elsif block
handler = block
return handler.call(key)
elsif args.empty?
@header.fetch(key)
else
return args.first
end
a.kind_of?(Array) ? a.join(', ') : a
end

Expand All @@ -366,7 +376,7 @@ def fetch(key, *args, &block) #:yield: +key+
#
# Net::HTTPHeader#each is an alias for Net::HTTPHeader#each_header.
def each_header #:yield: +key+, +value+
block_given? or return enum_for(__method__) { @header.size }
block_given? or return enum_for(:each_header) { @header.size }
@header.each do |k,va|
yield k, va.join(', ')
end
Expand All @@ -393,8 +403,11 @@ def each_header #:yield: +key+, +value+
#
# Net::HTTPHeader#each_name is an alias for Net::HTTPHeader#each_key.
def each_name(&block) #:yield: +key+
block_given? or return enum_for(__method__) { @header.size }
@header.each_key(&block)
block_given? or return enum_for(:each_name) { @header.size }
handler = block or return enum_for(:each_name) { @header.size }
@header.each_key do |key|
handler.call(key)
end
end

alias each_key each_name
Expand All @@ -419,7 +432,7 @@ def each_name(&block) #:yield: +key+
#
# Returns an enumerator if no block is given.
def each_capitalized_name #:yield: +key+
block_given? or return enum_for(__method__) { @header.size }
block_given? or return enum_for(:each_capitalized_name) { @header.size }
@header.each_key do |k|
yield capitalize(k)
end
Expand All @@ -440,7 +453,7 @@ def each_capitalized_name #:yield: +key+
#
# Returns an enumerator if no block is given.
def each_value #:yield: +value+
block_given? or return enum_for(__method__) { @header.size }
block_given? or return enum_for(:each_value) { @header.size }
@header.each_value do |va|
yield va.join(', ')
end
Expand All @@ -455,7 +468,7 @@ def each_value #:yield: +value+
# req.delete('Nosuch') # => nil
#
def delete(key)
@header.delete(key.downcase.to_s)
@header.delete(String(key).downcase)
end

# Returns +true+ if the field for the case-insensitive +key+ exists, +false+ otherwise:
Expand All @@ -465,7 +478,7 @@ def delete(key)
# req.key?('Nosuch') # => false
#
def key?(key)
@header.key?(key.downcase.to_s)
@header.key?(String(key).downcase)
end

# Returns a hash of the key/value pairs:
Expand All @@ -486,7 +499,7 @@ def to_hash
#
# Net::HTTPHeader#canonical_each is an alias for Net::HTTPHeader#each_capitalized.
def each_capitalized
block_given? or return enum_for(__method__) { @header.size }
block_given? or return enum_for(:each_capitalized) { @header.size }
@header.each do |k,v|
yield capitalize(k), v.join(', ')
end
Expand Down Expand Up @@ -524,7 +537,7 @@ def range
raise Net::HTTPHeaderSyntaxError, "invalid syntax for byte-ranges-specifier: '#{value}'"
end

byte_range_set = $1
byte_range_set = $1.to_s
result = byte_range_set.split(/,/).map {|spec|
m = /(\d+)?\s*-\s*(\d+)?/i.match(spec) or
raise Net::HTTPHeaderSyntaxError, "invalid byte-range-spec: '#{spec}'"
Expand Down Expand Up @@ -582,10 +595,14 @@ def set_range(r, e = nil)
@header.delete 'range'
return r
end
r = (r...r+e) if e
if e
first = Integer(r) or raise TypeError, 'Range/Integer is required'
length = Integer(e) or raise TypeError, 'Range/Integer is required'
r = first...(first + length)
end
case r
when Numeric
n = r.to_i
n = Integer(r)
rangestr = (n > 0 ? "0-#{n-1}" : "-#{-n}")
when Range
first = r.first
Expand Down Expand Up @@ -619,7 +636,7 @@ def set_range(r, e = nil)
#
def content_length
return nil unless key?('Content-Length')
len = self['Content-Length'].slice(/\d+/) or
len = self['Content-Length'].to_s.slice(/\d+/) or
raise Net::HTTPHeaderSyntaxError, 'wrong Content-Length format'
len.to_i
end
Expand Down Expand Up @@ -726,7 +743,7 @@ def content_type
#
def main_type
return nil unless @header['content-type']
self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip
self['Content-Type'].to_s.split(';').first.to_s.split('/')[0].to_s.strip
end

# Returns the trailing ('subtype') part of the
Expand All @@ -741,7 +758,7 @@ def main_type
#
def sub_type
return nil unless @header['content-type']
_, sub = *self['Content-Type'].split(';').first.to_s.split('/')
_, sub = *self['Content-Type'].to_s.split(';').first.to_s.split('/')
return nil unless sub
sub.strip
end
Expand All @@ -755,11 +772,12 @@ def sub_type
# res.type_params # => {"charset"=>"utf-8"}
#
def type_params
result = {}
result = {} #: Hash[String, String]
list = self['Content-Type'].to_s.split(';')
list.shift
list.each do |param|
k, v = *param.split('=', 2)
next unless k && v
result[k.strip] = v.strip
end
result
Expand All @@ -774,7 +792,7 @@ def type_params
#
# Net::HTTPHeader#content_type= is an alias for Net::HTTPHeader#set_content_type.
def set_content_type(type, params = {})
@header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
@header['content-type'] = [type.to_s + params.map{|k,v|"; #{k}=#{v}"}.join('')]
end

alias content_type= set_content_type
Expand Down
Loading