# class Net::HTTPGenericRequest

HTTPGenericRequest is the parent of the `Net::HTTPRequest` class.

Do not use this directly; instead, use a subclass of `Net::HTTPRequest`.

## About the Examples¶ ↑

Examples here assume that `net/http` has been required (which also requires `uri`):

    require 'net/http'

Many code examples here use these example websites:

- jsonplaceholder.typicode.com.

- example.com.

Some examples also assume these variables:

    uri = URI('https://jsonplaceholder.typicode.com/')
    uri.freeze # Examples may not modify.
    hostname = uri.hostname # => "jsonplaceholder.typicode.com"
    path = uri.path         # => "/"
    port = uri.port         # => 443

So that example requests may be written as:

    Net::HTTP.get(uri)
    Net::HTTP.get(hostname, '/index.html')
    Net::HTTP.start(hostname) do |http|
      http.get('/todos/1')
      http.get('/todos/2')
    end

An example that needs a modified `URI` first duplicates `uri`, then modifies the duplicate:

    _uri = uri.dup
    _uri.path = '/todos/1'

### Attributes

body [R]

Returns the string body for the request, or `nil` if there is none:

    req = Net::HTTP::Post.new(uri)
    req.body # => nil
    req.body = '{"title": "foo","body": "bar","userId": 1}'
    req.body # => "{\"title\": \"foo\",\"body\": \"bar\",\"userId\": 1}"

body_stream [R]

Returns the body stream object for the request, or `nil` if there is none:

    req = Net::HTTP::Post.new(uri)          # => #<Net::HTTP::Post POST>
    req.body_stream                         # => nil
    require 'stringio'
    req.body_stream = StringIO.new('xyzzy') # => #<StringIO:0x0000027d1e5affa8>
    req.body_stream                         # => #<StringIO:0x0000027d1e5affa8>

decode_content [R]

Returns `false` if the request’s header `'Accept-Encoding'` has been set manually or deleted (indicating that the user intends to handle encoding in the response), `true` otherwise:

    req = Net::HTTP::Get.new(uri) # => #<Net::HTTP::Get GET>
    req['Accept-Encoding']        # => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
    req.decode_content            # => true
    req['Accept-Encoding'] = 'foo'
    req.decode_content            # => false
    req.delete('Accept-Encoding')
    req.decode_content            # => false

method [R]

Returns the string method name for the request:

    Net::HTTP::Get.new(uri).method  # => "GET"
    Net::HTTP::Post.new(uri).method # => "POST"

path [R]

Returns the string path for the request:

    Net::HTTP::Get.new(uri).path # => "/"
    Net::HTTP::Post.new('example.com').path # => "example.com"

uri [R]

Returns the `URI` object for the request, or `nil` if none:

    Net::HTTP::Get.new(uri).uri
    # => #<URI::HTTPS https://jsonplaceholder.typicode.com/>
    Net::HTTP::Get.new('example.com').uri # => nil

### Public Instance Methods

body= (str)
Source

    # File lib/net/http/generic_request.rb, line 154
    def body=(str)
      @body = str
      @body_stream = nil
      @body_data = nil
      str
    end

Sets the body for the request:

    req = Net::HTTP::Post.new(uri)
    req.body # => nil
    req.body = '{"title": "foo","body": "bar","userId": 1}'
    req.body # => "{\"title\": \"foo\",\"body\": \"bar\",\"userId\": 1}"

body_stream= (input)
Source

    # File lib/net/http/generic_request.rb, line 179
    def body_stream=(input)
      @body = nil
      @body_stream = input
      @body_data = nil
      input
    end

Sets the body stream for the request:

    req = Net::HTTP::Post.new(uri)          # => #<Net::HTTP::Post POST>
    req.body_stream                         # => nil
    require 'stringio'
    req.body_stream = StringIO.new('xyzzy') # => #<StringIO:0x0000027d1e5affa8>
    req.body_stream                         # => #<StringIO:0x0000027d1e5affa8>

inspect ()
Source

    # File lib/net/http/generic_request.rb, line 101
    def inspect
      "\#<#{self.class} #{@method}>"
    end

Returns a string representation of the request:

    Net::HTTP::Post.new(uri).inspect # => "#<Net::HTTP::Post POST>"

request_body_permitted? ()
Source

    # File lib/net/http/generic_request.rb, line 120
    def request_body_permitted?
      @request_has_body
    end

Returns whether the request may have a body:

    Net::HTTP::Post.new(uri).request_body_permitted? # => true
    Net::HTTP::Get.new(uri).request_body_permitted?  # => false

response_body_permitted? ()
Source

    # File lib/net/http/generic_request.rb, line 129
    def response_body_permitted?
      @response_has_body
    end

Returns whether the response may have a body:

    Net::HTTP::Post.new(uri).response_body_permitted? # => true
    Net::HTTP::Head.new(uri).response_body_permitted? # => false

### Private Instance Methods

