123456789_123456789_123456789_123456789_123456789_

Class: Net::HTTPResponse

Relationships & Source Files
Namespace Children
Classes:
Extension / Inclusion / Inheritance Descendants
Subclasses:
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
self, HTTPHeader
Inherits: Object
Defined in: lib/net/http/response.rb,
lib/net/http/responses.rb

Overview

HTTP response class.

This class wraps together the response header and the response body (the entity requested).

It mixes in the HTTPHeader module, which provides access to response header values both via hash-like methods and via individual readers.

Note that each possible HTTP response code defines its own HTTPResponse subclass. All classes are defined under the ::Net module. Indentation indicates inheritance. For a list of the classes see HTTP.

Correspondence HTTP code => class is stored in CODE_TO_OBJ constant:

Net::HTTPResponse::CODE_TO_OBJ['404'] #=> Net::HTTPNotFound

Constant Summary

Class Attribute Summary

Class Method Summary

Instance Attribute Summary

  • #body (also: #entity) rw

    Returns the full entity body.

  • #body=(value) rw

    Because it may be necessary to modify the body, Eg, decompression this method facilitates that.

  • #body_encoding rw

    The encoding to use for the response body.

  • #body_encoding=(value) rw

    Set the encoding to use for the response body.

  • #code readonly

    The HTTP result code string.

  • #decode_content rw

    Set to true automatically when the request did not contain an Accept-Encoding header from the user.

  • #http_version readonly

    The HTTP version supported by the server.

  • #ignore_eof rw

    Whether to ignore EOF when reading bodies with a specified Content-Length header.

  • #message (also: #msg) readonly

    The HTTP result message sent by the server.

  • #uri rw

    The URI used to fetch this response.

  • #entity readonly Internal use only

    Alias for #body.

  • #msg readonly Internal use only

    Alias for #message.

  • #uri=(uri) rw Internal use only

HTTPHeader - Included

#chunked?

Returns “true” if the “transfer-encoding” header is present and set to “chunked”.

#connection_close?, #connection_keep_alive?,
#content_length

Returns an Integer object which represents the HTTP Content-Length: header field, or nil if that field was not provided.

#content_length=

Instance Method Summary

HTTPHeader - Included

#[]

Returns the header field corresponding to the case-insensitive key.

#[]=

Sets the header field corresponding to the case-insensitive key.

#add_field
Ruby 1.8.3

Adds a value to a named header field, instead of replacing its value.

#basic_auth

Set the Authorization: header for “Basic” authorization.

#canonical_each
#content_range

Returns a Range object which represents the value of the Content-Range: header field.

#content_type

Returns a content type string such as “text/html”.

#content_type=
#delete

Removes a header field, specified by case-insensitive key.

#each
#each_capitalized

As for #each_header, except the keys are provided in capitalized form.

#each_capitalized_name

Iterates through the header names in the header, passing capitalized header names to the code block.

#each_header

Iterates through the header names and values, passing in the name and value to the code block supplied.

#each_key
#each_name

Iterates through the header names in the header, passing each header name to the code block.

#each_value

Iterates through header values, passing each value to the code block.

#fetch

Returns the header field corresponding to the case-insensitive key.

#form_data=
#get_fields
Ruby 1.8.3

Returns an array of header field strings corresponding to the case-insensitive key.

#initialize_http_header,
#key?

true if key header exists.

#main_type

Returns a content type string such as “text”.

#proxy_basic_auth

Set Proxy-Authorization: header for “Basic” authorization.

#range

Returns an Array of Range objects which represent the Range: HTTP header field, or nil if there is no such header.

#range=
#range_length

The length of the range represented in Content-Range: header.

#set_content_type

Sets the content type in an HTTP header.

#set_form

Set an HTML form data set.

#set_form_data

Set header fields and a body from HTML form data.

#set_range

Sets the HTTP Range: header.

#sub_type

Returns a content type string such as “html”.

#to_hash

Returns a Hash consisting of header names and array of values.

#type_params

Any parameters specified for the content type, returned as a Hash.

#append_field_value, #basic_encode, #capitalize, #set_field,
#length

Alias for HTTPHeader#size.

#size

obsolete.

Constructor Details

.new(httpv, code, msg) ⇒ HTTPResponse

This method is for internal use only.

internal use only

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 78

