net-http 0.1.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/README.md +1 -1
- data/Rakefile +0 -7
- data/doc/net-http/examples.rdoc +31 -0
- data/doc/net-http/included_getters.rdoc +3 -0
- data/lib/net/http/backward.rb +27 -13
- data/lib/net/http/exceptions.rb +28 -27
- data/lib/net/http/generic_request.rb +96 -21
- data/lib/net/http/header.rb +628 -163
- data/lib/net/http/proxy_delta.rb +1 -1
- data/lib/net/http/request.rb +73 -6
- data/lib/net/http/requests.rb +327 -25
- data/lib/net/http/response.rb +339 -28
- data/lib/net/http/responses.rb +1090 -223
- data/lib/net/http/status.rb +7 -6
- data/lib/net/http.rb +1458 -668
- data/lib/net/https.rb +1 -1
- data/net-http.gemspec +9 -6
- metadata +5 -20
- data/.github/workflows/test.yml +0 -24
- data/.gitignore +0 -8
- data/Gemfile.lock +0 -23
    
        data/lib/net/http/header.rb
    CHANGED
    
    | @@ -1,16 +1,188 @@ | |
| 1 | 
            -
            # frozen_string_literal:  | 
| 2 | 
            -
            # The HTTPHeader module defines methods for reading and writing
         | 
| 3 | 
            -
            # HTTP headers.
         | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 4 2 | 
             
            #
         | 
| 5 | 
            -
            #  | 
| 6 | 
            -
            # | 
| 7 | 
            -
            #  | 
| 8 | 
            -
            # | 
| 9 | 
            -
            #  | 
| 3 | 
            +
            # The \HTTPHeader module provides access to \HTTP headers.
         | 
| 4 | 
            +
            #
         | 
| 5 | 
            +
            # The module is included in:
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            # - Net::HTTPGenericRequest (and therefore Net::HTTPRequest).
         | 
| 8 | 
            +
            # - Net::HTTPResponse.
         | 
| 9 | 
            +
            #
         | 
| 10 | 
            +
            # The headers are a hash-like collection of key/value pairs called _fields_.
         | 
| 11 | 
            +
            #
         | 
| 12 | 
            +
            # == Request and Response Fields
         | 
| 13 | 
            +
            #
         | 
| 14 | 
            +
            # Headers may be included in:
         | 
| 15 | 
            +
            #
         | 
| 16 | 
            +
            # - A Net::HTTPRequest object:
         | 
| 17 | 
            +
            #   the object's headers will be sent with the request.
         | 
| 18 | 
            +
            #   Any fields may be defined in the request;
         | 
| 19 | 
            +
            #   see {Setters}[rdoc-ref:Net::HTTPHeader@Setters].
         | 
| 20 | 
            +
            # - A Net::HTTPResponse object:
         | 
| 21 | 
            +
            #   the objects headers are usually those returned from the host.
         | 
| 22 | 
            +
            #   Fields may be retrieved from the object;
         | 
| 23 | 
            +
            #   see {Getters}[rdoc-ref:Net::HTTPHeader@Getters]
         | 
| 24 | 
            +
            #   and {Iterators}[rdoc-ref:Net::HTTPHeader@Iterators].
         | 
| 25 | 
            +
            #
         | 
| 26 | 
            +
            # Exactly which fields should be sent or expected depends on the host;
         | 
| 27 | 
            +
            # see:
         | 
| 28 | 
            +
            #
         | 
| 29 | 
            +
            # - {Request fields}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields].
         | 
| 30 | 
            +
            # - {Response fields}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields].
         | 
| 31 | 
            +
            #
         | 
| 32 | 
            +
            # == About the Examples
         | 
| 33 | 
            +
            #
         | 
| 34 | 
            +
            # :include: doc/net-http/examples.rdoc
         | 
| 35 | 
            +
            #
         | 
| 36 | 
            +
            # == Fields
         | 
| 37 | 
            +
            #
         | 
| 38 | 
            +
            # A header field is a key/value pair.
         | 
| 39 | 
            +
            #
         | 
| 40 | 
            +
            # === Field Keys
         | 
| 41 | 
            +
            #
         | 
| 42 | 
            +
            # A field key may be:
         | 
| 43 | 
            +
            #
         | 
| 44 | 
            +
            # - A string: Key <tt>'Accept'</tt> is treated as if it were
         | 
| 45 | 
            +
            #   <tt>'Accept'.downcase</tt>;  i.e., <tt>'accept'</tt>.
         | 
| 46 | 
            +
            # - A symbol: Key <tt>:Accept</tt> is treated as if it were
         | 
| 47 | 
            +
            #   <tt>:Accept.to_s.downcase</tt>;  i.e., <tt>'accept'</tt>.
         | 
| 48 | 
            +
            #
         | 
| 49 | 
            +
            # Examples:
         | 
| 50 | 
            +
            #
         | 
| 51 | 
            +
            #   req = Net::HTTP::Get.new(uri)
         | 
| 52 | 
            +
            #   req[:accept]  # => "*/*"
         | 
| 53 | 
            +
            #   req['Accept'] # => "*/*"
         | 
| 54 | 
            +
            #   req['ACCEPT'] # => "*/*"
         | 
| 55 | 
            +
            #
         | 
| 56 | 
            +
            #   req['accept'] = 'text/html'
         | 
| 57 | 
            +
            #   req[:accept] = 'text/html'
         | 
| 58 | 
            +
            #   req['ACCEPT'] = 'text/html'
         | 
| 59 | 
            +
            #
         | 
| 60 | 
            +
            # === Field Values
         | 
| 61 | 
            +
            #
         | 
| 62 | 
            +
            # A field value may be returned as an array of strings or as a string:
         | 
| 63 | 
            +
            #
         | 
| 64 | 
            +
            # - These methods return field values as arrays:
         | 
| 65 | 
            +
            #
         | 
| 66 | 
            +
            #   - #get_fields: Returns the array value for the given key,
         | 
| 67 | 
            +
            #     or +nil+ if it does not exist.
         | 
| 68 | 
            +
            #   - #to_hash: Returns a hash of all header fields:
         | 
| 69 | 
            +
            #     each key is a field name; its value is the array value for the field.
         | 
| 70 | 
            +
            #
         | 
| 71 | 
            +
            # - These methods return field values as string;
         | 
| 72 | 
            +
            #   the string value for a field is equivalent to
         | 
| 73 | 
            +
            #   <tt>self[key.downcase.to_s].join(', '))</tt>:
         | 
| 74 | 
            +
            #
         | 
| 75 | 
            +
            #   - #[]: Returns the string value for the given key,
         | 
| 76 | 
            +
            #     or +nil+ if it does not exist.
         | 
| 77 | 
            +
            #   - #fetch: Like #[], but accepts a default value
         | 
| 78 | 
            +
            #     to be returned if the key does not exist.
         | 
| 79 | 
            +
            #
         | 
| 80 | 
            +
            # The field value may be set:
         | 
| 81 | 
            +
            #
         | 
| 82 | 
            +
            # - #[]=: Sets the value for the given key;
         | 
| 83 | 
            +
            #   the given value may be a string, a symbol, an array, or a hash.
         | 
| 84 | 
            +
            # - #add_field: Adds a given value to a value for the given key
         | 
| 85 | 
            +
            #   (not overwriting the existing value).
         | 
| 86 | 
            +
            # - #delete: Deletes the field for the given key.
         | 
| 87 | 
            +
            #
         | 
| 88 | 
            +
            # Example field values:
         | 
| 89 | 
            +
            #
         | 
| 90 | 
            +
            # - \String:
         | 
| 91 | 
            +
            #
         | 
| 92 | 
            +
            #     req['Accept'] = 'text/html' # => "text/html"
         | 
| 93 | 
            +
            #     req['Accept']               # => "text/html"
         | 
| 94 | 
            +
            #     req.get_fields('Accept')    # => ["text/html"]
         | 
| 95 | 
            +
            #
         | 
| 96 | 
            +
            # - \Symbol:
         | 
| 97 | 
            +
            #
         | 
| 98 | 
            +
            #     req['Accept'] = :text    # => :text
         | 
| 99 | 
            +
            #     req['Accept']            # => "text"
         | 
| 100 | 
            +
            #     req.get_fields('Accept') # => ["text"]
         | 
| 101 | 
            +
            #
         | 
| 102 | 
            +
            # - Simple array:
         | 