encode_multipart_form_data (out, params, opt)
Source

    # File lib/net/http/generic_request.rb, line 312
    def encode_multipart_form_data(out, params, opt)
      charset = opt[:charset]
      boundary = opt[:boundary]
      require 'securerandom' unless defined?(SecureRandom)
      boundary ||= SecureRandom.urlsafe_base64(40)
      chunked_p = chunked?

      buf = +''
      params.each do |key, value, h={}|
        key = quote_string(key, charset)
        filename =
          h.key?(:filename) ? h[:filename] :
          value.respond_to?(:to_path) ? File.basename(value.to_path) :
          nil

        buf << "--#{boundary}\r\n"
        if filename
          filename = quote_string(filename, charset)
          type = h[:content_type] || 'application/octet-stream'
          buf << "Content-Disposition: form-data; " \
            "name=\"#{key}\"; filename=\"#{filename}\"\r\n" \
            "Content-Type: #{type}\r\n\r\n"
          if !out.respond_to?(:write) || !value.respond_to?(:read)
            # if +out+ is not an IO or +value+ is not an IO
            buf << (value.respond_to?(:read) ? value.read : value)
          elsif value.respond_to?(:size) && chunked_p
            # if +out+ is an IO and +value+ is a File, use IO.copy_stream
            flush_buffer(out, buf, chunked_p)
            out << "%x\r\n" % value.size if chunked_p
            IO.copy_stream(value, out)
            out << "\r\n" if chunked_p
          else
            # +out+ is an IO, and +value+ is not a File but an IO
            flush_buffer(out, buf, chunked_p)
            1 while flush_buffer(out, value.read(4096), chunked_p)
          end
        else
          # non-file field:
          #   HTML5 says, "The parts of the generated multipart/form-data
          #   resource that correspond to non-file fields must not have a
          #   Content-Type header specified."
          buf << "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n"
          buf << (value.respond_to?(:read) ? value.read : value)
        end
        buf << "\r\n"
      end
      buf << "--#{boundary}--\r\n"
      flush_buffer(out, buf, chunked_p)
      out << "0\r\n\r\n" if chunked_p
    end

flush_buffer (out, buf, chunked_p)
Source

    # File lib/net/http/generic_request.rb, line 368
    def flush_buffer(out, buf, chunked_p)
      return unless buf
      out << "%x\r\n"%buf.bytesize if chunked_p
      out << buf
      out << "\r\n" if chunked_p
      buf.clear
    end

quote_string (str, charset)
Source

    # File lib/net/http/generic_request.rb, line 363
    def quote_string(str, charset)
      str = str.encode(charset, fallback:->(c){'&#%d;'%c.encode("UTF-8").ord}) if charset
      str.gsub(/[\\"]/, '\\\\\&')
    end

send_request_with_body (sock, ver, path, body)
Source

    # File lib/net/http/generic_request.rb, line 260
    def send_request_with_body(sock, ver, path, body)
      self.content_length = body.bytesize
      delete 'Transfer-Encoding'
      supply_default_content_type
      write_header sock, ver, path
      wait_for_continue sock, ver if sock.continue_timeout
      sock.write body
    end

send_request_with_body_data (sock, ver, path, params)
Source

    # File lib/net/http/generic_request.rb, line 286
    def send_request_with_body_data(sock, ver, path, params)
      if /\Amultipart\/form-data\z/i !~ self.content_type
        self.content_type = 'application/x-www-form-urlencoded'
        return send_request_with_body(sock, ver, path, URI.encode_www_form(params))
      end

      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])
      if chunked?
        write_header sock, ver, path
        encode_multipart_form_data(sock, params, opt)
      else
        require 'tempfile'
        file = Tempfile.new('multipart')
        file.binmode
        encode_multipart_form_data(file, params, opt)
        file.rewind
        self.content_length = file.size
        write_header sock, ver, path
        IO.copy_stream(file, sock)
        file.close(true)
      end
    end

send_request_with_body_stream (sock, ver, path, f)
Source

    # File lib/net/http/generic_request.rb, line 269
    def send_request_with_body_stream(sock, ver, path, f)
      unless content_length() or chunked?
        raise ArgumentError,
            "Content-Length not given and Transfer-Encoding is not `chunked'"
      end
      supply_default_content_type
      write_header sock, ver, path
      wait_for_continue sock, ver if sock.continue_timeout
      if chunked?
        chunker = Chunker.new(sock)
        IO.copy_stream(f, chunker)
        chunker.finish
      else
        IO.copy_stream(f, sock)
      end
    end

supply_default_content_type ()
Source

    # File lib/net/http/generic_request.rb, line 376
    def supply_default_content_type
      return if content_type()
      warn 'net/http: Content-Type did not set; using application/x-www-form-urlencoded', uplevel: 1 if $VERBOSE
      set_content_type 'application/x-www-form-urlencoded'
    end

wait_for_continue (sock, ver)
Source

    # File lib/net/http/generic_request.rb, line 386
    def wait_for_continue(sock, ver)
      if ver >= '1.1' and @header['expect'] and
          @header['expect'].include?('100-continue')
        if sock.io.to_io.wait_readable(sock.continue_timeout)
          res = Net::HTTPResponse.read_new(sock)
          unless res.kind_of?(Net::HTTPContinue)
            res.decode_content = @decode_content
            throw :response, res
          end
        end
      end
    end

Waits up to the continue timeout for a response from the server provided we’re speaking HTTP 1.1 and are expecting a 100-continue response.

write_header (sock, ver, path)
Source

    # File lib/net/http/generic_request.rb, line 399
    def write_header(sock, ver, path)
      reqline = "#{@method} #{path} HTTP/#{ver}"
      if /[\r\n]/ =~ reqline
        raise ArgumentError, "A Request-Line must not contain CR or LF"
      end
      buf = +''
      buf << reqline << "\r\n"
      each_capitalized do |k,v|
        buf << "#{k}: #{v}\r\n"
      end
      buf << "\r\n"
      sock.write buf
    end