diff --git a/lib/net/http.rb b/lib/net/http.rb
index 7fd4c3ed..44d31472 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -761,11 +761,23 @@ class << HTTP
# Like Net::HTTP.get, but writes the returned body to $stdout;
# returns +nil+.
def HTTP.get_print(uri_or_host, path_or_headers = nil, port = nil)
- get_response(uri_or_host, path_or_headers, port) {|res|
- res.read_body do |chunk|
- $stdout.print chunk
- end
- }
+ if path_or_headers && !path_or_headers.is_a?(Hash)
+ host = uri_or_host #: String
+ path = path_or_headers #: String
+ get_response(host, path, port) {|res|
+ res.read_body do |chunk|
+ $stdout.print chunk
+ end
+ }
+ else
+ uri = uri_or_host #: URI::HTTP
+ headers = path_or_headers #: headers?
+ get_response(uri, headers) {|res|
+ res.read_body do |chunk|
+ $stdout.print chunk
+ end
+ }
+ end
nil
end
@@ -802,7 +814,15 @@ def HTTP.get_print(uri_or_host, path_or_headers = nil, port = nil)
# - Net::HTTP#get: convenience method for \HTTP method +GET+.
#
def HTTP.get(uri_or_host, path_or_headers = nil, port = nil)
- get_response(uri_or_host, path_or_headers, port).body
+ if path_or_headers && !path_or_headers.is_a?(Hash)
+ host = uri_or_host #: String
+ path = path_or_headers #: String
+ get_response(host, path, port).body
+ else
+ uri = uri_or_host #: URI::HTTP
+ headers = path_or_headers #: headers?
+ get_response(uri, headers).body
+ end
end
# :call-seq:
@@ -813,15 +833,16 @@ def HTTP.get(uri_or_host, path_or_headers = nil, port = nil)
# instead of the body string.
def HTTP.get_response(uri_or_host, path_or_headers = nil, port = nil, &block)
if path_or_headers && !path_or_headers.is_a?(Hash)
- host = uri_or_host
- path = path_or_headers
+ host = uri_or_host #: String
+ path = path_or_headers #: String
new(host, port || HTTP.default_port).start {|http|
return http.request_get(path, &block)
}
else
- uri = uri_or_host
- headers = path_or_headers
- start(uri.hostname, uri.port,
+ uri = uri_or_host #: URI::HTTP
+ headers = path_or_headers #: headers?
+ hostname = uri.hostname or raise ArgumentError, "no host component for URI"
+ start(hostname, uri.port,
:use_ssl => uri.scheme == 'https') {|http|
return http.request_get(uri, headers, &block)
}
@@ -855,7 +876,8 @@ def HTTP.get_response(uri_or_host, path_or_headers = nil, port = nil, &block)
# - Net::HTTP#post: convenience method for \HTTP method +POST+.
#
def HTTP.post(url, data, header = nil)
- start(url.hostname, url.port,
+ hostname = url.hostname or raise ArgumentError, "no host component for URI"
+ start(hostname, url.port,
:use_ssl => url.scheme == 'https' ) {|http|
http.post(url, data, header)
}
@@ -884,8 +906,11 @@ def HTTP.post(url, data, header = nil)
def HTTP.post_form(url, params)
req = Post.new(url)
req.form_data = params
- req.basic_auth url.user, url.password if url.user
- start(url.hostname, url.port,
+ if user = url.user
+ req.basic_auth(user, url.password.to_s)
+ end
+ hostname = url.hostname or raise ArgumentError, "no host component for URI"
+ start(hostname, url.port,
:use_ssl => url.scheme == 'https' ) {|http|
http.request(req)
}
@@ -918,7 +943,8 @@ def HTTP.post_form(url, params)
# - Net::HTTP#put: convenience method for \HTTP method +PUT+.
#
def HTTP.put(url, data, header = nil)
- start(url.hostname, url.port,
+ hostname = url.hostname or raise ArgumentError, "no host component for URI"
+ start(hostname, url.port,
:use_ssl => url.scheme == 'https' ) {|http|
http.put(url, data, header)
}
@@ -1054,14 +1080,22 @@ def HTTP.start(address, *arg, &block) # :yield: +http+
if opt[:use_ssl]
opt = {verify_mode: OpenSSL::SSL::VERIFY_PEER}.update(opt)
end
- http.methods.grep(/\A(\w+)=\z/) do |meth|
- key = $1.to_sym
- opt.key?(key) or next
+ http.methods.grep(/\A(\w+)=\z/).each do |meth|
+ match = /\A(\w+)=\z/.match(meth.to_s)
+ next unless match
+ key = match[1]
+ next unless key
+ key = key.to_sym
+ next unless opt.key?(key)
http.__send__(meth, opt[key])
end
end
- http.start(&block)
+ if block
+ http.start(&block)
+ else
+ http.start
+ end
end
class << HTTP
@@ -1098,7 +1132,7 @@ class << HTTP
# see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
#
def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_no_proxy = nil, p_use_ssl = nil)
- http = super address, port
+ http = newobj(address, port)
if proxy_class? then # from Net::HTTP::Proxy()
http.proxy_from_env = @proxy_from_env
@@ -1107,14 +1141,14 @@ def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_p
http.proxy_user = @proxy_user
http.proxy_pass = @proxy_pass
http.proxy_use_ssl = @proxy_use_ssl
- elsif p_addr == :ENV then
+ elsif p_addr.is_a?(Symbol) && p_addr == :ENV then
http.proxy_from_env = true
else
- if p_addr && p_no_proxy && !URI::Generic.use_proxy?(address, address, port, p_no_proxy)
+ if p_addr && p_no_proxy && !URI::Generic.use_proxy?(address, address, port || default_port, p_no_proxy)
p_addr = nil
p_port = nil
end
- http.proxy_address = p_addr
+ http.proxy_address = p_addr&.to_s
http.proxy_port = p_port || default_port
http.proxy_user = p_user
http.proxy_pass = p_pass
@@ -1347,7 +1381,12 @@ def response_body_encoding=(value)
# http.finish
#
def ipaddr
- started? ? @socket.io.peeraddr[3] : @ipaddr
+ if started?
+ socket = @socket or return @ipaddr
+ socket.io.peeraddr[3]
+ else
+ @ipaddr
+ end
end
# Sets the IP address for the connection:
@@ -1416,7 +1455,9 @@ def max_retries=(retries)
# http.get('/todos/1') # Raises Net::ReadTimeout.
#
def read_timeout=(sec)
- @socket.read_timeout = sec if @socket
+ if (socket = @socket)
+ socket.read_timeout = sec
+ end
@read_timeout = sec
end
@@ -1440,7 +1481,9 @@ def read_timeout=(sec)
# http.post(_uri.path, data, headers) # Raises Net::WriteTimeout.
#
def write_timeout=(sec)
- @socket.write_timeout = sec if @socket
+ if (socket = @socket)
+ socket.write_timeout = sec
+ end
@write_timeout = sec
end
@@ -1453,7 +1496,9 @@ def write_timeout=(sec)
# If the \HTTP object does not receive a response in this many seconds
# it sends the request body.
def continue_timeout=(sec)
- @socket.continue_timeout = sec if @socket
+ if (socket = @socket)
+ socket.continue_timeout = sec
+ end
@continue_timeout = sec
end
@@ -1595,10 +1640,11 @@ def use_ssl=(flag)
# for the session's socket peer,
# or +nil+ if none.
def peer_cert
- if not use_ssl? or not @socket
+ socket = @socket
+ if !use_ssl? || !socket
return nil
end
- @socket.io.peer_cert
+ socket.io.peer_cert
end
# Starts an \HTTP session.
@@ -1676,7 +1722,8 @@ def connect
begin
s = timeouted_connect(conn_addr, conn_port)
rescue => e
- if (defined?(IO::TimeoutError) && e.is_a?(IO::TimeoutError)) || e.is_a?(Errno::ETIMEDOUT) # for compatibility with previous versions
+ timeout_error = IO.const_get(:TimeoutError, false) if IO.const_defined?(:TimeoutError, false)
+ if (timeout_error && e.is_a?(timeout_error)) || e.is_a?(Errno::ETIMEDOUT) # for compatibility with previous versions
e = Net::OpenTimeout.new(e)
end
raise e, "Failed to open TCP connection to " +
@@ -1718,19 +1765,23 @@ def connect
end
end
end
- @ssl_context.set_params(ssl_parameters)
- unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby
- @ssl_context.session_cache_mode =
+ ssl_context = @ssl_context or raise OpenSSL::SSL::SSLError, 'SSL context not initialized'
+ ssl_context.set_params(ssl_parameters)
+ unless ssl_context.session_cache_mode.nil? # a dummy method on JRuby
+ ssl_context.session_cache_mode =
OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
end
- if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby
- @ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
+ if ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby
+ ssl_context.session_new_cb = ->(socket_or_pair) do
+ socket, session = Array(socket_or_pair)
+ @ssl_session = session || socket.session
+ end
end
# Still do the post_connection_check below even if connecting
# to IP address
- verify_hostname = @ssl_context.verify_hostname
+ verify_hostname = ssl_context.verify_hostname
# Server Name Indication (SNI) RFC 3546/6066
case @address
@@ -1739,25 +1790,26 @@ def connect
# per RFC 6066, section 3.
# Avoid openssl warning
- @ssl_context.verify_hostname = false
+ ssl_context.verify_hostname = false
else
ssl_host_address = @address
end
debug "starting SSL for #{conn_addr}:#{conn_port}..."
- s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
+ s = OpenSSL::SSL::SSLSocket.new(s, ssl_context)
s.sync_close = true
s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address
- if @ssl_session and
- Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
- s.session = @ssl_session
+ if (ssl_session = @ssl_session) &&
+ Process.clock_gettime(Process::CLOCK_REALTIME) < ssl_session.time.to_f + ssl_session.timeout
+ s.session = ssl_session
end
ssl_socket_connect(s, @open_timeout)
- if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
+ if (ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
s.post_connection_check(@address)
end
- debug "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
+ cipher = s.cipher
+ debug "SSL established, protocol: #{s.ssl_version}, cipher: #{cipher ? cipher[0] : nil}"
end
@socket = BufferedIO.new(s, read_timeout: @read_timeout,
write_timeout: @write_timeout,
@@ -1785,11 +1837,13 @@ def connect
private_constant :TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT
def timeouted_connect(conn_addr, conn_port)
+ conn_addr = conn_addr or raise ArgumentError, "missing connection address"
+ conn_port = conn_port or raise ArgumentError, "missing connection port"
if TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT
- TCPSocket.open(conn_addr, conn_port, @local_host, @local_port, open_timeout: @open_timeout)
+ TCPSocket.new(conn_addr, conn_port, @local_host, @local_port, open_timeout: @open_timeout)
else
Timeout.timeout(@open_timeout, Net::OpenTimeout) {
- TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
+ TCPSocket.new(conn_addr, conn_port, @local_host, @local_port)
}
end
end
@@ -1801,7 +1855,9 @@ def on_connect
def do_finish
@started = false
- @socket.close if @socket
+ if (socket = @socket)
+ socket.close
+ end
@socket = nil
end
private :do_finish
@@ -1832,13 +1888,14 @@ def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_use_ss
Class.new(self) {
@is_proxy_class = true
- if p_addr == :ENV then
+ case p_addr
+ when :ENV
@proxy_from_env = true
@proxy_address = nil
@proxy_port = nil
else
@proxy_from_env = false
- @proxy_address = p_addr
+ @proxy_address = String(p_addr)
@proxy_port = p_port || default_port
end
@@ -2011,13 +2068,14 @@ def edit_path(path)
# - Net::HTTP.get: sends GET request, returns response body.
#
def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+
- res = nil
-
request(Get.new(path, initheader)) {|r|
- r.read_body dest, &block
- res = r
+ if block
+ raise ArgumentError, 'both arg and block given for HTTP method' if dest
+ r.read_body(&block)
+ else
+ r.read_body(dest)
+ end
}
- res
end
# Sends a HEAD request to the server;
@@ -2404,7 +2462,7 @@ def request(req, body = nil, &block) # :yield: +response+
}
end
if proxy_user()
- req.proxy_basic_auth proxy_user(), proxy_pass() unless use_ssl?
+ req.proxy_basic_auth proxy_user(), proxy_pass().to_s unless use_ssl?
end
req.set_body_internal body
res = transport_request(req, &block)
@@ -2420,12 +2478,14 @@ def request(req, body = nil, &block) # :yield: +response+
# Executes a request which uses a representation
# and returns its body.
def send_entity(path, data, initheader, dest, type, &block)
- res = nil
request(type.new(path, initheader), data) {|r|
- r.read_body dest, &block
- res = r
+ if block
+ raise ArgumentError, 'both arg and block given for HTTP method' if dest
+ r.read_body(&block)
+ else
+ r.read_body(dest)
+ end
}
- res
end
# :stopdoc:
@@ -2437,24 +2497,29 @@ def transport_request(req)
begin
begin_transport req
res = catch(:response) {
+ socket = @socket or raise IOError, 'HTTP session not yet started'
begin
- req.exec @socket, @curr_http_version, edit_path(req.path)
+ req.exec socket, @curr_http_version, edit_path(req.path)
rescue Errno::EPIPE
# Failure when writing full request, but we can probably
# still read the received response.
end
- begin
- res = HTTPResponse.read_new(@socket)
+ res = HTTPResponse.read_new(socket)
+ loop do
res.decode_content = req.decode_content
res.body_encoding = @response_body_encoding
res.ignore_eof = @ignore_eof
- end while res.kind_of?(HTTPInformation)
+ break unless res.kind_of?(HTTPInformation)
+ res = HTTPResponse.read_new(socket)
+ end
- res.uri = req.uri
+ response = res or raise Net::HTTPBadResponse, 'no HTTP response'
+ response.uri = req.uri if req.uri
- res
+ response
}
+ res = res or raise Net::HTTPBadResponse, 'no HTTP response'
res.reading_body(@socket, req.response_body_permitted?) {
if block_given?
count = max_retries # Don't restart in the middle of a download
@@ -2470,12 +2535,16 @@ def transport_request(req)
Timeout::Error => exception
if count < max_retries && IDEMPOTENT_METHODS_.include?(req.method)
count += 1
- @socket.close if @socket
+ if (socket = @socket)
+ socket.close
+ end
debug "Conn close because of error #{exception}, and retry"
retry
end
debug "Conn close because of error #{exception}"
- @socket.close if @socket
+ if (socket = @socket)
+ socket.close
+ end
raise
end
@@ -2483,21 +2552,25 @@ def transport_request(req)
res
rescue => exception
debug "Conn close because of error #{exception}"
- @socket.close if @socket
+ if (socket = @socket)
+ socket.close
+ end
raise exception
end
def begin_transport(req)
- if @socket.closed?
+ socket = @socket or raise IOError, 'HTTP session not yet started'
+ if socket.closed?
connect
elsif @last_communicated
- if @last_communicated + @keep_alive_timeout < Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ last_communicated = @last_communicated
+ if last_communicated && last_communicated + @keep_alive_timeout < Process.clock_gettime(Process::CLOCK_MONOTONIC)
debug 'Conn close because of keep_alive_timeout'
- @socket.close
+ socket.close
connect
- elsif @socket.io.to_io.wait_readable(0) && @socket.eof?
+ elsif socket.io.to_io.wait_readable(0) && socket.eof?
debug "Conn close because of EOF"
- @socket.close
+ socket.close
connect
end
end
@@ -2511,19 +2584,20 @@ def begin_transport(req)
end
def end_transport(req, res)
- @curr_http_version = res.http_version
+ @curr_http_version = res.http_version || HTTPVersion
@last_communicated = nil
- if @socket.closed?
+ socket = @socket or raise IOError, 'HTTP session not yet started'
+ if socket.closed?
debug 'Conn socket closed'
elsif not res.body and @close_on_empty_response
debug 'Conn close'
- @socket.close
+ socket.close
elsif keep_alive?(req, res)
debug 'Conn keep-alive'
@last_communicated = Process.clock_gettime(Process::CLOCK_MONOTONIC)
else
debug 'Conn close'
- @socket.close
+ socket.close
end
end
@@ -2539,7 +2613,7 @@ def keep_alive?(req, res)
def sspi_auth?(res)
return false unless @sspi_enabled
if res.kind_of?(HTTPProxyAuthenticationRequired) and
- proxy? and res["Proxy-Authenticate"].include?("Negotiate")
+ proxy? and res["Proxy-Authenticate"].to_s.include?("Negotiate")
begin
require 'win32/sspi'
true
@@ -2579,9 +2653,9 @@ def addr_port
# Adds a message to debugging output
def debug(msg)
- return unless @debug_output
- @debug_output << msg
- @debug_output << "\n"
+ output = @debug_output or return
+ output << msg
+ output << "\n"
end
alias_method :D, :debug
diff --git a/lib/net/http/generic_request.rb b/lib/net/http/generic_request.rb
index 5b01ea4a..792cef7e 100644
--- a/lib/net/http/generic_request.rb
+++ b/lib/net/http/generic_request.rb
@@ -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
@@ -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
@@ -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
@@ -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
@@ -218,12 +220,12 @@ 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
@@ -231,7 +233,7 @@ def exec(sock, ver, path) #:nodoc: internal use only
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'
@@ -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
@@ -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
@@ -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)
diff --git a/lib/net/http/header.rb b/lib/net/http/header.rb
index 797a3bea..abfa4cd3 100644
--- a/lib/net/http/header.rb
+++ b/lib/net/http/header.rb
@@ -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
@@ -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
@@ -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
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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:
@@ -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:
@@ -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
@@ -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}'"
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
diff --git a/lib/net/http/response.rb b/lib/net/http/response.rb
index bea4346e..c2424860 100644
--- a/lib/net/http/response.rb
+++ b/lib/net/http/response.rb
@@ -159,7 +159,8 @@ def read_status_line(sock)
str = sock.readline
m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)(?:\s+(.*))?\z/in.match(str) or
raise Net::HTTPBadResponse, "wrong status line: #{str.dump}"
- m.captures
+ code = m[2] or raise Net::HTTPBadResponse, "wrong status line: #{str.dump}"
+ [m[1], code, m[3]]
end
def response_class(code)
@@ -169,20 +170,30 @@ def response_class(code)
end
def each_response_header(sock)
- key = value = nil
+ key = nil #: String?
+ value = nil #: String?
while true
line = sock.readuntil("\n", true).sub(/\s+\z/, '')
break if line.empty?
- if line[0] == ?\s or line[0] == ?\t and value
- value << ' ' unless value.empty?
- value << line.strip
+ if (line[0] == ?\s || line[0] == ?\t) && value.is_a?(String)
+ current_value = value
+ current_value << ' ' unless current_value.empty?
+ current_value << line.strip
else
- yield key, value if key
+ if key.is_a?(String) && value.is_a?(String)
+ current_key = key
+ current_value = value
+ yield current_key, current_value
+ end
key, value = line.strip.split(/\s*:\s*/, 2)
raise Net::HTTPBadResponse, 'wrong header line format' if value.nil?
end
end
- yield key, value if key
+ if key.is_a?(String) && value.is_a?(String)
+ current_key = key
+ current_value = value
+ yield current_key, current_value
+ end
end
end
@@ -274,7 +285,9 @@ def code_type #:nodoc:
def error! #:nodoc:
message = @code
- message = "#{message} #{@message.dump}" if @message
+ if detail = @message
+ message = "#{message} #{detail.dump}"
+ end
raise error_type().new(message, self)
end
@@ -369,16 +382,15 @@ def read_body(dest = nil, &block)
@read = true
return if @body.nil?
- case enc = @body_encoding
- when Encoding, false, nil
- # Encoding: force given encoding
- # false/nil: do not force encoding
- else
- # other value: detect encoding from body
- enc = detect_encoding(@body)
+ enc = @body_encoding
+ if enc.nil? || enc == false
+ # nil/false: do not force encoding
+ elsif !enc.is_a?(Encoding)
+ body = @body or return
+ enc = detect_encoding(body)
end
- @body.force_encoding(enc) if enc
+ @body&.force_encoding(enc) if enc
@body
end
@@ -466,10 +478,10 @@ def scanning_meta(str)
require 'strscan'
ss = StringScanner.new(str)
if ss.scan_until(/]*/)
+ name = ss.scan(/[^=\t\n\f\r \/>]*/).to_s
name.downcase!
raise if name.empty?
ss.skip(/[\t\n\f\r ]*/)
@@ -521,18 +539,18 @@ def get_attribute(ss)
case ss.peek(1)
when '"'
ss.getch
- value = ss.scan(/[^"]+/)
+ value = ss.scan(/[^"]+/).to_s
value.downcase!
ss.getch
when "'"
ss.getch
- value = ss.scan(/[^']+/)
+ value = ss.scan(/[^']+/).to_s
value.downcase!
ss.getch
when '>'
value = ''
else
- value = ss.scan(/[^\t\n\f\r >]+/)
+ value = ss.scan(/[^\t\n\f\r >]+/).to_s
value.downcase!
end
[name, value]
@@ -556,16 +574,18 @@ def extracting_encodings_from_meta_elements(value)
# bytes in the range may not be a complete deflate block.
def inflater # :nodoc:
- return yield @socket unless Net::HTTP::HAVE_ZLIB
- return yield @socket unless @decode_content
- return yield @socket if self['content-range']
+ socket = @socket or raise IOError, 'attempt to read body out of block'
+ return yield socket unless Net::HTTP::HAVE_ZLIB
+ return yield socket unless @decode_content
+ return yield socket if self['content-range']
v = self['content-encoding']
case v&.downcase
when 'deflate', 'gzip', 'x-gzip' then
self.delete 'content-encoding'
- inflate_body_io = Inflater.new(@socket)
+ inflate_body_io = Inflater.new(socket)
+ success = false
begin
yield inflate_body_io
@@ -584,9 +604,9 @@ def inflater # :nodoc:
when 'none', 'identity' then
self.delete 'content-encoding'
- yield @socket
+ yield socket
else
- yield @socket
+ yield socket
end
end
@@ -597,19 +617,19 @@ def read_body_0(dest)
return
end
- @socket = inflate_body_io
+ body_io = inflate_body_io
clen = content_length()
if clen
- @socket.read clen, dest, @ignore_eof
+ body_io.read clen, dest, @ignore_eof
return
end
clen = range_length()
if clen
- @socket.read clen, dest
+ body_io.read clen, dest
return
end
- @socket.read_all dest
+ body_io.read_all dest
end
end
@@ -621,9 +641,10 @@ def read_body_0(dest)
# See RFC 2616 section 3.6.1 for definitions
def read_chunked(dest, chunk_data_io) # :nodoc:
+ socket = @socket or raise IOError, 'attempt to read body out of block'
total = 0
while true
- line = @socket.readline
+ line = socket.readline
hexlen = line.slice(/[0-9a-fA-F]+/) or
raise Net::HTTPBadResponse, "wrong chunk size line: #{line}"
len = hexlen.hex
@@ -632,16 +653,17 @@ def read_chunked(dest, chunk_data_io) # :nodoc:
chunk_data_io.read len, dest
ensure
total += len
- @socket.read 2 # \r\n
+ socket.read 2 # \r\n
end
end
- until @socket.readline.empty?
+ until socket.readline.empty?
# none
end
end
def stream_check
- raise IOError, 'attempt to read body out of block' if @socket.nil? || @socket.closed?
+ socket = @socket or raise IOError, 'attempt to read body out of block'
+ raise IOError, 'attempt to read body out of block' if socket.closed?
end
def procdest(dest, block)
@@ -736,4 +758,3 @@ def read_all dest
end
end
-
diff --git a/lib/net/http/status.rb b/lib/net/http/status.rb
index e70b47d9..2e87f770 100644
--- a/lib/net/http/status.rb
+++ b/lib/net/http/status.rb
@@ -11,8 +11,10 @@
puts
puts "Net::HTTP::STATUS_CODES = {"
url = "https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv"
- URI(url).read.each_line do |line|
+ uri = URI(url) #: URI::HTTP
+ uri.read({}).each_line do |line|
code, mes, = line.split(',')
+ next if mes.nil?
next if ['(Unused)', 'Unassigned', 'Description'].include?(mes)
puts " #{code} => '#{mes}',"
end
diff --git a/net-http.gemspec b/net-http.gemspec
index d59d5c3b..faa08596 100644
--- a/net-http.gemspec
+++ b/net-http.gemspec
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- excludes = %W[/.git* /bin /test /test_sig /*file /#{File.basename(__FILE__)}]
+ excludes = %W[/.git* /bin /test /test_sig /sig/*-impl.rbs /*file /#{File.basename(__FILE__)}]
spec.files = IO.popen(%W[git -C #{__dir__} ls-files -z --] + excludes.map {|e| ":^#{e}"}, &:read).split("\x0")
spec.bindir = "exe"
spec.require_paths = ["lib"]
diff --git a/sig/net-http-impl.rbs b/sig/net-http-impl.rbs
new file mode 100644
index 00000000..30ae6f17
--- /dev/null
+++ b/sig/net-http-impl.rbs
@@ -0,0 +1,200 @@
+class URI::Generic
+ def authority: () -> String?
+end
+
+module Win32
+ module SSPI
+ class NegotiateAuth
+ def self.new: () -> NegotiateAuth
+ def get_initial_token: () -> String
+ def complete_authentication: (String authphrase) -> String
+ end
+ end
+end
+
+module Net
+ class HTTPAuthenticationError < StandardError
+ def initialize: (String msg, untyped err) -> void
+ end
+
+ module HTTPHeader
+ @header: Hash[String, Array[String]]
+ @body: String?
+ @body_data: Array[untyped] | Hash[untyped, untyped] | nil
+ @body_stream: untyped
+ @form_option: Hash[Symbol, untyped]
+
+ attr_accessor body: String?
+ end
+
+ class HTTP
+ @address: String
+ @port: Integer
+ @ipaddr: String?
+ @local_host: String?
+ @local_port: Integer?
+ @curr_http_version: String
+ @keep_alive_timeout: Float | Integer
+ @last_communicated: Float?
+ @close_on_empty_response: bool
+ @socket: Net::BufferedIO?
+ @started: bool
+ @open_timeout: Float | Integer
+ @read_timeout: Float | Integer
+ @write_timeout: Float | Integer
+ @continue_timeout: Float | Integer | nil
+ @max_retries: Integer
+ @debug_output: IO?
+ @response_body_encoding: Encoding | false | nil
+ @ignore_eof: bool
+ @tcpsocket_supports_open_timeout: bool?
+ @proxy_from_env: bool
+ @proxy_uri: URI::Generic | false | nil
+ @proxy_address: String?
+ @proxy_port: Integer?
+ @proxy_user: String?
+ @proxy_pass: String?
+ @proxy_use_ssl: bool?
+ @use_ssl: bool
+ @ssl_context: OpenSSL::SSL::SSLContext?
+ @ssl_session: OpenSSL::SSL::Session?
+ @sspi_enabled: bool
+ self.@is_proxy_class: bool
+ self.@proxy_from_env: bool
+ self.@proxy_addr: String?
+ self.@proxy_address: String?
+ self.@proxy_port: Integer?
+ self.@proxy_user: String?
+ self.@proxy_pass: String?
+ self.@proxy_use_ssl: bool?
+
+ TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT: bool
+ IDEMPOTENT_METHODS_: Array[String]
+
+ def initialize: (String address, ?Integer? port) -> void
+ def do_start: () -> void
+ def connect: () -> void
+ def timeouted_connect: (String? conn_addr, Integer? conn_port) -> TCPSocket
+ def on_connect: () -> void
+ def do_finish: () -> void
+ def unescape: (String value) -> String
+ def conn_address: () -> String?
+ def conn_port: () -> Integer?
+ def edit_path: (String path) -> String
+ def send_entity: (String | URI::HTTP path, String data, headers? initheader, untyped dest, singleton(Net::HTTPRequest) type) ?{ (String body_segment) -> void } -> Net::HTTPResponse
+ def transport_request: (Net::HTTPGenericRequest req) ?{ (Net::HTTPResponse response) -> void } -> Net::HTTPResponse
+ def begin_transport: (Net::HTTPGenericRequest req) -> void
+ def end_transport: (Net::HTTPGenericRequest req, Net::HTTPResponse res) -> void
+ def keep_alive?: (Net::HTTPGenericRequest req, Net::HTTPResponse res) -> bool
+ def sspi_auth?: (Net::HTTPResponse res) -> bool
+ def sspi_auth: (Net::HTTPGenericRequest req) -> untyped
+ def addr_port: () -> String
+ def debug: (String msg) -> void
+
+ alias D debug
+ end
+
+ class HTTPSession = HTTP
+
+ module HTTP::ProxyDelta
+ def proxy_address: () -> String?
+ def proxy_port: () -> Integer?
+ def use_ssl?: () -> bool
+ def addr_port: () -> String
+ def conn_address: () -> String?
+ def conn_port: () -> Integer?
+ def edit_path: (String path) -> String
+ end
+
+ class HTTPRequest
+ METHOD: String
+ REQUEST_HAS_BODY: bool
+ RESPONSE_HAS_BODY: bool
+ end
+
+ class HTTPGenericRequest
+ @method: String
+ @request_has_body: bool
+ @response_has_body: bool
+ @uri: URI::Generic?
+ @path: String
+ @decode_content: bool
+ @body: String?
+ @body_stream: untyped
+ @body_data: Array[untyped] | Hash[untyped, untyped] | nil
+
+ def set_body_internal: (String? str) -> void
+ def exec: (Net::BufferedIO sock, String ver, String path) -> void
+ def update_uri: (String address, Integer port, bool ssl) -> void
+ def pretty_print: (untyped q) -> void
+ def send_request_with_body: (Net::BufferedIO sock, String ver, String path, String body) -> void
+ def send_request_with_body_stream: (Net::BufferedIO sock, String ver, String path, untyped body_stream) -> void
+ def send_request_with_body_data: (Net::BufferedIO sock, String ver, String path, untyped params) -> void
+ def encode_multipart_form_data: (untyped out, untyped params, untyped opt) -> void
+ def quote_string: (String str, untyped charset) -> String
+ def flush_buffer: (untyped out, String? buf, bool chunked_p) -> untyped
+ def wait_for_continue: (Net::BufferedIO sock, String ver) -> void
+ def write_header: (Net::BufferedIO sock, String ver, String path) -> Integer
+
+ class Chunker
+ @sock: Net::BufferedIO
+
+ def initialize: (Net::BufferedIO sock) -> void
+ def write: (*_ToS buf) -> Integer
+ def finish: () -> Integer
+ end
+ end
+
+ class HTTPResponse
+ @http_version: String?
+ @code: String
+ @message: String?
+ @body: String?
+ @read: bool
+ @uri: URI::Generic?
+ @decode_content: bool
+ @body_encoding: Encoding | false | nil
+ @ignore_eof: bool
+ @socket: Net::BufferedIO?
+ @body_exist: bool
+
+ HAS_BODY: bool
+ EXCEPTION_TYPE: untyped
+ def self.read_new: (Net::BufferedIO sock) -> Net::HTTPResponse
+ def self.exception_type: () -> untyped
+ def self.read_status_line: (Net::BufferedIO sock) -> [String?, String, String?]
+ def self.response_class: (String code) -> singleton(Net::HTTPResponse)
+ def self.each_response_header: (Net::BufferedIO sock) { (String, String) -> void } -> void
+
+ def initialize: (String? httpv, String code, String? msg) -> void
+ def body_encoding=: (Encoding | String | false | nil value) -> (Encoding | false | nil)
+ def ignore_eof=: (bool value) -> bool
+ def response: () -> self
+ def header: () -> self
+ def read_header: () -> self
+ def reading_body: (Net::BufferedIO sock, bool reqmethodallowbody) { () -> untyped } -> String?
+ def detect_encoding: (String str, ?Encoding? encoding) -> Encoding?
+ def sniff_encoding: (String str, ?Encoding? encoding) -> Encoding?
+ def check_bom: (String str) -> Encoding?
+ def scanning_meta: (String str) -> Encoding?
+ def get_attribute: (untyped ss) -> [String, String]?
+ def extracting_encodings_from_meta_elements: (String value) -> String?
+ def inflater: () { (untyped io) -> untyped } -> untyped
+ def read_body_0: (untyped dest) -> void
+ def read_chunked: (untyped dest, untyped chunk_data_io) -> void
+ def stream_check: () -> void
+ def procdest: (untyped dest, untyped block) -> untyped
+
+ class Inflater
+ @socket: Net::BufferedIO
+ @inflate: Zlib::Inflate
+
+ def initialize: (Net::BufferedIO socket) -> void
+ def finish: () -> void
+ def bytes_inflated: () -> Integer
+ def inflate_adapter: (untyped dest) -> Net::ReadAdapter
+ def read: (Integer clen, untyped dest, ?bool ignore_eof) -> untyped
+ def read_all: (untyped dest) -> untyped
+ end
+ end
+end
diff --git a/sig/net-http.rbs b/sig/net-http.rbs
index b54eb936..14279e8d 100644
--- a/sig/net-http.rbs
+++ b/sig/net-http.rbs
@@ -14,9 +14,8 @@ module Net
#
# * [Hypertext Transfer
# Protocol](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol).
- # * [Technical
- # overview](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Techni
- # cal_overview).
+ # * [Technology](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Tec
+ # hnology).
#
# ## About the Examples
#
@@ -56,7 +55,7 @@ module Net
# ## Strategies
#
# * If you will make only a few GET requests, consider using
- # [OpenURI](rdoc-ref:OpenURI).
+ # [OpenURI](https://docs.ruby-lang.org/en/master/OpenURI.html).
# * If you will make only a few requests of all kinds, consider using the
# various singleton convenience methods in this class. Each of the following
# methods automatically starts and finishes a
@@ -83,9 +82,8 @@ module Net
# * If performance is important, consider using sessions, which lower request
# overhead. This [session](rdoc-ref:Net::HTTP@Sessions) has multiple
# requests for [HTTP
- # methods](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request
- # _methods) and [WebDAV
- # methods](https://en.wikipedia.org/wiki/WebDAV#Implementation):
+ # methods](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Method)
+ # and [WebDAV methods](https://en.wikipedia.org/wiki/WebDAV#Implementation):
#
# Net::HTTP.start(hostname) do |http|
# # Session started automatically before block execution.
@@ -120,9 +118,9 @@ module Net
# scheme, hostname, path, query, and fragment; see [URI
# syntax](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax).
#
- # A Ruby [URI::Generic](rdoc-ref:URI::Generic) object represents an internet
- # URI. It provides, among others, methods `scheme`, `hostname`, `path`, `query`,
- # and `fragment`.
+ # A Ruby [URI::Generic](https://docs.ruby-lang.org/en/master/URI/Generic.html)
+ # object represents an internet URI. It provides, among others, methods
+ # `scheme`, `hostname`, `path`, `query`, and `fragment`.
#
# ### Schemes
#
@@ -212,8 +210,8 @@ module Net
# single request:
#
# * [HTTP
- # methods](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request
- # _methods):
+ # methods](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Method)
+ # :
#
# * #get, #request_get: GET.
# * #head, #request_head: HEAD.
@@ -462,8 +460,8 @@ module Net
# has header 'Content-Range'.
#
# Otherwise decompression (or not) depends on the value of header
- # [Content-Encoding](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#co
- # ntent-encoding-response-header):
+ # [Content-Encoding](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Co
+ # ntent-Encoding_2):
#
# * 'deflate', 'gzip', or 'x-gzip':
# decompresses the body and deletes the header.
@@ -475,7 +473,9 @@ module Net
#
# First, what's elsewhere. Class Net::HTTP:
#
- # * Inherits from [class Object](rdoc-ref:Object@What-27s+Here).
+ # * Inherits from [class
+ # Object](https://docs.ruby-lang.org/en/master/Object.html#class-object-what
+ # s-here).
#
# This is a categorized summary of methods and attributes.
#
@@ -761,7 +761,7 @@ module Net
# -->
# Like Net::HTTP.get, but writes the returned body to $stdout; returns `nil`.
#
- def self.get_print: (URI::Generic uri, ?headers header) -> void
+ def self.get_print: (URI::Generic uri, ?headers? header, ?Integer? port) -> void
| (String host, String path, ?Integer port) -> void
#
+ # Sends a PUT request to the server; returns a Net::HTTPResponse object.
+ #
+ # Argument `url` must be a URL; argument `data` must be a string:
+ #
+ # _uri = uri.dup
+ # _uri.path = '/posts'
+ # data = '{"title": "foo", "body": "bar", "userId": 1}'
+ # headers = {'content-type': 'application/json'}
+ # res = Net::HTTP.put(_uri, data, headers) # => #
+ # puts res.body
+ #
+ # Output:
+ #
+ # {
+ # "title": "foo",
+ # "body": "bar",
+ # "userId": 1,
+ # "id": 101
+ # }
+ #
+ # Related:
+ #
+ # * Net::HTTP::Put: request class for HTTP method `PUT`.
+ # * Net::HTTP#put: convenience method for HTTP method `PUT`.
+ #
+ def self.put: (URI::HTTP url, String data, ?headers? header) -> Net::HTTPResponse
#
+ # Allows to set the default configuration that will be used when creating a new
+ # connection.
+ #
+ # Example:
+ #
+ # Net::HTTP.default_configuration = {
+ # read_timeout: 1,
+ # write_timeout: 1
+ # }
+ # http = Net::HTTP.new(hostname)
+ # http.open_timeout # => 60
+ # http.read_timeout # => 1
+ # http.write_timeout # => 1
+ #
+ def self.default_configuration: () -> Hash[Symbol, untyped]?
+
+ #
+ # Allows to set the default configuration that will be used when creating a new
+ # connection.
+ #
+ # Example:
+ #
+ # Net::HTTP.default_configuration = {
+ # read_timeout: 1,
+ # write_timeout: 1
+ # }
+ # http = Net::HTTP.new(hostname)
+ # http.open_timeout # => 60
+ # http.read_timeout # => 1
+ # http.write_timeout # => 1
+ #
+ def self.default_configuration=: (Hash[Symbol, untyped]?) -> Hash[Symbol, untyped]?
+
+ def self.socket_type: () -> singleton(Net::BufferedIO)
#
# Sets or returns the integer local port used to establish the connection;
# initially `nil`.
#
- attr_accessor local_port: Integer
+ attr_accessor local_port: Integer?
#
# Sets whether to determine the proxy from environment variable
# 'ENV['http_proxy']'; see {Proxy Using
- # [ENV]('http_proxy')}[Net::HTTP@Proxy+Using+-27ENV-5B-27http_proxy-27-5D-27].
+ # [ENV]('http_proxy')}[Net::HTTP@Proxy+Using+ENVHTTPProxy].
#
attr_writer proxy_from_env: untyped
@@ -1141,6 +1209,12 @@ module Net
#
attr_accessor proxy_pass: String?
+ #
+ # Sets whether the proxy uses SSL; see [Proxy
+ # Server](rdoc-ref:Net::HTTP@Proxy+Server).
+ #
+ attr_writer proxy_use_ssl: bool?
+
#
+ # Returns the encoding to use for the response body; see
+ # #response_body_encoding=.
+ #
+ def response_body_encoding: () -> (Encoding | String | false | nil)
+
+ #
+ # Sets the encoding to be used for the response body; returns the encoding.
+ #
+ # The given `value` may be:
+ #
+ # * An Encoding object.
+ # * The name of an encoding.
+ # * An alias for an encoding name.
+ #
+ # See [Encoding](https://docs.ruby-lang.org/en/master/Encoding.html).
+ #
+ # Examples:
+ #
+ # http = Net::HTTP.new(hostname)
+ # http.response_body_encoding = Encoding::US_ASCII # => #
+ # http.response_body_encoding = 'US-ASCII' # => "US-ASCII"
+ # http.response_body_encoding = 'ASCII' # => "ASCII"
+ #
+ def response_body_encoding=: (Encoding | String | false | nil) -> (Encoding | String | false | nil)
+
#
# Sets or returns the numeric (Integer or Float) number of seconds to keep the
# connection open after a request is sent; initially 2. If a new request is made
@@ -1487,7 +1590,7 @@ module Net
# This class is obsolete. You may pass these same parameters directly to
# Net::HTTP.new. See Net::HTTP.new for details of the arguments.
#
- def self.Proxy: (?interned p_addr, ?Integer? p_port, ?String? p_user, ?String? p_pass) -> untyped
+ def self.Proxy: (?interned p_addr, ?Integer? p_port, ?String? p_user, ?String? p_pass, ?bool? p_use_ssl) -> untyped
#
@@ -2052,7 +2155,7 @@ module Net
# - new(m, reqbody, resbody, uri_or_path, initheader = nil)
# -->
#
- def initialize: (String m, boolish reqbody, boolish resbody, URI::Generic | String uri_or_path, ?headers initheader) -> void
+ def initialize: (String m, boolish reqbody, boolish resbody, URI::HTTP | String uri_or_path, ?headers? initheader) -> void
#
# Returns the string method name for the request:
@@ -2077,7 +2180,7 @@ module Net
# # => #
# Net::HTTP::Get.new('example.com').uri # => nil
#
- attr_reader uri: URI::Generic
+ attr_reader uri: URI::Generic?
#
# Returns `false` if the request's header 'Accept-Encoding' has
@@ -2406,12 +2509,22 @@ module Net
# * #each_value: Passes each string field value to the block.
#
module HTTPHeader : BasicObject
+ #
+ # The maximum length of HTTP header keys.
+ #
+ MAX_KEY_LENGTH: Integer
+
+ #
+ # The maximum length of HTTP header values.
+ #
+ MAX_FIELD_LENGTH: Integer
+
#
#
- def initialize_http_header: (Hash[untyped, untyped] initheader) -> void
+ def initialize_http_header: (Hash[untyped, untyped]? initheader) -> void
def size: () -> Integer
@@ -2533,9 +2646,8 @@ module Net
# res.fetch('Nosuch', 'Foo') # => "Foo"
# res.fetch('Nosuch') # Raises KeyError.
#
- def fetch: (interned key) -> String
- | (interned key, untyped) -> untyped
- | (interned key) { (String) -> untyped } -> untyped
+ def fetch: (interned key, *untyped args) -> untyped
+ | (interned key, *untyped args) { (String) -> untyped } -> untyped
#
#
- def capitalize: (interned name) -> String
+ def capitalize: (String | Symbol name) -> String
public
@@ -2770,7 +2882,7 @@ module Net
#
# Net::HTTPHeader#range= is an alias for Net::HTTPHeader#set_range.
#
- def set_range: (Range[Integer] | Numeric r, ?Integer? e) -> Range[Integer]
+ def set_range: (Range[Integer] | Numeric? r, ?Integer? e) -> (Range[Integer] | Numeric | nil)
#
@@ -3278,12 +3391,9 @@ module Net
#
# * Request body: optional.
# * Response body: yes.
- # * [Safe](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_meth
- # ods): yes.
- # * [Idempotent](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Ide
- # mpotent_methods): yes.
- # * [Cacheable](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cach
- # eable_methods): yes.
+ # * [Safe](https://en.wikipedia.org/wiki/HTTP#Safe_method): yes.
+ # * [Idempotent](https://en.wikipedia.org/wiki/HTTP#Idempotent_method): yes.
+ # * [Cacheable](https://en.wikipedia.org/wiki/HTTP#Cacheable_method): yes.
#
# Related:
#
@@ -3317,12 +3427,9 @@ module Net
#
# * Request body: optional.
# * Response body: no.
- # * [Safe](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_meth
- # ods): yes.
- # * [Idempotent](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Ide
- # mpotent_methods): yes.
- # * [Cacheable](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cach
- # eable_methods): yes.
+ # * [Safe](https://en.wikipedia.org/wiki/HTTP#Safe_method): yes.
+ # * [Idempotent](https://en.wikipedia.org/wiki/HTTP#Idempotent_method): yes.
+ # * [Cacheable](https://en.wikipedia.org/wiki/HTTP#Cacheable_method): yes.
#
# Related:
#
@@ -3358,12 +3465,9 @@ module Net
#
# * Request body: yes.
# * Response body: yes.
- # * [Safe](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_meth
- # ods): no.
- # * [Idempotent](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Ide
- # mpotent_methods): no.
- # * [Cacheable](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cach
- # eable_methods): yes.
+ # * [Safe](https://en.wikipedia.org/wiki/HTTP#Safe_method): no.
+ # * [Idempotent](https://en.wikipedia.org/wiki/HTTP#Idempotent_method): no.
+ # * [Cacheable](https://en.wikipedia.org/wiki/HTTP#Cacheable_method): yes.
#
# Related:
#
@@ -3400,12 +3504,9 @@ module Net
#
# * Request body: yes.
# * Response body: yes.
- # * [Safe](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_meth
- # ods): no.
- # * [Idempotent](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Ide
- # mpotent_methods): yes.
- # * [Cacheable](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cach
- # eable_methods): no.
+ # * [Safe](https://en.wikipedia.org/wiki/HTTP#Safe_method): no.
+ # * [Idempotent](https://en.wikipedia.org/wiki/HTTP#Idempotent_method): yes.
+ # * [Cacheable](https://en.wikipedia.org/wiki/HTTP#Cacheable_method): no.
#
# Related:
#
@@ -3440,12 +3541,9 @@ module Net
#
# * Request body: optional.
# * Response body: yes.
- # * [Safe](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_meth
- # ods): no.
- # * [Idempotent](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Ide
- # mpotent_methods): yes.
- # * [Cacheable](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cach
- # eable_methods): no.
+ # * [Safe](https://en.wikipedia.org/wiki/HTTP#Safe_method): no.
+ # * [Idempotent](https://en.wikipedia.org/wiki/HTTP#Idempotent_method): yes.
+ # * [Cacheable](https://en.wikipedia.org/wiki/HTTP#Cacheable_method): no.
#
# Related:
#
@@ -3478,12 +3576,9 @@ module Net
#
# * Request body: optional.
# * Response body: yes.
- # * [Safe](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_meth
- # ods): yes.
- # * [Idempotent](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Ide
- # mpotent_methods): yes.
- # * [Cacheable](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cach
- # eable_methods): no.
+ # * [Safe](https://en.wikipedia.org/wiki/HTTP#Safe_method): yes.
+ # * [Idempotent](https://en.wikipedia.org/wiki/HTTP#Idempotent_method): yes.
+ # * [Cacheable](https://en.wikipedia.org/wiki/HTTP#Cacheable_method): no.
#
# Related:
#
@@ -3516,12 +3611,9 @@ module Net
#
# * Request body: no.
# * Response body: yes.
- # * [Safe](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_meth
- # ods): yes.
- # * [Idempotent](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Ide
- # mpotent_methods): yes.
- # * [Cacheable](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cach
- # eable_methods): no.
+ # * [Safe](https://en.wikipedia.org/wiki/HTTP#Safe_method): yes.
+ # * [Idempotent](https://en.wikipedia.org/wiki/HTTP#Idempotent_method): yes.
+ # * [Cacheable](https://en.wikipedia.org/wiki/HTTP#Cacheable_method): no.
#
# Related:
#
@@ -3557,12 +3649,9 @@ module Net
#
# * Request body: yes.
# * Response body: yes.
- # * [Safe](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_meth
- # ods): no.
- # * [Idempotent](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Ide
- # mpotent_methods): no.
- # * [Cacheable](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cach
- # eable_methods): no.
+ # * [Safe](https://en.wikipedia.org/wiki/HTTP#Safe_method): no.
+ # * [Idempotent](https://en.wikipedia.org/wiki/HTTP#Idempotent_method): no.
+ # * [Cacheable](https://en.wikipedia.org/wiki/HTTP#Cacheable_method): no.
#
# Related:
#
@@ -3936,7 +4025,7 @@ module Net
#
# The HTTP version supported by the server.
#
- attr_reader http_version: String
+ attr_reader http_version: String?
#
# The HTTP result code string. For example, '302'. You can also determine the
@@ -3948,7 +4037,7 @@ module Net
#
# The HTTP result message sent by the server. For example, 'Not Found'.
#
- attr_reader message: String
+ attr_reader message: String?
#
# The HTTP result message sent by the server. For example, 'Not Found'.
@@ -3978,7 +4067,7 @@ module Net
def error!: () -> untyped
- def error_type: () -> (Net::HTTPError | Net::HTTPServerException | Net::HTTPRetriableError | Net::HTTPFatalError)
+ def error_type: () -> (singleton(Net::HTTPError) | singleton(Net::HTTPClientException) | singleton(Net::HTTPRetriableError) | singleton(Net::HTTPFatalError))
#
@@ -4091,7 +4180,7 @@ module Net
class HTTPInformation < HTTPResponse
HAS_BODY: bool
- EXCEPTION_TYPE: Net::HTTPError
+ EXCEPTION_TYPE: singleton(Net::HTTPError)
end
#
@@ -4109,7 +4198,7 @@ module Net
class HTTPSuccess < HTTPResponse
HAS_BODY: bool
- EXCEPTION_TYPE: Net::HTTPError
+ EXCEPTION_TYPE: singleton(Net::HTTPError)
end
#
@@ -4127,7 +4216,7 @@ module Net
class HTTPRedirection < HTTPResponse
HAS_BODY: bool
- EXCEPTION_TYPE: Net::HTTPRetriableError
+ EXCEPTION_TYPE: singleton(Net::HTTPRetriableError)
end
#
@@ -4144,7 +4233,7 @@ module Net
class HTTPClientError < HTTPResponse
HAS_BODY: bool
- EXCEPTION_TYPE: untyped
+ EXCEPTION_TYPE: singleton(Net::HTTPClientException)
end
#
@@ -4161,7 +4250,7 @@ module Net
class HTTPServerError < HTTPResponse
HAS_BODY: bool
- EXCEPTION_TYPE: Net::HTTPFatalError
+ EXCEPTION_TYPE: singleton(Net::HTTPFatalError)
end
#
@@ -4483,7 +4572,7 @@ module Net
# s).
# * [Wikipedia](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#300).
#
- HTTPMultipleChoice: HTTPMultipleChoices
+ class HTTPMultipleChoice = HTTPMultipleChoices
#
# Response class for `Moved Permanently` responses (status code 301).
@@ -5549,6 +5638,20 @@ module Net
HTTP::STATUS_CODES: Hash[Integer, String]
+ class HTTPMovedTemporarily = HTTPFound
+
+ class HTTPRequestTimeOut = HTTPRequestTimeout
+
+ class HTTPRequestEntityTooLarge = HTTPPayloadTooLarge
+
+ class HTTPRequestURITooLong = HTTPURITooLong
+
+ class HTTPRequestURITooLarge = HTTPRequestURITooLong
+
+ class HTTPRequestedRangeNotSatisfiable = HTTPRangeNotSatisfiable
+
+ class HTTPGatewayTimeOut = HTTPGatewayTimeout
+
#
# Net::HTTP exception class. You cannot use Net::HTTPExceptions directly;
# instead, you must use its subclasses.
@@ -5569,11 +5672,13 @@ module Net
include Net::HTTPExceptions
end
- class HTTPServerException < ProtoServerError
+ class HTTPClientException < ProtoServerError
# We cannot use the name "HTTPServerError", it is the name of the response.
include Net::HTTPExceptions
end
+ class HTTPServerException = HTTPClientException
+
class HTTPFatalError < ProtoFatalError
include Net::HTTPExceptions
end
diff --git a/sig/net-protocol-impl.rbs b/sig/net-protocol-impl.rbs
new file mode 100644
index 00000000..5bdb4081
--- /dev/null
+++ b/sig/net-protocol-impl.rbs
@@ -0,0 +1,94 @@
+module Net
+ class Protocol
+ private
+
+ def ssl_socket_connect: (untyped socket, Time::_Timeout? timeout) -> void
+ end
+
+ class ProtocolError < StandardError
+ end
+
+ class ProtoSyntaxError < ProtocolError
+ end
+
+ class ProtoFatalError < ProtocolError
+ end
+
+ class ProtoUnknownError < ProtocolError
+ end
+
+ class ProtoServerError < ProtocolError
+ end
+
+ class ProtoAuthError < ProtocolError
+ end
+
+ class ProtoCommandError < ProtocolError
+ end
+
+ class ProtoRetriableError < ProtocolError
+ end
+
+ class OpenTimeout < Timeout::Error
+ end
+
+ class ReadTimeout < Timeout::Error
+ attr_reader io: IO?
+
+ def initialize: (?IO? io) -> void
+ def message: () -> String
+ end
+
+ class WriteTimeout < Timeout::Error
+ attr_reader io: IO?
+
+ def initialize: (?IO? io) -> void
+ def message: () -> String
+ end
+
+ class BufferedIO
+ def initialize: (
+ untyped io,
+ ?read_timeout: Time::_Timeout,
+ ?write_timeout: Time::_Timeout,
+ ?continue_timeout: Time::_Timeout?,
+ ?debug_output: IO?
+ ) -> void
+
+ attr_reader io: untyped
+ attr_accessor read_timeout: Time::_Timeout
+ attr_accessor write_timeout: Time::_Timeout
+ attr_accessor continue_timeout: Time::_Timeout?
+ attr_accessor debug_output: IO?
+
+ def inspect: () -> String
+ def eof?: () -> bool
+ def closed?: () -> bool
+ def close: () -> untyped
+ def read: (Integer len, ?untyped dest, ?bool ignore_eof) -> untyped
+ def read_all: (?untyped dest) -> untyped
+ def readuntil: (String terminator, ?bool ignore_eof) -> String
+ def readline: () -> String
+ def write: (*_ToS strs) -> Integer
+ def <<: (*_ToS strs) -> Integer
+ def writeline: (String str) -> Integer
+ end
+
+ class ReadAdapter
+ def initialize: (Proc block) -> void
+ def inspect: () -> String
+ def <<: (String str) -> untyped
+ end
+
+end
+
+class TCPSocket
+ def self.new: (
+ String remote_host,
+ Integer remote_port,
+ ?String? local_host,
+ ?Integer? local_port,
+ ?fast_fallback: boolish,
+ ?open_timeout: Time::_Timeout
+ ) -> instance
+end