| 103 | 
            +
            #
         | 
| 104 | 
            +
            #     req[:foo] = %w[bar baz bat]
         | 
| 105 | 
            +
            #     req[:foo]            # => "bar, baz, bat"
         | 
| 106 | 
            +
            #     req.get_fields(:foo) # => ["bar", "baz", "bat"]
         | 
| 107 | 
            +
            #
         | 
| 108 | 
            +
            # - Simple hash:
         | 
| 109 | 
            +
            #
         | 
| 110 | 
            +
            #     req[:foo] = {bar: 0, baz: 1, bat: 2}
         | 
| 111 | 
            +
            #     req[:foo]            # => "bar, 0, baz, 1, bat, 2"
         | 
| 112 | 
            +
            #     req.get_fields(:foo) # => ["bar", "0", "baz", "1", "bat", "2"]
         | 
| 113 | 
            +
            #
         | 
| 114 | 
            +
            # - Nested:
         | 
| 115 | 
            +
            #
         | 
| 116 | 
            +
            #     req[:foo] = [%w[bar baz], {bat: 0, bam: 1}]
         | 
| 117 | 
            +
            #     req[:foo]            # => "bar, baz, bat, 0, bam, 1"
         | 
| 118 | 
            +
            #     req.get_fields(:foo) # => ["bar", "baz", "bat", "0", "bam", "1"]
         | 
| 119 | 
            +
            #
         | 
| 120 | 
            +
            #     req[:foo] = {bar: %w[baz bat], bam: {bah: 0, bad: 1}}
         | 
| 121 | 
            +
            #     req[:foo]            # => "bar, baz, bat, bam, bah, 0, bad, 1"
         | 
| 122 | 
            +
            #     req.get_fields(:foo) # => ["bar", "baz", "bat", "bam", "bah", "0", "bad", "1"]
         | 
| 123 | 
            +
            #
         | 
| 124 | 
            +
            # == Convenience Methods
         | 
| 125 | 
            +
            #
         | 
| 126 | 
            +
            # Various convenience methods retrieve values, set values, query values,
         | 
| 127 | 
            +
            # set form values, or iterate over fields.
         | 
| 128 | 
            +
            #
         | 
| 129 | 
            +
            # === Setters
         | 
| 130 | 
            +
            #
         | 
| 131 | 
            +
            # \Method #[]= can set any field, but does little to validate the new value;
         | 
| 132 | 
            +
            # some of the other setter methods provide some validation:
         | 
| 133 | 
            +
            #
         | 
| 134 | 
            +
            # - #[]=: Sets the string or array value for the given key.
         | 
| 135 | 
            +
            # - #add_field: Creates or adds to the array value for the given key.
         | 
| 136 | 
            +
            # - #basic_auth: Sets the string authorization header for <tt>'Authorization'</tt>.
         | 
| 137 | 
            +
            # - #content_length=: Sets the integer length for field <tt>'Content-Length</tt>.
         | 
| 138 | 
            +
            # - #content_type=: Sets the string value for field <tt>'Content-Type'</tt>.
         | 
| 139 | 
            +
            # - #proxy_basic_auth: Sets the string authorization header for <tt>'Proxy-Authorization'</tt>.
         | 
| 140 | 
            +
            # - #set_range: Sets the value for field <tt>'Range'</tt>.
         | 
| 141 | 
            +
            #
         | 
| 142 | 
            +
            # === Form Setters
         | 
| 143 | 
            +
            #
         | 
| 144 | 
            +
            # - #set_form: Sets an HTML form data set.
         | 
| 145 | 
            +
            # - #set_form_data: Sets header fields and a body from HTML form data.
         | 
| 146 | 
            +
            #
         | 
| 147 | 
            +
            # === Getters
         | 
| 148 | 
            +
            #
         | 
| 149 | 
            +
            # \Method #[] can retrieve the value of any field that exists,
         | 
| 150 | 
            +
            # but always as a string;
         | 
| 151 | 
            +
            # some of the other getter methods return something different
         | 
| 152 | 
            +
            # from the simple string value:
         | 
| 153 | 
            +
            #
         | 
| 154 | 
            +
            # - #[]: Returns the string field value for the given key.
         | 
| 155 | 
            +
            # - #content_length: Returns the integer value of field <tt>'Content-Length'</tt>.
         | 
| 156 | 
            +
            # - #content_range: Returns the Range value of field <tt>'Content-Range'</tt>.
         | 
| 157 | 
            +
            # - #content_type: Returns the string value of field <tt>'Content-Type'</tt>.
         | 
| 158 | 
            +
            # - #fetch: Returns the string field value for the given key.
         | 
| 159 | 
            +
            # - #get_fields: Returns the array field value for the given +key+.
         | 
| 160 | 
            +
            # - #main_type: Returns first part of the string value of field <tt>'Content-Type'</tt>.
         | 
| 161 | 
            +
            # - #sub_type: Returns second part of the string value of field <tt>'Content-Type'</tt>.
         | 
| 162 | 
            +
            # - #range: Returns an array of Range objects of field <tt>'Range'</tt>, or +nil+.
         | 
| 163 | 
            +
            # - #range_length: Returns the integer length of the range given in field <tt>'Content-Range'</tt>.
         | 
| 164 | 
            +
            # - #type_params: Returns the string parameters for <tt>'Content-Type'</tt>.
         | 
| 165 | 
            +
            #
         | 
| 166 | 
            +
            # === Queries
         | 
| 167 | 
            +
            #
         | 
| 168 | 
            +
            # - #chunked?: Returns whether field <tt>'Transfer-Encoding'</tt> is set to <tt>'chunked'</tt>.
         | 
| 169 | 
            +
            # - #connection_close?: Returns whether field <tt>'Connection'</tt> is set to <tt>'close'</tt>.
         | 
| 170 | 
            +
            # - #connection_keep_alive?: Returns whether field <tt>'Connection'</tt> is set to <tt>'keep-alive'</tt>.
         | 
| 171 | 
            +
            # - #key?: Returns whether a given key exists.
         | 
| 172 | 
            +
            #
         | 
| 173 | 
            +
            # === Iterators
         | 
| 174 | 
            +
            #
         | 
| 175 | 
            +
            # - #each_capitalized: Passes each field capitalized-name/value pair to the block.
         | 
| 176 | 
            +
            # - #each_capitalized_name: Passes each capitalized field name to the block.
         | 
| 177 | 
            +
            # - #each_header: Passes each field name/value pair to the block.
         | 
| 178 | 
            +
            # - #each_name: Passes each field name to the block.
         | 
| 179 | 
            +
            # - #each_value: Passes each string field value to the block.
         | 
| 10 180 | 
             
            #
         | 
| 11 181 | 
             
            module Net::HTTPHeader
         | 
| 182 | 
            +
              MAX_KEY_LENGTH = 1024
         | 
| 183 | 
            +
              MAX_FIELD_LENGTH = 65536
         | 
| 12 184 |  | 
| 13 | 
            -
              def initialize_http_header(initheader)
         | 
| 185 | 
            +
              def initialize_http_header(initheader) #:nodoc:
         | 
| 14 186 | 
             
                @header = {}
         | 
| 15 187 | 
             
                return unless initheader
         | 
| 16 188 | 
             
                initheader.each do |key, value|
         | 
| @@ -19,6 +191,12 @@ module Net::HTTPHeader | |
| 19 191 | 
             
                    warn "net/http: nil HTTP header: #{key}", uplevel: 3 if $VERBOSE
         | 
| 20 192 | 
             
                  else
         | 
| 21 193 | 
             
                    value = value.strip # raise error for invalid byte sequences
         | 
| 194 | 
            +
                    if key.to_s.bytesize > MAX_KEY_LENGTH
         | 
| 195 | 
            +
                      raise ArgumentError, "too long (#{key.bytesize} bytes) header: #{key[0, 30].inspect}..."
         | 
| 196 | 
            +
                    end
         | 
| 197 | 
            +
                    if value.to_s.bytesize > MAX_FIELD_LENGTH
         | 
| 198 | 
            +
                      raise ArgumentError, "header #{key} has too long field value: #{value.bytesize}"
         | 
| 199 | 
            +
                    end
         | 
| 22 200 | 
             
                    if value.count("\r\n") > 0
         | 
| 23 201 | 
             
                      raise ArgumentError, "header #{key} has field value #{value.inspect}, this cannot include CR/LF"
         | 