def initialize(httpv, code, msg)   #:nodoc: internal use only
  @http_version = httpv
  @code         = code
  @message      = msg
  initialize_http_header nil
  @body = nil
  @read = false
  @uri  = nil
  @decode_content = false
  @body_encoding = false
  @ignore_eof = true
end

Class Attribute Details

.body_permitted?Boolean (readonly)

true if the response has a body.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 22

def body_permitted?
  self::HAS_BODY
end

Class Method Details

.each_response_header(sock) {|key, value| ... } (private)

Yields:

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 54

def each_response_header(sock)
  key = value = nil
  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
    else
      yield key, value if key
      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
end

.exception_type

This method is for internal use only.

internal use only

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 26

def exception_type   # :nodoc: internal use only
  self::EXCEPTION_TYPE
end

.read_new(sock)

This method is for internal use only.

internal use only

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 30

def read_new(sock)   #:nodoc: internal use only
  httpv, code, msg = read_status_line(sock)
  res = response_class(code).new(httpv, code, msg)
  each_response_header(sock) do |k,v|
    res.add_field k, v
  end
  res
end

.read_status_line(sock) (private)

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 41

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
end

.response_class(code) (private)

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 48

def response_class(code)
  CODE_TO_OBJ[code] or
  CODE_CLASS_TO_OBJ[code[0,1]] or
  Net::HTTPUnknownResponse
end

Instance Attribute Details

#body (rw) Also known as: #entity

Returns the full entity body.

Calling this method a second or subsequent time will return the string already read.

http.request_get(‘/index.html’) {|res|

  puts res.body
}

http.request_get(‘/index.html’) {|res|

  p res.body.object_id   # 538149362
  p res.body.object_id   # 538149362
}
[ GitHub ]

  
# File 'lib/net/http/response.rb', line 263

def body
  read_body()
end

#body=(value) (rw)

Because it may be necessary to modify the body, Eg, decompression this method facilitates that.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 269

def body=(value)
  @body = value
end

#body_encoding (rw)

The encoding to use for the response body. If Encoding, use that encoding. If other true value, attempt to detect the appropriate encoding, and use that.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 114

attr_reader :body_encoding

#body_encoding=(value) (rw)

Set the encoding to use for the response body. If given a String, find the related Encoding.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 118

def body_encoding=(value)
  value = Encoding.find(value) if value.is_a?(String)
  @body_encoding = value
end

#code (readonly)

The HTTP result code string. For example, ‘302’. You can also determine the response type by examining which response subclass the response object is an instance of.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 97

attr_reader :code

#decode_content (rw)

Set to true automatically when the request did not contain an Accept-Encoding header from the user.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 109

attr_accessor :decode_content

#entity (readonly)

This method is for internal use only.

Alias for #body.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 273

alias entity body   #:nodoc: obsolete

#http_version (readonly)

The HTTP version supported by the server.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 92

attr_reader :http_version

#ignore_eof (rw)

Whether to ignore EOF when reading bodies with a specified Content-Length header.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 125

attr_accessor :ignore_eof

#message (readonly) Also known as: #msg

The HTTP result message sent by the server. For example, ‘Not Found’.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 100

attr_reader :message

#msg (readonly)

This method is for internal use only.

Alias for #message.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 101

alias msg message   # :nodoc: obsolete

#uri (rw)

The URI used to fetch this response. The response URI is only available if a URI was used to create the request.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 105

attr_reader :uri

#uri=(uri) (rw)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/http/response.rb', line 154

def uri= uri # :nodoc:
  @uri = uri.dup if uri
end

Instance Method Details

#check_bom(str) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/http/response.rb', line 314

def check_bom(str)
  case str.byteslice(0, 2)
  when "\xFE\xFF"
    return Encoding::UTF_16BE
  when "\xFF\xFE"
    return Encoding::UTF_16LE
  end
  if "\xEF\xBB\xBF" == str.byteslice(0, 3)
    return Encoding::UTF_8
  end
  nil
end

#code_type

This method is for internal use only.

response <-> exception relationship

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 135

def code_type   #:nodoc:
  self.class
end

#detect_encoding(str, encoding = nil) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/http/response.rb', line 278

