module Gem::Net::HTTPHeader

def [](key)

see {Getters}[rdoc-ref:Gem::Net::HTTPHeader@Getters].
Note that some field values may be retrieved via convenience methods;

res['Nosuch'] # => nil
res['Connection'] # => "keep-alive"
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
or +nil+ if there is no such key;
Returns the string field value for the case-insensitive field +key+,
def [](key)
  a = @header[key.downcase.to_s] or return nil
  a.join(', ')
end

def []=(key, val)

see {Setters}[rdoc-ref:Gem::Net::HTTPHeader@Setters].
Note that some field values may be set via convenience methods;

req['Accept'] # => "text/html"
req['Accept'] = 'text/html'
req['Accept'] # => "*/*"
req = Gem::Net::HTTP::Get.new(uri)

see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
overwriting the previous value if the field exists;
Sets the value for the case-insensitive +key+ to +val+,
def []=(key, val)
  unless val
    @header.delete key.downcase.to_s
    return val
  end
  set_field(key, val)
end

def add_field(key, val)


req.get_fields('Foo') # => ["bar", "baz", "baz", "bam"]
req['Foo'] # => "bar, baz, baz, bam"
req.add_field('Foo', %w[baz bam])
req['Foo'] # => "bar, baz"
req.add_field('Foo', 'baz')
req['Foo'] # => "bar"
req.add_field('Foo', 'bar')
req = Gem::Net::HTTP::Get.new(uri)

see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
creates the field with the given +key+ and +val+ if it does not exist.
Adds value +val+ to the value array for field +key+ if the field exists;
def add_field(key, val)
  stringified_downcased_key = key.downcase.to_s
  if @header.key?(stringified_downcased_key)
    append_field_value(@header[stringified_downcased_key], val)
  else
    set_field(key, val)
  end
end

def append_field_value(ary, val)

def append_field_value(ary, val)
al
numerable
each{|x| append_field_value(ary, x)}
= val.to_s
[\r\n]/n.match?(val.b)
ise ArgumentError, 'header field value cannot include CR/LF'
push val

def basic_auth(account, password)


# => "Basic bXlfYWNjb3VudDpteV9wYXNzd29yZA=="
req['Authorization']
req.basic_auth('my_account', 'my_password')

+account+ and +password+ strings:
Sets header 'Authorization' using the given
def basic_auth(account, password)
  @header['authorization'] = [basic_encode(account, password)]
end

def basic_encode(account, password)

def basic_encode(account, password)
  'Basic ' + ["#{account}:#{password}"].pack('m0')
end

def capitalize(name)

def capitalize(name)
  name.to_s.split('-'.freeze).map {|s| s.capitalize }.join('-'.freeze)
end

def chunked?


res.chunked? # => true
res['Transfer-Encoding'] # => "chunked"
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