| 24 202 | 
             
                    end
         | 
| @@ -33,14 +211,32 @@ module Net::HTTPHeader | |
| 33 211 |  | 
| 34 212 | 
             
              alias length size   #:nodoc: obsolete
         | 
| 35 213 |  | 
| 36 | 
            -
              # Returns the  | 
| 37 | 
            -
              #  | 
| 214 | 
            +
              # Returns the string field value for the case-insensitive field +key+,
         | 
| 215 | 
            +
              # or +nil+ if there is no such key;
         | 
| 216 | 
            +
              # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
         | 
| 217 | 
            +
              #
         | 
| 218 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 219 | 
            +
              #   res['Connection'] # => "keep-alive"
         | 
| 220 | 
            +
              #   res['Nosuch']     # => nil
         | 
| 221 | 
            +
              #
         | 
| 222 | 
            +
              # Note that some field values may be retrieved via convenience methods;
         | 
| 223 | 
            +
              # see {Getters}[rdoc-ref:Net::HTTPHeader@Getters].
         | 
| 38 224 | 
             
              def [](key)
         | 
| 39 225 | 
             
                a = @header[key.downcase.to_s] or return nil
         | 
| 40 226 | 
             
                a.join(', ')
         | 
| 41 227 | 
             
              end
         | 
| 42 228 |  | 
| 43 | 
            -
              # Sets the  | 
| 229 | 
            +
              # Sets the value for the case-insensitive +key+ to +val+,
         | 
| 230 | 
            +
              # overwriting the previous value if the field exists;
         | 
| 231 | 
            +
              # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
         | 
| 232 | 
            +
              #
         | 
| 233 | 
            +
              #   req = Net::HTTP::Get.new(uri)
         | 
| 234 | 
            +
              #   req['Accept'] # => "*/*"
         | 
| 235 | 
            +
              #   req['Accept'] = 'text/html'
         | 
| 236 | 
            +
              #   req['Accept'] # => "text/html"
         | 
| 237 | 
            +
              #
         | 
| 238 | 
            +
              # Note that some field values may be set via convenience methods;
         | 
| 239 | 
            +
              # see {Setters}[rdoc-ref:Net::HTTPHeader@Setters].
         | 
| 44 240 | 
             
              def []=(key, val)
         | 
| 45 241 | 
             
                unless val
         | 
| 46 242 | 
             
                  @header.delete key.downcase.to_s
         | 
| @@ -49,20 +245,18 @@ module Net::HTTPHeader | |
| 49 245 | 
             
                set_field(key, val)
         | 
| 50 246 | 
             
              end
         | 
| 51 247 |  | 
| 52 | 
            -
              #  | 
| 53 | 
            -
              #  | 
| 54 | 
            -
              #  | 
| 55 | 
            -
              # See also #[]=, #[] and #get_fields.
         | 
| 248 | 
            +
              # Adds value +val+ to the value array for field +key+ if the field exists;
         | 
| 249 | 
            +
              # creates the field with the given +key+ and +val+ if it does not exist.
         | 
| 250 | 
            +
              # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
         | 
| 56 251 | 
             
              #
         | 
| 57 | 
            -
              #    | 
| 58 | 
            -
              #    | 
| 59 | 
            -
              #    | 
| 60 | 
            -
              #    | 
| 61 | 
            -
              #    | 
| 62 | 
            -
              #    | 
| 63 | 
            -
              #    | 
| 64 | 
            -
              #    | 
| 65 | 
            -
              #   p request.get_fields('X-My-Header')   #=> ["a", "b", "c"]
         | 
| 252 | 
            +
              #   req = Net::HTTP::Get.new(uri)
         | 
| 253 | 
            +
              #   req.add_field('Foo', 'bar')
         | 
| 254 | 
            +
              #   req['Foo']            # => "bar"
         | 
| 255 | 
            +
              #   req.add_field('Foo', 'baz')
         | 
| 256 | 
            +
              #   req['Foo']            # => "bar, baz"
         | 
| 257 | 
            +
              #   req.add_field('Foo', %w[baz bam])
         | 
| 258 | 
            +
              #   req['Foo']            # => "bar, baz, baz, bam"
         | 
| 259 | 
            +
              #   req.get_fields('Foo') # => ["bar", "baz", "baz", "bam"]
         | 
| 66 260 | 
             
              #
         | 
| 67 261 | 
             
              def add_field(key, val)
         | 
| 68 262 | 
             
                stringified_downcased_key = key.downcase.to_s
         | 
| @@ -101,16 +295,13 @@ module Net::HTTPHeader | |
| 101 295 | 
             
                end
         | 
| 102 296 | 
             
              end
         | 
| 103 297 |  | 
| 104 | 
            -
              #  | 
| 105 | 
            -
              #  | 
| 106 | 
            -
              #  | 
| 107 | 
            -
              # header fields without any processing.  See also #[].
         | 
| 298 | 
            +
              # Returns the array field value for the given +key+,
         | 
| 299 | 
            +
              # or +nil+ if there is no such field;
         | 
| 300 | 
            +
              # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
         | 
| 108 301 | 
             
              #
         | 
| 109 | 
            -
              #    | 
| 110 | 
            -
              # | 
| 111 | 
            -
              # | 
| 112 | 
            -
              #   p response['Set-Cookie']
         | 
| 113 | 
            -
              #     #=> "session=al98axx; expires=Fri, 31-Dec-1999 23:58:23, query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"
         | 
| 302 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 303 | 
            +
              #   res.get_fields('Connection') # => ["keep-alive"]
         | 
| 304 | 
            +
              #   res.get_fields('Nosuch')     # => nil
         | 
| 114 305 | 
             
              #
         | 
| 115 306 | 
             
              def get_fields(key)
         | 
| 116 307 | 
             
                stringified_downcased_key = key.downcase.to_s
         | 
| @@ -118,24 +309,58 @@ module Net::HTTPHeader | |
| 118 309 | 
             
                @header[stringified_downcased_key].dup
         | 
| 119 310 | 
             
              end
         | 
| 120 311 |  | 
| 121 | 
            -
              #  | 
| 122 | 
            -
              #  | 
| 123 | 
            -
              #  | 
| 124 | 
            -
              # | 
| 312 | 
            +
              # call-seq:
         | 
| 313 | 
            +
              #   fetch(key, default_val = nil) {|key| ... } -> object
         | 
| 314 | 
            +
              #   fetch(key, default_val = nil) -> value or default_val
         | 
| 315 | 
            +
              #
         | 
| 316 | 
            +
              # With a block, returns the string value for +key+ if it exists;
         | 
| 317 | 
            +
              # otherwise returns the value of the block;
         | 
| 318 | 
            +
              # ignores the +default_val+;
         | 
| 319 | 
            +
              # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
         | 
| 320 | 
            +
              #
         | 
| 321 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 322 | 
            +
              #
         | 
| 323 | 
            +
              #   # Field exists; block not called.
         | 
| 324 | 
            +
              #   res.fetch('Connection') do |value|
         | 
| 325 | 
            +
              #     fail 'Cannot happen'
         | 
| 326 | 
            +
              #   end # => "keep-alive"
         | 
| 327 | 
            +
              #
         | 
| 328 | 
            +
              #   # Field does not exist; block called.
         | 
| 329 | 
            +
              #   res.fetch('Nosuch') do |value|
         | 
| 330 | 
            +
              #     value.downcase
         | 
| 331 | 
            +
              #   end # => "nosuch"
         | 
| 332 | 
            +
              #
         | 
| 333 | 
            +
              # With no block, returns the string value for +key+ if it exists;
         | 
| 334 | 
            +
              # otherwise, returns +default_val+ if it was given;
         | 
| 335 | 
            +
              # otherwise raises an exception:
         | 
| 336 | 
            +
              #
         | 
| 337 | 
            +
              #   res.fetch('Connection', 'Foo') # => "keep-alive"
         | 
| 338 | 
            +
              #   res.fetch('Nosuch', 'Foo')     # => "Foo"
         | 
| 339 | 
            +
              #   res.fetch('Nosuch')            # Raises KeyError.
         | 
| 340 | 
            +
              #
         | 
| 125 341 | 
             
              def fetch(key, *args, &block)   #:yield: +key+
         | 
| 126 342 | 
             
                a = @header.fetch(key.downcase.to_s, *args, &block)
         | 