def detect_encoding(str, encoding=nil)
  if encoding
  elsif encoding = type_params['charset']
  elsif encoding = check_bom(str)
  else
    encoding = case content_type&.downcase
    when %r{text/x(?:ht)?ml|application/(?:[^]\+)?xml}
      /\A<xml[ \t\r\n]+
        version[ \t\r\n]*=[ \t\r\n]*(?:"[0-9.]+"|'[0-9.]*')[ \t\r\n]+
        encoding[ \t\r\n]*=[ \t\r\n]*
        (?:"([A-Za-z][\-A-Za-z0-9._]*)"|'([A-Za-z][\-A-Za-z0-9._]*)')/x =~ str
      encoding = $1 || $2 || Encoding::UTF_8
    when %r{text/html.*}
      sniff_encoding(str)
    end
  end
  return encoding
end

#error!

This method is for internal use only.

Raises:

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 139

def error!   #:nodoc:
  message = @code
  message += ' ' + @message.dump if @message
  raise error_type().new(message, self)
end

#error_type

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/http/response.rb', line 145

def error_type   #:nodoc:
  self.class::EXCEPTION_TYPE
end

#extracting_encodings_from_meta_elements(value) (private)

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 404

def extracting_encodings_from_meta_elements(value)
  # http://dev.w3.org/html5/spec/fetching-resources.html#algorithm-for-extracting-an-encoding-from-a-meta-element
  if /charset[\t\n\f\r ]*=(?:"([^"]*)"|'([^']*)'|["']|\z|([^\t\n\f\r ;]+))/i =~ value
    return $1 || $2 || $3
  end
  return nil
end

#get_attribute(ss) (private)

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 369