see {Transfer-Encoding response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#transfer-encoding-response-header]:
+false+ otherwise;
exists and has value 'chunked',
Returns +true+ if field 'Transfer-Encoding'
def chunked?
  return false unless @header['transfer-encoding']
  field = self['Transfer-Encoding']
  (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
end

def connection_close?

Returns whether the HTTP session is to be closed.
def connection_close?
  token = /(?:\A|,)\s*close\s*(?:\z|,)/i
  @header['connection']&.grep(token) {return true}
  @header['proxy-connection']&.grep(token) {return true}
  false
end

def connection_keep_alive?

Returns whether the HTTP session is to be kept alive.
def connection_keep_alive?
  token = /(?:\A|,)\s*keep-alive\s*(?:\z|,)/i
  @header['connection']&.grep(token) {return true}
  @header['proxy-connection']&.grep(token) {return true}
  false
end

def content_length


res.content_length # => nil
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
res.content_length # => 2
res = Gem::Net::HTTP.get_response(hostname, '/nosuch/1')

see {Content-Length request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-length-request-header]:
or +nil+ if there is no such field;
Returns the value of field 'Content-Length' as an integer,
def content_length
  return nil unless key?('Content-Length')
  len = self['Content-Length'].slice(/\d+/) or
      raise Gem::Net::HTTPHeaderSyntaxError, 'wrong Content-Length format'
  len.to_i
end

def content_length=(len)


end # => #
http.request(req)
res = Gem::Net::HTTP.start(hostname) do |http|
req.content_type = 'application/json'
req.content_length = req.body.size # => 42
req.body = '{"title": "foo","body": "bar","userId": 1}'
req = Gem::Net::HTTP::Post.new(_uri) # => #
_uri.path = '/posts' # => "/posts"
hostname = _uri.hostname # => "jsonplaceholder.typicode.com"
_uri = uri.dup

see {Content-Length response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-length-response-header]:
Sets the value of field 'Content-Length' to the given numeric;
def content_length=(len)
  unless len
    @header.delete 'content-length'
    return nil
  end
  @header['content-length'] = [len.to_i.to_s]
end

def content_range


res.content_range # => 0..499
res['Content-Range'] # => "bytes 0-499/1000"
res['Content-Range'] = 'bytes 0-499/1000'
res['Content-Range'] # => nil
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

see {Content-Range response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-range-response-header]:
'Content-Range', or +nil+ if no such field exists;
Returns a Range object representing the value of field
def content_range
  return nil unless @header['content-range']
  m = %r<\A\s*(\w+)\s+(\d+)-(\d+)/(\d+|\*)>.match(self['Content-Range']) or
      raise Gem::Net::HTTPHeaderSyntaxError, 'wrong Content-Range format'
  return unless m[1] == 'bytes'
  m[2].to_i .. m[3].to_i
end

def content_type


res.content_type # => "application/json"
res['content-type'] # => "application/json; charset=utf-8"
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
or +nil+ if no such field exists;
from the value of field 'Content-Type',
Returns the {media type}[https://en.wikipedia.org/wiki/Media_type]
def content_type
  main = main_type()
  return nil unless main
  sub = sub_type()
  if sub
    "#{main}/#{sub}"
  else
    main
  end
end

def delete(key)


req.delete('Nosuch') # => nil
req.delete('Accept') # => ["*/*"]
req = Gem::Net::HTTP::Get.new(uri)

returns the deleted value, or +nil+ if no such field exists:
(see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]);
Removes the header for the given case-insensitive +key+
def delete(key)
  @header.delete(key.downcase.to_s)
end

def each_capitalized

Gem::Net::HTTPHeader#canonical_each is an alias for Gem::Net::HTTPHeader#each_capitalized.

Like #each_header, but the keys are returned in capitalized form.
def each_capitalized
  block_given? or return enum_for(__method__) { @header.size }
  @header.each do |k,v|
    yield capitalize(k), v.join(', ')
  end
end

def each_capitalized_name #:yield: +key+

:yield: +key+
Returns an enumerator if no block is given.

see {Case Mapping}[https://docs.ruby-lang.org/en/master/case_mapping_rdoc.html].
The capitalization is system-dependent;

"Cf-Ray"
"Cf-Cache-Status"
"Cache-Control"
"Connection"
"Content-Type"

Output:

end
p key if key.start_with?('C')
res.each_capitalized_name do |key|
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

Calls the block with each capitalized field name:
def each_capitalized_name  #:yield: +key+
  block_given? or return enum_for(__method__) { @header.size }
  @header.each_key do |k|
    yield capitalize(k)
  end
end

def each_header #:yield: +key+, +value+

:yield: +key+, +value+
Gem::Net::HTTPHeader#each is an alias for Gem::Net::HTTPHeader#each_header.

Returns an enumerator if no block is given.

["cf-ray", "771d17e9bc542cf5-ORD"]
["cf-cache-status", "HIT"]
["cache-control", "max-age=43200"]
["connection", "keep-alive"]
["content-type", "application/json; charset=utf-8"]

Output:

end
p [key, value] if key.start_with?('c')
res.each_header do |key, value|
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

Calls the block with each key/value pair:
def each_header   #:yield: +key+, +value+
  block_given? or return enum_for(__method__) { @header.size }
  @header.each do |k,va|
    yield k, va.join(', ')
  end
end

def each_name(&block) #:yield: +key+

:yield: +key+
Gem::Net::HTTPHeader#each_name is an alias for Gem::Net::HTTPHeader#each_key.

Returns an enumerator if no block is given.

"cf-ray"
"cf-cache-status"
"cache-control"
"connection"
"content-type"

Output:

end
p key if key.start_with?('c')
res.each_key do |key|
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

Calls the block with each field key:
def each_name(&block)   #:yield: +key+
  block_given? or return enum_for(__method__) { @header.size }
  @header.each_key(&block)
end

def each_value #:yield: +value+

:yield: +value+
Returns an enumerator if no block is given.

"cloudflare"
"cf-q-config;dur=6.0000002122251e-06"
"chunked"

Output:

end
p value if value.start_with?('c')
res.each_value do |value|
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

Calls the block with each string field value:
def each_value   #:yield: +value+
  block_given? or return enum_for(__method__) { @header.size }
  @header.each_value do |va|
    yield va.join(', ')
  end
end

def fetch(key, *args, &block) #:yield: +key+

:yield: +key+

res.fetch('Nosuch') # Raises KeyError.
res.fetch('Nosuch', 'Foo') # => "Foo"
res.fetch('Connection', 'Foo') # => "keep-alive"

otherwise raises an exception:
otherwise, returns +default_val+ if it was given;
With no block, returns the string value for +key+ if it exists;

end # => "nosuch"
value.downcase
res.fetch('Nosuch') do |value|
# Field does not exist; block called.

end # => "keep-alive"
fail 'Cannot happen'
res.fetch('Connection') do |value|
# Field exists; block not called.

res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
ignores the +default_val+;
otherwise returns the value of the block;
With a block, returns the string value for +key+ if it exists;

fetch(key, default_val = nil) -> value or default_val
fetch(key, default_val = nil) {|key| ... } -> object
call-seq:
def fetch(key, *args, &block)   #:yield: +key+
  a = @header.fetch(key.downcase.to_s, *args, &block)
  a.kind_of?(Array) ? a.join(', ') : a
end

def get_fields(key)


res.get_fields('Nosuch') # => nil
res.get_fields('Connection') # => ["keep-alive"]
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
or +nil+ if there is no such field;
Returns the array field value for the given +key+,
def get_fields(key)
  stringified_downcased_key = key.downcase.to_s
  return nil unless @header[stringified_downcased_key]
  @header[stringified_downcased_key].dup
end

def initialize_http_header(initheader) #:nodoc:

:nodoc:
def initialize_http_header(initheader) #:nodoc:
  @header = {}
  return unless initheader
  initheader.each do |key, value|
    warn "net/http: duplicated HTTP header: #{key}", uplevel: 3 if key?(key) and $VERBOSE
    if value.nil?
      warn "net/http: nil HTTP header: #{key}", uplevel: 3 if $VERBOSE
    else
      value = value.strip # raise error for invalid byte sequences
      if key.to_s.bytesize > MAX_KEY_LENGTH
        raise ArgumentError, "too long (#{key.bytesize} bytes) header: #{key[0, 30].inspect}..."
      end
      if value.to_s.bytesize > MAX_FIELD_LENGTH
        raise ArgumentError, "header #{key} has too long field value: #{value.bytesize}"
      end
      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]
    end
  end
end

def key?(key)


req.key?('Nosuch') # => false
req.key?('Accept') # => true
req = Gem::Net::HTTP::Get.new(uri)

Returns +true+ if the field for the case-insensitive +key+ exists, +false+ otherwise:
def key?(key)
  @header.key?(key.downcase.to_s)
end

def main_type


res.main_type # => "application"
res['content-type'] # => "application/json; charset=utf-8"
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
or +nil+ if no such field exists;
from the value of field 'Content-Type',
{media type}[https://en.wikipedia.org/wiki/Media_type]
Returns the leading ('type') part of the
def main_type
  return nil unless @header['content-type']
  self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip
end

def proxy_basic_auth(account, password)


# => "Basic bXlfYWNjb3VudDpteV9wYXNzd29yZA=="
req['Proxy-Authorization']
req.proxy_basic_auth('my_account', 'my_password')

+account+ and +password+ strings:
Sets header 'Proxy-Authorization' using the given
def proxy_basic_auth(account, password)
  @header['proxy-authorization'] = [basic_encode(account, password)]
end

def range


req.range # # => nil
req.delete('Range')
req.range # => [0..99, 200..299, 400..499]
req['Range'] = 'bytes=0-99,200-299,400-499'
req = Gem::Net::HTTP::Get.new(uri)

see {Range request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#range-request-header]:
or +nil+ if there is no such field;
the value of field 'Range',
Returns an array of Range objects that represent
def range
  return nil unless @header['range']
  value = self['Range']
  # byte-range-set = *( "," OWS ) ( byte-range-spec / suffix-byte-range-spec )
  #   *( OWS "," [ OWS ( byte-range-spec / suffix-byte-range-spec ) ] )
  # corrected collected ABNF
  # http://tools.ietf.org/html/draft-ietf-httpbis-p5-range-19#section-5.4.1
  # http://tools.ietf.org/html/draft-ietf-httpbis-p5-range-19#appendix-C
  # http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-19#section-3.2.5
  unless /\Abytes=((?:,[ \t]*)*(?:\d+-\d*|-\d+)(?:[ \t]*,(?:[ \t]*\d+-\d*|-\d+)?)*)\z/ =~ value
    raise Gem::Net::HTTPHeaderSyntaxError, "invalid syntax for byte-ranges-specifier: '#{value}'"
  end
  byte_range_set = $1
  result = byte_range_set.split(/,/).map {|spec|
    m = /(\d+)?\s*-\s*(\d+)?/i.match(spec) or
            raise Gem::Net::HTTPHeaderSyntaxError, "invalid byte-range-spec: '#{spec}'"
    d1 = m[1].to_i
    d2 = m[2].to_i
    if m[1] and m[2]
      if d1 > d2
        raise Gem::Net::HTTPHeaderSyntaxError, "last-byte-pos MUST greater than or equal to first-byte-pos but '#{spec}'"
      end
      d1..d2
    elsif m[1]
      d1..-1
    elsif m[2]
      -d2..-1
    else
      raise Gem::Net::HTTPHeaderSyntaxError, 'range is not specified'
    end
  }
  # if result.empty?
  # byte-range-set must include at least one byte-range-spec or suffix-byte-range-spec
  # but above regexp already denies it.
  if result.size == 1 && result[0].begin == 0 && result[0].end == -1
    raise Gem::Net::HTTPHeaderSyntaxError, 'only one suffix-byte-range-spec with zero suffix-length'
  end
  result
end

def range_length


res.range_length # => 500
res['Content-Range'] = 'bytes 0-499/1000'
res['Content-Range'] # => nil
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

see {Content-Range response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-range-response-header]:
'Content-Range', or +nil+ if no such field exists;
Returns the integer representing length of the value of field
def range_length
  r = content_range() or return nil
  r.end - r.begin + 1
end

def set_content_type(type, params = {})

Gem::Net::HTTPHeader#content_type= is an alias for Gem::Net::HTTPHeader#set_content_type.

req.set_content_type('application/json') # => ["application/json"]
req = Gem::Net::HTTP::Get.new(uri)

see {Content-Type request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-request-header]:
returns the new value;
Sets the value of field 'Content-Type';
def set_content_type(type, params = {})
  @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
end

def set_field(key, val)

def set_field(key, val)
al
numerable
= []
nd_field_value(ary, val)
der[key.downcase.to_s] = ary
= val.to_s # for compatibility use to_s instead of to_str
al.b.count("\r\n") > 0
ise ArgumentError, 'header field value cannot include CR/LF'
der[key.downcase.to_s] = [val]

def set_form(params, enctype='application/x-www-form-urlencoded', formopt={})


Field names and values of non-file fields should be encoded with this charset.
- +:charset+: Value is the character set for the form submission.
See {Boundary}[https://www.rfc-editor.org/rfc/rfc7578#section-4.1].
If not given, the boundary is a random string.
- +:boundary+: The value is the boundary string for the multipart message.

that may include the following entries:
is 'multipart/form-data')
(applicable only when argument +enctype+
Optional argument +formopt+ is a hash of options

see {RFC 7578}[https://www.rfc-editor.org/rfc/rfc7578].
- 'multipart/form-data';
- 'application/x-www-form-urlencoded' (the default).

to field 'Content-Type', and must be one of:
Optional argument +enctype+ specifies the value to be given

req.set_form({'foo' => nil, 'bar' => 1, 'file' => file})
# Mixture of fields.

req.set_form({'file' => StringIO.new('Ruby is cool.')})
require 'stringio'
# IO-valued field.

req.set_form({'foo' => 0, 'bar' => 1, 'baz' => 2})
# String-valued fields.

req.set_form({'foo' => nil, 'bar' => nil, 'baz' => nil})
# Nil-valued fields.

Examples:

'multipart/form-data').
(only when argument +enctype+ -- see below -- is given as
- An IO stream opened for reading
- Another string.
- +nil+.

- The value may be:
- The name is a string.

each of its entries is a name/value pair that defines a field:
When +params+ is a hash,

Argument +params+ As a Hash

req.set_form(['foo', %w[bar 1], ['file', file]])

The various forms may be mixed:

req.set_form([['file', file, {filename: "other-filename.foo"}]]

Example:

- +:content_type+: The content type of the uploaded file.
- +:filename+: The name of the file to use.

and an options hash, which may contain these entries:
- A string name, an IO stream opened for reading,

req.set_form([['file', StringIO.new('Ruby is cool.')]])
require 'stringio'

- A string name and an IO stream opened for reading:

'multipart/form-data':
- When argument +enctype+ (see below) is given as

req.set_form([%w[foo 0], %w[bar 1], %w[baz 2]])

- Two strings:

req.set_form([['foo'], ['bar'], ['baz']])

- One string:

the subarray may contain:
each of its elements is a subarray that defines a field;
When +params+ is an array,

Argument +params+ As an Array

req = Gem::Net::HTTP::Post.new(_uri)
_uri.path ='/posts'
_uri = uri.dup

First, we set up a request:

and is often an array or hash.
(method params.map will be called),
{Enumerable}[https://docs.ruby-lang.org/en/master/Enumerable.html#module-Enumerable-label-Enumerable+in+Ruby+Classes]
Argument +params+ should be an

- An IO stream opened for reading.
- A name/value pair.
- A scalar value.

each field is:
The form data given in +params+ consists of zero or more fields;

Stores form data to be used in a +POST+ or +PUT+ request.
def set_form(params, enctype='application/x-www-form-urlencoded', formopt={})
  @body_data = params
  @body = nil
  @body_stream = nil
  @form_option = formopt
  case enctype
  when /\Aapplication\/x-www-form-urlencoded\z/i,
    /\Amultipart\/form-data\z/i
    self.content_type = enctype
  else
    raise ArgumentError, "invalid enctype: #{enctype}"
  end
end

def set_form_data(params, sep = '&')

Gem::Net::HTTPHeader#form_data= is an alias for Gem::Net::HTTPHeader#set_form_data.

req.body # => "q=ruby|lang=en"
req.set_form_data({q: 'ruby', lang: 'en'}, '|')

uses that string as the separator:
With string argument +sep+ also given,

req.body # => "q=ruby&q=perl&lang=en"
req.set_form_data([['q', 'ruby'], ['q', 'perl'], ['lang', 'en']])

req.body # => "q=ruby&q=perl&lang=en"
req.set_form_data(q: ['ruby', 'perl'], lang: 'en')

req.body # => "q=ruby&lang=en"
req.set_form_data([['q', 'ruby'], ['lang', 'en']])

req['Content-Type'] # => "application/x-www-form-urlencoded"
req.body # => "q=ruby&lang=en"
req.set_form_data(q: 'ruby', lang: 'en')

req = Gem::Net::HTTP::Post.new('example.com')

sets the body to a URL-encoded string with the default separator '&':
With only argument +params+ given,

{Gem::URI.encode_www_form}[https://docs.ruby-lang.org/en/master/Gem::URI.html#method-c-encode_www_form].
Argument +params+ must be suitable for use as argument +enum+ to

The resulting request is suitable for HTTP request +POST+ or +PUT+.

to 'application/x-www-form-urlencoded'.
and sets request header field 'Content-Type'
Sets the request body to a URL-encoded string derived from argument +params+,
def set_form_data(params, sep = '&')
  query = Gem::URI.encode_www_form(params)
  query.gsub!(/&/, sep) if sep != '&'
  self.body = query
  self.content_type = 'application/x-www-form-urlencoded'
end

def set_range(r, e = nil)

Gem::Net::HTTPHeader#range= is an alias for Gem::Net::HTTPHeader#set_range.

req['Range'] # => "bytes=100-199"
req.set_range(100..199) # => 100..199

With argument +range+:

req['Range'] # => "bytes=100-199"
req.set_range(100, 100) # => 100...200

With arguments +offset+ and +length+:

req['Range'] # => "bytes=0-99"
req.set_range(100) # => 100
req = Gem::Net::HTTP::Get.new(uri)

With argument +length+:

see {Range request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#range-request-header]:
Sets the value for field 'Range';

set_range(begin..length) -> range
set_range(offset, length) -> range
set_range(length) -> length
call-seq:
def set_range(r, e = nil)
  unless r
    @header.delete 'range'
    return r
  end
  r = (r...r+e) if e
  case r
  when Numeric
    n = r.to_i
    rangestr = (n > 0 ? "0-#{n-1}" : "-#{-n}")
  when Range
    first = r.first
    last = r.end
    last -= 1 if r.exclude_end?
    if last == -1
      rangestr = (first > 0 ? "#{first}-" : "-#{-first}")
    else
      raise Gem::Net::HTTPHeaderSyntaxError, 'range.first is negative' if first < 0
      raise Gem::Net::HTTPHeaderSyntaxError, 'range.last is negative' if last < 0
      raise Gem::Net::HTTPHeaderSyntaxError, 'must be .first < .last' if first > last
      rangestr = "#{first}-#{last}"
    end
  else
    raise TypeError, 'Range/Integer is required'
  end
  @header['range'] = ["bytes=#{rangestr}"]
  r
end

def size #:nodoc: obsolete

:nodoc: obsolete
def size   #:nodoc: obsolete
  @header.size
end

def sub_type


res.sub_type # => "json"
res['content-type'] # => "application/json; charset=utf-8"
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
or +nil+ if no such field exists;
from the value of field 'Content-Type',
{media type}[https://en.wikipedia.org/wiki/Media_type]
Returns the trailing ('subtype') part of the
def sub_type
  return nil unless @header['content-type']
  _, sub = *self['Content-Type'].split(';').first.to_s.split('/')
  return nil unless sub
  sub.strip
end

def to_hash


"host"=>["jsonplaceholder.typicode.com"]}
"user-agent"=>["Ruby"],
"accept"=>["*/*"],
{"accept-encoding"=>["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],
# =>
req.to_hash
req = Gem::Net::HTTP::Get.new(uri)

Returns a hash of the key/value pairs:
def to_hash
  @header.dup
end

def type_params


res.type_params # => {"charset"=>"utf-8"}
res['content-type'] # => "application/json; charset=utf-8"
res = Gem::Net::HTTP.get_response(hostname, '/todos/1')

see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
or +nil+ if no such field exists;
Returns the trailing ('parameters') part of the value of field 'Content-Type',
def type_params
  result = {}
  list = self['Content-Type'].to_s.split(';')
  list.shift
  list.each do |param|
    k, v = *param.split('=', 2)
    result[k.strip] = v.strip
  end
  result
end