| 127 343 | 
             
                a.kind_of?(Array) ? a.join(', ') : a
         | 
| 128 344 | 
             
              end
         | 
| 129 345 |  | 
| 130 | 
            -
              #  | 
| 131 | 
            -
              # and value to the code block supplied.
         | 
| 346 | 
            +
              # Calls the block with each key/value pair:
         | 
| 132 347 | 
             
              #
         | 
| 133 | 
            -
              #  | 
| 348 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 349 | 
            +
              #   res.each_header do |key, value|
         | 
| 350 | 
            +
              #     p [key, value] if key.start_with?('c')
         | 
| 351 | 
            +
              #   end
         | 
| 134 352 | 
             
              #
         | 
| 135 | 
            -
              #  | 
| 353 | 
            +
              # Output:
         | 
| 136 354 | 
             
              #
         | 
| 137 | 
            -
              # | 
| 355 | 
            +
              #   ["content-type", "application/json; charset=utf-8"]
         | 
| 356 | 
            +
              #   ["connection", "keep-alive"]
         | 
| 357 | 
            +
              #   ["cache-control", "max-age=43200"]
         | 
| 358 | 
            +
              #   ["cf-cache-status", "HIT"]
         | 
| 359 | 
            +
              #   ["cf-ray", "771d17e9bc542cf5-ORD"]
         | 
| 138 360 | 
             
              #
         | 
| 361 | 
            +
              # Returns an enumerator if no block is given.
         | 
| 362 | 
            +
              #
         | 
| 363 | 
            +
              # Net::HTTPHeader#each is an alias for Net::HTTPHeader#each_header.
         | 
| 139 364 | 
             
              def each_header   #:yield: +key+, +value+
         | 
| 140 365 | 
             
                block_given? or return enum_for(__method__) { @header.size }
         | 
| 141 366 | 
             
                @header.each do |k,va|
         | 
| @@ -145,10 +370,24 @@ module Net::HTTPHeader | |
| 145 370 |  | 
| 146 371 | 
             
              alias each each_header
         | 
| 147 372 |  | 
| 148 | 
            -
              #  | 
| 149 | 
            -
              # | 
| 373 | 
            +
              # Calls the block with each field key:
         | 
| 374 | 
            +
              #
         | 
| 375 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 376 | 
            +
              #   res.each_key do |key|
         | 
| 377 | 
            +
              #     p key if key.start_with?('c')
         | 
| 378 | 
            +
              #   end
         | 
| 379 | 
            +
              #
         | 
| 380 | 
            +
              # Output:
         | 
| 381 | 
            +
              #
         | 
| 382 | 
            +
              #   "content-type"
         | 
| 383 | 
            +
              #   "connection"
         | 
| 384 | 
            +
              #   "cache-control"
         | 
| 385 | 
            +
              #   "cf-cache-status"
         | 
| 386 | 
            +
              #   "cf-ray"
         | 
| 150 387 | 
             
              #
         | 
| 151 388 | 
             
              # Returns an enumerator if no block is given.
         | 
| 389 | 
            +
              #
         | 
| 390 | 
            +
              # Net::HTTPHeader#each_name is an alias for Net::HTTPHeader#each_key.
         | 
| 152 391 | 
             
              def each_name(&block)   #:yield: +key+
         | 
| 153 392 | 
             
                block_given? or return enum_for(__method__) { @header.size }
         | 
| 154 393 | 
             
                @header.each_key(&block)
         | 
| @@ -156,12 +395,23 @@ module Net::HTTPHeader | |
| 156 395 |  | 
| 157 396 | 
             
              alias each_key each_name
         | 
| 158 397 |  | 
| 159 | 
            -
              #  | 
| 160 | 
            -
              # | 
| 398 | 
            +
              # Calls the block with each capitalized field name:
         | 
| 399 | 
            +
              #
         | 
| 400 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 401 | 
            +
              #   res.each_capitalized_name do |key|
         | 
| 402 | 
            +
              #     p key if key.start_with?('C')
         | 
| 403 | 
            +
              #   end
         | 
| 404 | 
            +
              #
         | 
| 405 | 
            +
              # Output:
         | 
| 161 406 | 
             
              #
         | 
| 162 | 
            -
              # | 
| 163 | 
            -
              # | 
| 164 | 
            -
              # | 
| 407 | 
            +
              #   "Content-Type"
         | 
| 408 | 
            +
              #   "Connection"
         | 
| 409 | 
            +
              #   "Cache-Control"
         | 
| 410 | 
            +
              #   "Cf-Cache-Status"
         | 
| 411 | 
            +
              #   "Cf-Ray"
         | 
| 412 | 
            +
              #
         | 
| 413 | 
            +
              # The capitalization is system-dependent;
         | 
| 414 | 
            +
              # see {Case Mapping}[https://docs.ruby-lang.org/en/master/case_mapping_rdoc.html].
         | 
| 165 415 | 
             
              #
         | 
| 166 416 | 
             
              # Returns an enumerator if no block is given.
         | 
| 167 417 | 
             
              def each_capitalized_name  #:yield: +key+
         | 
| @@ -171,8 +421,18 @@ module Net::HTTPHeader | |
| 171 421 | 
             
                end
         | 
| 172 422 | 
             
              end
         | 
| 173 423 |  | 
| 174 | 
            -
              #  | 
| 175 | 
            -
              # | 
| 424 | 
            +
              # Calls the block with each string field value:
         | 
| 425 | 
            +
              #
         | 
| 426 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 427 | 
            +
              #   res.each_value do |value|
         | 
| 428 | 
            +
              #     p value if value.start_with?('c')
         | 
| 429 | 
            +
              #   end
         | 
| 430 | 
            +
              #
         | 
| 431 | 
            +
              # Output:
         | 
| 432 | 
            +
              #
         | 
| 433 | 
            +
              #   "chunked"
         | 
| 434 | 
            +
              #   "cf-q-config;dur=6.0000002122251e-06"
         | 
| 435 | 
            +
              #   "cloudflare"
         | 
| 176 436 | 
             
              #
         | 
| 177 437 | 
             
              # Returns an enumerator if no block is given.
         | 
| 178 438 | 
             
              def each_value   #:yield: +value+
         | 
| @@ -182,32 +442,45 @@ module Net::HTTPHeader | |
| 182 442 | 
             
                end
         | 
| 183 443 | 
             
              end
         | 
| 184 444 |  | 
| 185 | 
            -
              # Removes  | 
| 445 | 
            +
              # Removes the header for the given case-insensitive +key+
         | 
| 446 | 
            +
              # (see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]);
         | 
| 447 | 
            +
              # returns the deleted value, or +nil+ if no such field exists:
         | 
| 448 | 
            +
              #
         | 
| 449 | 
            +
              #   req = Net::HTTP::Get.new(uri)
         | 
| 450 | 
            +
              #   req.delete('Accept') # => ["*/*"]
         | 
| 451 | 
            +
              #   req.delete('Nosuch') # => nil
         | 
| 452 | 
            +
              #
         | 
| 186 453 | 
             
              def delete(key)
         | 
| 187 454 | 
             
                @header.delete(key.downcase.to_s)
         | 
| 188 455 | 
             
              end
         | 
| 189 456 |  | 
| 190 | 
            -
              # true if +key+  | 
| 457 | 
            +
              # Returns +true+ if the field for the case-insensitive +key+ exists, +false+ otherwise:
         | 
| 458 | 
            +
              #
         | 
| 459 | 
            +
              #   req = Net::HTTP::Get.new(uri)
         | 
| 460 | 
            +
              #   req.key?('Accept') # => true
         | 
| 461 | 
            +
              #   req.key?('Nosuch') # => false
         | 
| 462 | 
            +
              #
         | 
| 191 463 | 
             
              def key?(key)
         | 
| 192 464 | 
             
                @header.key?(key.downcase.to_s)
         | 
| 193 465 | 
             
              end
         | 
| 194 466 |  | 
| 195 | 
            -
              # Returns a  | 
| 196 | 
            -
              # | 
| 197 | 
            -
              #  | 
| 198 | 
            -
              # | 
| 199 | 
            -
              # | 
| 467 | 
            +
              # Returns a hash of the key/value pairs:
         | 
| 468 | 
            +
              #
         | 
| 469 | 
            +
              #   req = Net::HTTP::Get.new(uri)
         | 
| 470 | 
            +
              #   req.to_hash
         | 