def get_attribute(ss)
  ss.scan(/[\t\n\f\r \/]*/)
  if ss.peek(1) == '>'
    ss.getch
    return nil
  end
  name = ss.scan(/[^=\t\n\f\r \/>]*/)
  name.downcase!
  raise if name.empty?
  ss.skip(/[\t\n\f\r ]*/)
  if ss.getch != '='
    value = ''
    return [name, value]
  end
  ss.skip(/[\t\n\f\r ]*/)
  case ss.peek(1)
  when '"'
    ss.getch
    value = ss.scan(/[^"]+/)
    value.downcase!
    ss.getch
  when "'"
    ss.getch
    value = ss.scan(/[^']+/)
    value.downcase!
    ss.getch
  when '>'
    value = ''
  else
    value = ss.scan(/[^\t\n\f\r >]+/)
    value.downcase!
  end
  [name, value]
end

#header

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/http/response.rb', line 167

def header   #:nodoc:
  warn "Net::HTTPResponse#header is obsolete", uplevel: 1 if $VERBOSE
  self
end

#inflater (private)

This method is for internal use only.

Checks for a supported Content-Encoding header and yields an Inflate wrapper for this response’s socket when zlib is present. If the Content-Encoding is not supported or zlib is missing, the plain socket is yielded.

If a Content-Range header is present, a plain socket is yielded as the bytes in the range may not be a complete deflate block.

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 421

def inflater # :nodoc:
  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)

    begin
      yield inflate_body_io
      success = true
    ensure
      begin
        inflate_body_io.finish
        if self['content-length']
          self['content-length'] = inflate_body_io.bytes_inflated.to_s
        end
      rescue => err
        # Ignore #finish's error if there is an exception from yield
        raise err if success
      end
    end
  when 'none', 'identity' then
    self.delete 'content-encoding'

    yield @socket
  else
    yield @socket
  end
end

#inspect

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 127

def inspect
  "#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
end

#procdest(dest, block) (private)

Raises:

  • (ArgumentError)
[ GitHub ]

  
# File 'lib/net/http/response.rb', line 510

def procdest(dest, block)
  raise ArgumentError, 'both arg and block given for HTTP method' if
    dest and block
  if block
    Net::ReadAdapter.new(block)
  else
    dest || ''
  end
end

#read_body(dest = nil, &block)

Gets the entity body returned by the remote HTTP server.

If a block is given, the body is passed to the block, and the body is provided in fragments, as it is read in from the socket.

If dest argument is given, response is read into that variable, with dest#<< method (it could be String or IO, or any other object responding to <<).

Calling this method a second or subsequent time for the same HTTPResponse object will return the value already read.

http.request_get(‘/index.html’) {|res|

  puts res.read_body
}

http.request_get(‘/index.html’) {|res|

  p res.read_body.object_id   # 538149362
  p res.read_body.object_id   # 538149362
}

# using iterator

http.request_get(‘/index.html’) {|res|

  res.read_body do |segment|
    print segment
  end
}
[ GitHub ]

  
# File 'lib/net/http/response.rb', line 220

def read_body(dest = nil, &block)
  if @read
    raise IOError, "#{self.class}\#read_body called twice" if dest or block
    return @body
  end
  to = procdest(dest, block)
  stream_check
  if @body_exist
    read_body_0 to
    @body = to
  else
    @body = nil
  end
  @read = true

  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)
  end

  @body.force_encoding(enc) if enc

  @body
end

#read_body_0(dest) (private)

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 456

def read_body_0(dest)
  inflater do |inflate_body_io|
    if chunked?
      read_chunked dest, inflate_body_io
      return
    end

    @socket = inflate_body_io

    clen = content_length()
    if clen
      @socket.read clen, dest, @ignore_eof
      return
    end
    clen = range_length()
    if clen
      @socket.read clen, dest
      return
    end
    @socket.read_all dest
  end
end

#read_chunked(dest, chunk_data_io) (private)

This method is for internal use only.

read_chunked reads from @socket for chunk-size, chunk-extension, CRLF, etc. and chunk_data_io for chunk-data which may be deflate or gzip encoded.

See RFC 2616 section 3.6.1 for definitions

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 486

def read_chunked(dest, chunk_data_io) # :nodoc:
  total = 0
  while true
    line = @socket.readline
    hexlen = line.slice(/[0-9a-fA-F]+/) or
        raise Net::HTTPBadResponse, "wrong chunk size line: #{line}"
    len = hexlen.hex
    break if len == 0
    begin
      chunk_data_io.read len, dest
    ensure
      total += len
      @socket.read 2   # \r\n
    end
  end
  until @socket.readline.empty?
    # none
  end
end

#read_header

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/http/response.rb', line 172

def read_header   #:nodoc:
  warn "Net::HTTPResponse#read_header is obsolete", uplevel: 1 if $VERBOSE
  self
end

#reading_body(sock, reqmethodallowbody)

This method is for internal use only.

body

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 181

def reading_body(sock, reqmethodallowbody)  #:nodoc: internal use only
  @socket = sock
  @body_exist = reqmethodallowbody && self.class.body_permitted?
  begin
    yield
    self.body   # ensure to read body
  ensure
    @socket = nil
  end
end

#response

This method is for internal use only.

header (for backward compatibility only; DO NOT USE)

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 162

def response   #:nodoc:
  warn "Net::HTTPResponse#response is obsolete", uplevel: 1 if $VERBOSE
  self
end

#scanning_meta(str) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/http/response.rb', line 328

def scanning_meta(str)
  require 'strscan'
  ss = StringScanner.new(str)
  if ss.scan_until(/<meta[\t\n\f\r ]*/)
    attrs = {} # attribute_list
    got_pragma = false
    need_pragma = nil
    charset = nil

    # step: Attributes
    while attr = get_attribute(ss)
      name, value = *attr
      next if attrs[name]
      attrs[name] = true
      case name
      when 'http-equiv'
        got_pragma = true if value == 'content-type'
      when 'content'
        encoding = extracting_encodings_from_meta_elements(value)
        unless charset
          charset = encoding
        end
        need_pragma = true
      when 'charset'
        need_pragma = false
        charset = value
      end
    end

    # step: Processing
    return if need_pragma.nil?
    return if need_pragma && !got_pragma

    charset = Encoding.find(charset) rescue nil
    return unless charset
    charset = Encoding::UTF_8 if charset == Encoding::UTF_16
    return charset # tentative
  end
  nil
end

#sniff_encoding(str, encoding = nil) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/http/response.rb', line 298

def sniff_encoding(str, encoding=nil)
  # the encoding sniffing algorithm
  # http://www.w3.org/TR/html5/parsing.html#determining-the-character-encoding
  if enc = scanning_meta(str)
    enc
  # 6. last visited page or something
  # 7. frequency
  elsif str.ascii_only?
    Encoding::US_ASCII
  elsif str.dup.force_encoding(Encoding::UTF_8).valid_encoding?
    Encoding::UTF_8
  end
  # 8. implementation-defined or user-specified
end

#stream_check (private)

Raises:

  • (IOError)
[ GitHub ]

  
# File 'lib/net/http/response.rb', line 506

def stream_check
  raise IOError, 'attempt to read body out of block' if @socket.closed?
end

#value

Raises an HTTP error if the response is not 2xx (success).

[ GitHub ]

  
# File 'lib/net/http/response.rb', line 150

def value
  error! unless self.kind_of?(Net::HTTPSuccess)
end