| 471 | 
            +
              #   # =>
         | 
| 472 | 
            +
              #   {"accept-encoding"=>["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],
         | 
| 473 | 
            +
              #    "accept"=>["*/*"],
         | 
| 474 | 
            +
              #    "user-agent"=>["Ruby"],
         | 
| 475 | 
            +
              #    "host"=>["jsonplaceholder.typicode.com"]}
         | 
| 476 | 
            +
              #
         | 
| 200 477 | 
             
              def to_hash
         | 
| 201 478 | 
             
                @header.dup
         | 
| 202 479 | 
             
              end
         | 
| 203 480 |  | 
| 204 | 
            -
              #  | 
| 481 | 
            +
              # Like #each_header, but the keys are returned in capitalized form.
         | 
| 205 482 | 
             
              #
         | 
| 206 | 
            -
              #  | 
| 207 | 
            -
              # capitalization may not match that used by the remote HTTP
         | 
| 208 | 
            -
              # server in its response.
         | 
| 209 | 
            -
              #
         | 
| 210 | 
            -
              # Returns an enumerator if no block is given.
         | 
| 483 | 
            +
              # Net::HTTPHeader#canonical_each is an alias for Net::HTTPHeader#each_capitalized.
         | 
| 211 484 | 
             
              def each_capitalized
         | 
| 212 485 | 
             
                block_given? or return enum_for(__method__) { @header.size }
         | 
| 213 486 | 
             
                @header.each do |k,v|
         | 
| @@ -222,8 +495,17 @@ module Net::HTTPHeader | |
| 222 495 | 
             
              end
         | 
| 223 496 | 
             
              private :capitalize
         | 
| 224 497 |  | 
| 225 | 
            -
              # Returns an  | 
| 226 | 
            -
              #  | 
| 498 | 
            +
              # Returns an array of Range objects that represent
         | 
| 499 | 
            +
              # the value of field <tt>'Range'</tt>,
         | 
| 500 | 
            +
              # or +nil+ if there is no such field;
         | 
| 501 | 
            +
              # see {Range request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#range-request-header]:
         | 
| 502 | 
            +
              #
         | 
| 503 | 
            +
              #   req = Net::HTTP::Get.new(uri)
         | 
| 504 | 
            +
              #   req['Range'] = 'bytes=0-99,200-299,400-499'
         | 
| 505 | 
            +
              #   req.range # => [0..99, 200..299, 400..499]
         | 
| 506 | 
            +
              #   req.delete('Range')
         | 
| 507 | 
            +
              #   req.range # # => nil
         | 
| 508 | 
            +
              #
         | 
| 227 509 | 
             
              def range
         | 
| 228 510 | 
             
                return nil unless @header['range']
         | 
| 229 511 |  | 
| @@ -266,14 +548,31 @@ module Net::HTTPHeader | |
| 266 548 | 
             
                result
         | 
| 267 549 | 
             
              end
         | 
| 268 550 |  | 
| 269 | 
            -
              #  | 
| 270 | 
            -
              #  | 
| 271 | 
            -
              #  | 
| 272 | 
            -
              #  | 
| 551 | 
            +
              # call-seq:
         | 
| 552 | 
            +
              #   set_range(length) -> length
         | 
| 553 | 
            +
              #   set_range(offset, length) -> range
         | 
| 554 | 
            +
              #   set_range(begin..length) -> range
         | 
| 555 | 
            +
              #
         | 
| 556 | 
            +
              # Sets the value for field <tt>'Range'</tt>;
         | 
| 557 | 
            +
              # see {Range request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#range-request-header]:
         | 
| 558 | 
            +
              #
         | 
| 559 | 
            +
              # With argument +length+:
         | 
| 560 | 
            +
              #
         | 
| 561 | 
            +
              #   req = Net::HTTP::Get.new(uri)
         | 
| 562 | 
            +
              #   req.set_range(100)      # => 100
         | 
| 563 | 
            +
              #   req['Range']            # => "bytes=0-99"
         | 
| 273 564 | 
             
              #
         | 
| 274 | 
            -
              # | 
| 275 | 
            -
              #   req.set_range 0, 1023
         | 
| 565 | 
            +
              # With arguments +offset+ and +length+:
         | 
| 276 566 | 
             
              #
         | 
| 567 | 
            +
              #   req.set_range(100, 100) # => 100...200
         | 
| 568 | 
            +
              #   req['Range']            # => "bytes=100-199"
         | 
| 569 | 
            +
              #
         | 
| 570 | 
            +
              # With argument +range+:
         | 
| 571 | 
            +
              #
         | 
| 572 | 
            +
              #   req.set_range(100..199) # => 100..199
         | 
| 573 | 
            +
              #   req['Range']            # => "bytes=100-199"
         | 
| 574 | 
            +
              #
         | 
| 575 | 
            +
              # Net::HTTPHeader#range= is an alias for Net::HTTPHeader#set_range.
         | 
| 277 576 | 
             
              def set_range(r, e = nil)
         | 
| 278 577 | 
             
                unless r
         | 
| 279 578 | 
             
                  @header.delete 'range'
         | 
| @@ -305,8 +604,15 @@ module Net::HTTPHeader | |
| 305 604 |  | 
| 306 605 | 
             
              alias range= set_range
         | 
| 307 606 |  | 
| 308 | 
            -
              # Returns  | 
| 309 | 
            -
              #  | 
| 607 | 
            +
              # Returns the value of field <tt>'Content-Length'</tt> as an integer,
         | 
| 608 | 
            +
              # or +nil+ if there is no such field;
         | 
| 609 | 
            +
              # see {Content-Length request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-length-request-header]:
         | 
| 610 | 
            +
              #
         | 
| 611 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/nosuch/1')
         | 
| 612 | 
            +
              #   res.content_length # => 2
         | 
| 613 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 614 | 
            +
              #   res.content_length # => nil
         | 
| 615 | 
            +
              #
         | 
| 310 616 | 
             
              def content_length
         | 
| 311 617 | 
             
                return nil unless key?('Content-Length')
         | 
| 312 618 | 
             
                len = self['Content-Length'].slice(/\d+/) or
         | 
| @@ -314,6 +620,20 @@ module Net::HTTPHeader | |
| 314 620 | 
             
                len.to_i
         | 
| 315 621 | 
             
              end
         | 
| 316 622 |  | 
| 623 | 
            +
              # Sets the value of field <tt>'Content-Length'</tt> to the given numeric;
         | 
| 624 | 
            +
              # see {Content-Length response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-length-response-header]:
         | 
| 625 | 
            +
              #
         | 
| 626 | 
            +
              #   _uri = uri.dup
         | 
| 627 | 
            +
              #   hostname = _uri.hostname           # => "jsonplaceholder.typicode.com"
         | 
| 628 | 
            +
              #   _uri.path = '/posts'               # => "/posts"
         | 
| 629 | 
            +
              #   req = Net::HTTP::Post.new(_uri)    # => #<Net::HTTP::Post POST>
         | 
| 630 | 
            +
              #   req.body = '{"title": "foo","body": "bar","userId": 1}'
         | 
| 631 | 
            +
              #   req.content_length = req.body.size # => 42
         | 
| 632 | 
            +
              #   req.content_type = 'application/json'
         | 
| 633 | 
            +
              #   res = Net::HTTP.start(hostname) do |http|
         | 
| 634 | 
            +
              #     http.request(req)
         | 
| 635 | 
            +
              #   end # => #<Net::HTTPCreated 201 Created readbody=true>
         | 
| 636 | 
            +
              #
         | 
| 317 637 | 
             
              def content_length=(len)
         | 
| 318 638 | 
             
                unless len
         | 
| 319 639 | 
             
                  @header.delete 'content-length'
         | 
| @@ -322,53 +642,99 @@ module Net::HTTPHeader | |
| 322 642 | 
             
                @header['content-length'] = [len.to_i.to_s]
         | 
| 323 643 | 
             
              end
         | 
| 324 644 |  | 
| 325 | 
            -
              # Returns  | 
| 326 | 
            -
              #  | 
| 327 | 
            -
              #  | 
| 328 | 
            -
              #  | 
| 645 | 
            +
              # Returns +true+ if field <tt>'Transfer-Encoding'</tt>
         | 
| 646 | 
            +
              # exists and has value <tt>'chunked'</tt>,
         | 
| 647 | 
            +
              # +false+ otherwise;
         | 
| 648 | 
            +
              # see {Transfer-Encoding response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#transfer-encoding-response-header]:
         | 
| 649 | 
            +
              #
         | 
| 650 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 651 | 
            +
              #   res['Transfer-Encoding'] # => "chunked"
         | 
| 652 | 
            +
              #   res.chunked?             # => true
         | 
| 653 | 
            +
              #
         | 
| 329 654 | 
             
              def chunked?
         | 
| 330 655 | 
             
                return false unless @header['transfer-encoding']
         | 
| 331 656 | 
             
                field = self['Transfer-Encoding']
         | 
| 332 657 | 
             
                (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
         | 
| 333 658 | 
             
              end
         | 
| 334 659 |  | 
| 335 | 
            -
              # Returns a Range object  | 
| 336 | 
            -
              #  | 
| 337 | 
            -
              #  | 
| 338 | 
            -
              # | 
| 660 | 
            +
              # Returns a Range object representing the value of field
         | 
| 661 | 
            +
              # <tt>'Content-Range'</tt>, or +nil+ if no such field exists;
         | 
| 662 | 
            +
              # see {Content-Range response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-range-response-header]:
         | 
| 663 | 
            +
              #
         | 
| 664 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 665 | 
            +
              #   res['Content-Range'] # => nil
         | 
| 666 | 
            +
              #   res['Content-Range'] = 'bytes 0-499/1000'
         | 
| 667 | 
            +
              #   res['Content-Range'] # => "bytes 0-499/1000"
         | 
| 668 | 
            +
              #   res.content_range    # => 0..499
         | 
| 669 | 
            +
              #
         | 
| 339 670 | 
             
              def content_range
         | 
| 340 671 | 
             
                return nil unless @header['content-range']
         | 
| 341 | 
            -
                m = %r | 
| 672 | 
            +
                m = %r<\A\s*(\w+)\s+(\d+)-(\d+)/(\d+|\*)>.match(self['Content-Range']) or
         | 
| 342 673 | 
             
                    raise Net::HTTPHeaderSyntaxError, 'wrong Content-Range format'
         | 
| 343 | 
            -
                m[1] | 
| 674 | 
            +
                return unless m[1] == 'bytes'
         | 
| 675 | 
            +
                m[2].to_i .. m[3].to_i
         | 
| 344 676 | 
             
              end
         | 
| 345 677 |  | 
| 346 | 
            -
              #  | 
| 678 | 
            +
              # Returns the integer representing length of the value of field
         | 
| 679 | 
            +
              # <tt>'Content-Range'</tt>, or +nil+ if no such field exists;
         | 
| 680 | 
            +
              # see {Content-Range response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-range-response-header]:
         | 
| 681 | 
            +
              #
         | 
| 682 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 683 | 
            +
              #   res['Content-Range'] # => nil
         | 
| 684 | 
            +
              #   res['Content-Range'] = 'bytes 0-499/1000'
         | 
| 685 | 
            +
              #   res.range_length     # => 500
         | 
| 686 | 
            +
              #
         | 
| 347 687 | 
             
              def range_length
         | 
| 348 688 | 
             
                r = content_range() or return nil
         | 
| 349 689 | 
             
                r.end - r.begin + 1
         | 
| 350 690 | 
             
              end
         | 
| 351 691 |  | 
| 352 | 
            -
              # Returns  | 
| 353 | 
            -
              #  | 
| 692 | 
            +
              # Returns the {media type}[https://en.wikipedia.org/wiki/Media_type]
         | 
| 693 | 
            +
              # from the value of field <tt>'Content-Type'</tt>,
         | 
| 694 | 
            +
              # or +nil+ if no such field exists;
         | 
| 695 | 
            +
              # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
         | 
| 696 | 
            +
              #
         | 
| 697 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 698 | 
            +
              #   res['content-type'] # => "application/json; charset=utf-8"
         | 
| 699 | 
            +
              #   res.content_type    # => "application/json"
         | 
| 700 | 
            +
              #
         | 
| 354 701 | 
             
              def content_type
         | 
| 355 | 
            -
                 | 
| 356 | 
            -
                 | 
| 357 | 
            -
             | 
| 358 | 
            -
                 | 
| 702 | 
            +
                main = main_type()
         | 
| 703 | 
            +
                return nil unless main
         | 
| 704 | 
            +
             | 
| 705 | 
            +
                sub = sub_type()
         | 
| 706 | 
            +
                if sub
         | 
| 707 | 
            +
                  "#{main}/#{sub}"
         | 
| 708 | 
            +
                else
         | 
| 709 | 
            +
                  main
         | 
| 359 710 | 
             
                end
         | 
| 360 711 | 
             
              end
         | 
| 361 712 |  | 
| 362 | 
            -
              # Returns  | 
| 363 | 
            -
              #  | 
| 713 | 
            +
              # Returns the leading ('type') part of the
         | 
| 714 | 
            +
              # {media type}[https://en.wikipedia.org/wiki/Media_type]
         | 
| 715 | 
            +
              # from the value of field <tt>'Content-Type'</tt>,
         | 
| 716 | 
            +
              # or +nil+ if no such field exists;
         | 
| 717 | 
            +
              # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
         | 
| 718 | 
            +
              #
         | 
| 719 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 720 | 
            +
              #   res['content-type'] # => "application/json; charset=utf-8"
         | 
| 721 | 
            +
              #   res.main_type       # => "application"
         | 
| 722 | 
            +
              #
         | 
| 364 723 | 
             
              def main_type
         | 
| 365 724 | 
             
                return nil unless @header['content-type']
         | 
| 366 725 | 
             
                self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip
         | 
| 367 726 | 
             
              end
         | 
| 368 727 |  | 
| 369 | 
            -
              # Returns  | 
| 370 | 
            -
              #  | 
| 371 | 
            -
              #  | 
| 728 | 
            +
              # Returns the trailing ('subtype') part of the
         | 
| 729 | 
            +
              # {media type}[https://en.wikipedia.org/wiki/Media_type]
         | 
| 730 | 
            +
              # from the value of field <tt>'Content-Type'</tt>,
         | 
| 731 | 
            +
              # or +nil+ if no such field exists;
         | 
| 732 | 
            +
              # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
         | 
| 733 | 
            +
              #
         | 
| 734 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 735 | 
            +
              #   res['content-type'] # => "application/json; charset=utf-8"
         | 
| 736 | 
            +
              #   res.sub_type        # => "json"
         | 
| 737 | 
            +
              #
         | 
| 372 738 | 
             
              def sub_type
         | 
| 373 739 | 
             
                return nil unless @header['content-type']
         | 
| 374 740 | 
             
                _, sub = *self['Content-Type'].split(';').first.to_s.split('/')
         | 
| @@ -376,9 +742,14 @@ module Net::HTTPHeader | |
| 376 742 | 
             
                sub.strip
         | 
| 377 743 | 
             
              end
         | 
| 378 744 |  | 
| 379 | 
            -
              #  | 
| 380 | 
            -
              #  | 
| 381 | 
            -
              #  | 
| 745 | 
            +
              # Returns the trailing ('parameters') part of the value of field <tt>'Content-Type'</tt>,
         | 
| 746 | 
            +
              # or +nil+ if no such field exists;
         | 
| 747 | 
            +
              # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
         | 
| 748 | 
            +
              #
         | 
| 749 | 
            +
              #   res = Net::HTTP.get_response(hostname, '/todos/1')
         | 
| 750 | 
            +
              #   res['content-type'] # => "application/json; charset=utf-8"
         | 
| 751 | 
            +
              #   res.type_params     # => {"charset"=>"utf-8"}
         | 
| 752 | 
            +
              #
         | 
| 382 753 | 
             
              def type_params
         | 
| 383 754 | 
             
                result = {}
         | 
| 384 755 | 
             
                list = self['Content-Type'].to_s.split(';')
         | 
| @@ -390,29 +761,54 @@ module Net::HTTPHeader | |
| 390 761 | 
             
                result
         | 
| 391 762 | 
             
              end
         | 
| 392 763 |  | 
| 393 | 
            -
              # Sets the  | 
| 394 | 
            -
              #  | 
| 395 | 
            -
              #  | 
| 396 | 
            -
              # | 
| 764 | 
            +
              # Sets the value of field <tt>'Content-Type'</tt>;
         | 
| 765 | 
            +
              # returns the new value;
         | 
| 766 | 
            +
              # see {Content-Type request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-request-header]:
         | 
| 767 | 
            +
              #
         | 
| 768 | 
            +
              #   req = Net::HTTP::Get.new(uri)
         | 
| 769 | 
            +
              #   req.set_content_type('application/json') # => ["application/json"]
         | 
| 770 | 
            +
              #
         | 
| 771 | 
            +
              # Net::HTTPHeader#content_type= is an alias for Net::HTTPHeader#set_content_type.
         | 
| 397 772 | 
             
              def set_content_type(type, params = {})
         | 
| 398 773 | 
             
                @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
         | 
| 399 774 | 
             
              end
         | 
| 400 775 |  | 
| 401 776 | 
             
              alias content_type= set_content_type
         | 
| 402 777 |  | 
| 403 | 
            -
              #  | 
| 404 | 
            -
              #  | 
| 405 | 
            -
              #  | 
| 406 | 
            -
              # | 
| 778 | 
            +
              # Sets the request body to a URL-encoded string derived from argument +params+,
         | 
| 779 | 
            +
              # and sets request header field <tt>'Content-Type'</tt>
         | 
| 780 | 
            +
              # to <tt>'application/x-www-form-urlencoded'</tt>.
         | 
| 781 | 
            +
              #
         | 
| 782 | 
            +
              # The resulting request is suitable for HTTP request +POST+ or +PUT+.
         | 
| 783 | 
            +
              #
         | 
| 784 | 
            +
              # Argument +params+ must be suitable for use as argument +enum+ to
         | 
| 785 | 
            +
              # {URI.encode_www_form}[https://docs.ruby-lang.org/en/master/URI.html#method-c-encode_www_form].
         | 
| 786 | 
            +
              #
         | 
| 787 | 
            +
              # With only argument +params+ given,
         | 
| 788 | 
            +
              # sets the body to a URL-encoded string with the default separator <tt>'&'</tt>:
         | 
| 789 | 
            +
              #
         | 
| 790 | 
            +
              #   req = Net::HTTP::Post.new('example.com')
         | 
| 791 | 
            +
              #
         | 
| 792 | 
            +
              #   req.set_form_data(q: 'ruby', lang: 'en')
         | 
| 793 | 
            +
              #   req.body            # => "q=ruby&lang=en"
         | 
| 794 | 
            +
              #   req['Content-Type'] # => "application/x-www-form-urlencoded"
         | 
| 407 795 | 
             
              #
         | 
| 408 | 
            -
              #  | 
| 409 | 
            -
              #  | 
| 796 | 
            +
              #   req.set_form_data([['q', 'ruby'], ['lang', 'en']])
         | 
| 797 | 
            +
              #   req.body            # => "q=ruby&lang=en"
         | 
| 410 798 | 
             
              #
         | 
| 411 | 
            -
              #  | 
| 412 | 
            -
              # | 
| 413 | 
            -
              #    http.form_data = {"q" => ["ruby", "perl"], "lang" => "en"}
         | 
| 414 | 
            -
              #    http.set_form_data({"q" => "ruby", "lang" => "en"}, ';')
         | 
| 799 | 
            +
              #   req.set_form_data(q: ['ruby', 'perl'], lang: 'en')
         | 
| 800 | 
            +
              #   req.body            # => "q=ruby&q=perl&lang=en"
         | 
| 415 801 | 
             
              #
         | 
| 802 | 
            +
              #   req.set_form_data([['q', 'ruby'], ['q', 'perl'], ['lang', 'en']])
         | 
| 803 | 
            +
              #   req.body            # => "q=ruby&q=perl&lang=en"
         | 
| 804 | 
            +
              #
         | 
| 805 | 
            +
              # With string argument +sep+ also given,
         | 
| 806 | 
            +
              # uses that string as the separator:
         | 
| 807 | 
            +
              #
         | 
| 808 | 
            +
              #   req.set_form_data({q: 'ruby', lang: 'en'}, '|')
         | 
| 809 | 
            +
              #   req.body # => "q=ruby|lang=en"
         | 
| 810 | 
            +
              #
         | 
| 811 | 
            +
              # Net::HTTPHeader#form_data= is an alias for Net::HTTPHeader#set_form_data.
         | 
| 416 812 | 
             
              def set_form_data(params, sep = '&')
         | 
| 417 813 | 
             
                query = URI.encode_www_form(params)
         | 
| 418 814 | 
             
                query.gsub!(/&/, sep) if sep != '&'
         | 
| @@ -422,53 +818,108 @@ module Net::HTTPHeader | |
| 422 818 |  | 
| 423 819 | 
             
              alias form_data= set_form_data
         | 
| 424 820 |  | 
| 425 | 
            -
              #  | 
| 426 | 
            -
              # | 
| 427 | 
            -
              # | 
| 428 | 
            -
              #  | 
| 429 | 
            -
              # | 
| 430 | 
            -
              # | 
| 431 | 
            -
              #  | 
| 432 | 
            -
              # | 
| 433 | 
            -
              # | 
| 434 | 
            -
              # | 
| 435 | 
            -
              # | 
| 436 | 
            -
              # | 
| 437 | 
            -
              #
         | 
| 438 | 
            -
              # | 
| 439 | 
            -
              #  | 
| 440 | 
            -
              # | 
| 441 | 
            -
              # | 
| 442 | 
            -
              # | 
| 443 | 
            -
              # | 
| 444 | 
            -
              # | 
| 445 | 
            -
              # | 
| 446 | 
            -
              #
         | 
| 447 | 
            -
              #  | 
| 448 | 
            -
              #  | 
| 449 | 
            -
              # the  | 
| 450 | 
            -
              #
         | 
| 451 | 
            -
              #  | 
| 452 | 
            -
              # | 
| 453 | 
            -
              # | 
| 454 | 
            -
              # | 
| 455 | 
            -
              #
         | 
| 456 | 
            -
              # | 
| 457 | 
            -
              # | 
| 458 | 
            -
              #
         | 
| 459 | 
            -
              # | 
| 460 | 
            -
              # | 
| 461 | 
            -
              # | 
| 462 | 
            -
              # | 
| 463 | 
            -
              #
         | 
| 464 | 
            -
              # | 
| 465 | 
            -
              # | 
| 466 | 
            -
              # | 
| 467 | 
            -
              # | 
| 468 | 
            -
              # | 
| 469 | 
            -
              # | 
| 470 | 
            -
              #
         | 
| 471 | 
            -
              #  | 
| 821 | 
            +
              # Stores form data to be used in a +POST+ or +PUT+ request.
         | 
| 822 | 
            +
              #
         | 
| 823 | 
            +
              # The form data given in +params+ consists of zero or more fields;
         | 
| 824 | 
            +
              # each field is:
         | 
| 825 | 
            +
              #
         | 
| 826 | 
            +
              # - A scalar value.
         | 
| 827 | 
            +
              # - A name/value pair.
         | 
| 828 | 
            +
              # - An IO stream opened for reading.
         | 
| 829 | 
            +
              #
         | 
| 830 | 
            +
              # Argument +params+ should be an
         | 
| 831 | 
            +
              # {Enumerable}[https://docs.ruby-lang.org/en/master/Enumerable.html#module-Enumerable-label-Enumerable+in+Ruby+Classes]
         | 
| 832 | 
            +
              # (method <tt>params.map</tt> will be called),
         | 
| 833 | 
            +
              # and is often an array or hash.
         | 
| 834 | 
            +
              #
         | 
| 835 | 
            +
              # First, we set up a request:
         | 
| 836 | 
            +
              #
         | 
| 837 | 
            +
              #   _uri = uri.dup
         | 
| 838 | 
            +
              #   _uri.path ='/posts'
         | 
| 839 | 
            +
              #   req = Net::HTTP::Post.new(_uri)
         | 
| 840 | 
            +
              #
         | 
| 841 | 
            +
              # <b>Argument +params+ As an Array</b>
         | 
| 842 | 
            +
              #
         | 
| 843 | 
            +
              # When +params+ is an array,
         | 
| 844 | 
            +
              # each of its elements is a subarray that defines a field;
         | 
| 845 | 
            +
              # the subarray may contain:
         | 
| 846 | 
            +
              #
         | 
| 847 | 
            +
              # - One string:
         | 
| 848 | 
            +
              #
         | 
| 849 | 
            +
              #     req.set_form([['foo'], ['bar'], ['baz']])
         | 
| 850 | 
            +
              #
         | 
| 851 | 
            +
              # - Two strings:
         | 
| 852 | 
            +
              #
         | 
| 853 | 
            +
              #     req.set_form([%w[foo 0], %w[bar 1], %w[baz 2]])
         | 
| 854 | 
            +
              #
         | 
| 855 | 
            +
              # - When argument +enctype+ (see below) is given as
         | 
| 856 | 
            +
              #   <tt>'multipart/form-data'</tt>:
         | 
| 857 | 
            +
              #
         | 
| 858 | 
            +
              #   - A string name and an IO stream opened for reading:
         | 
| 859 | 
            +
              #
         | 
| 860 | 
            +
              #       require 'stringio'
         | 
| 861 | 
            +
              #       req.set_form([['file', StringIO.new('Ruby is cool.')]])
         | 
| 862 | 
            +
              #
         | 
| 863 | 
            +
              #   - A string name, an IO stream opened for reading,
         | 
| 864 | 
            +
              #     and an options hash, which may contain these entries:
         | 
| 865 | 
            +
              #
         | 
| 866 | 
            +
              #     - +:filename+: The name of the file to use.
         | 
| 867 | 
            +
              #     - +:content_type+: The content type of the uploaded file.
         | 
| 868 | 
            +
              #
         | 
| 869 | 
            +
              #     Example:
         | 
| 870 | 
            +
              #
         | 
| 871 | 
            +
              #       req.set_form([['file', file, {filename: "other-filename.foo"}]]
         | 
| 872 | 
            +
              #
         | 
| 873 | 
            +
              # The various forms may be mixed:
         | 
| 874 | 
            +
              #
         | 
| 875 | 
            +
              #   req.set_form(['foo', %w[bar 1], ['file', file]])
         | 
| 876 | 
            +
              #
         | 
| 877 | 
            +
              # <b>Argument +params+ As a Hash</b>
         | 
| 878 | 
            +
              #
         | 
| 879 | 
            +
              # When +params+ is a hash,
         | 
| 880 | 
            +
              # each of its entries is a name/value pair that defines a field:
         | 
| 881 | 
            +
              #
         | 
| 882 | 
            +
              # - The name is a string.
         | 
| 883 | 
            +
              # - The value may be:
         | 
| 884 | 
            +
              #
         | 
| 885 | 
            +
              #   - +nil+.
         | 
| 886 | 
            +
              #   - Another string.
         | 
| 887 | 
            +
              #   - An IO stream opened for reading
         | 
| 888 | 
            +
              #     (only when argument +enctype+ -- see below -- is given as
         | 
| 889 | 
            +
              #     <tt>'multipart/form-data'</tt>).
         | 
| 890 | 
            +
              #
         | 
| 891 | 
            +
              # Examples:
         | 
| 892 | 
            +
              #
         | 
| 893 | 
            +
              #   # Nil-valued fields.
         | 
| 894 | 
            +
              #   req.set_form({'foo' => nil, 'bar' => nil, 'baz' => nil})
         | 
| 895 | 
            +
              #
         | 
| 896 | 
            +
              #   # String-valued fields.
         | 
| 897 | 
            +
              #   req.set_form({'foo' => 0, 'bar' => 1, 'baz' => 2})
         | 
| 898 | 
            +
              #
         | 
| 899 | 
            +
              #   # IO-valued field.
         | 
| 900 | 
            +
              #   require 'stringio'
         | 
| 901 | 
            +
              #   req.set_form({'file' => StringIO.new('Ruby is cool.')})
         | 
| 902 | 
            +
              #
         | 
| 903 | 
            +
              #   # Mixture of fields.
         | 
| 904 | 
            +
              #   req.set_form({'foo' => nil, 'bar' => 1, 'file' => file})
         | 
| 905 | 
            +
              #
         | 
| 906 | 
            +
              # Optional argument +enctype+ specifies the value to be given
         | 
| 907 | 
            +
              # to field <tt>'Content-Type'</tt>, and must be one of:
         | 
| 908 | 
            +
              #
         | 
| 909 | 
            +
              # - <tt>'application/x-www-form-urlencoded'</tt> (the default).
         | 
| 910 | 
            +
              # - <tt>'multipart/form-data'</tt>;
         | 
| 911 | 
            +
              #   see {RFC 7578}[https://www.rfc-editor.org/rfc/rfc7578].
         | 
| 912 | 
            +
              #
         | 
| 913 | 
            +
              # Optional argument +formopt+ is a hash of options
         | 
| 914 | 
            +
              # (applicable only when argument +enctype+
         | 
| 915 | 
            +
              # is <tt>'multipart/form-data'</tt>)
         | 
| 916 | 
            +
              # that may include the following entries:
         | 
| 917 | 
            +
              #
         | 
| 918 | 
            +
              # - +:boundary+: The value is the boundary string for the multipart message.
         | 
| 919 | 
            +
              #   If not given, the boundary is a random string.
         | 
| 920 | 
            +
              #   See {Boundary}[https://www.rfc-editor.org/rfc/rfc7578#section-4.1].
         | 
| 921 | 
            +
              # - +:charset+: Value is the character set for the form submission.
         | 
| 922 | 
            +
              #   Field names and values of non-file fields should be encoded with this charset.
         | 
| 472 923 | 
             
              #
         | 
| 473 924 | 
             
              def set_form(params, enctype='application/x-www-form-urlencoded', formopt={})
         | 
| 474 925 | 
             
                @body_data = params
         | 
| @@ -484,12 +935,24 @@ module Net::HTTPHeader | |
| 484 935 | 
             
                end
         | 
| 485 936 | 
             
              end
         | 
| 486 937 |  | 
| 487 | 
            -
              #  | 
| 938 | 
            +
              # Sets header <tt>'Authorization'</tt> using the given
         | 
| 939 | 
            +
              # +account+ and +password+ strings:
         | 
| 940 | 
            +
              #
         | 
| 941 | 
            +
              #   req.basic_auth('my_account', 'my_password')
         | 
| 942 | 
            +
              #   req['Authorization']
         | 
| 943 | 
            +
              #   # => "Basic bXlfYWNjb3VudDpteV9wYXNzd29yZA=="
         | 
| 944 | 
            +
              #
         | 
| 488 945 | 
             
              def basic_auth(account, password)
         | 
| 489 946 | 
             
                @header['authorization'] = [basic_encode(account, password)]
         | 
| 490 947 | 
             
              end
         | 
| 491 948 |  | 
| 492 | 
            -
              #  | 
| 949 | 
            +
              # Sets header <tt>'Proxy-Authorization'</tt> using the given
         | 
| 950 | 
            +
              # +account+ and +password+ strings:
         | 
| 951 | 
            +
              #
         | 
| 952 | 
            +
              #   req.proxy_basic_auth('my_account', 'my_password')
         | 
| 953 | 
            +
              #   req['Proxy-Authorization']
         | 
| 954 | 
            +
              #   # => "Basic bXlfYWNjb3VudDpteV9wYXNzd29yZA=="
         | 
| 955 | 
            +
              #
         | 
| 493 956 | 
             
              def proxy_basic_auth(account, password)
         | 
| 494 957 | 
             
                @header['proxy-authorization'] = [basic_encode(account, password)]
         | 
| 495 958 | 
             
              end
         | 
| @@ -499,6 +962,7 @@ module Net::HTTPHeader | |
| 499 962 | 
             
              end
         | 
| 500 963 | 
             
              private :basic_encode
         | 
| 501 964 |  | 
| 965 | 
            +
            # Returns whether the HTTP session is to be closed.
         | 
| 502 966 | 
             
              def connection_close?
         | 
| 503 967 | 
             
                token = /(?:\A|,)\s*close\s*(?:\z|,)/i
         | 
| 504 968 | 
             
                @header['connection']&.grep(token) {return true}
         | 
| @@ -506,6 +970,7 @@ module Net::HTTPHeader | |
| 506 970 | 
             
                false
         | 
| 507 971 | 
             
              end
         | 
| 508 972 |  | 
| 973 | 
            +
            # Returns whether the HTTP session is to be kept alive.
         | 
| 509 974 | 
             
              def connection_keep_alive?
         | 
| 510 975 | 
             
                token = /(?:\A|,)\s*keep-alive\s*(?:\z|,)/i
         | 
| 511 976 | 
             
                @header['connection']&.grep(token) {return true}
         |