http 4.4.1 → 5.1.0
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/.github/workflows/ci.yml +65 -0
 - data/.gitignore +6 -10
 - data/.rspec +0 -4
 - data/.rubocop/layout.yml +8 -0
 - data/.rubocop/style.yml +32 -0
 - data/.rubocop.yml +8 -110
 - data/.rubocop_todo.yml +205 -0
 - data/.yardopts +1 -1
 - data/CHANGES.md +188 -3
 - data/Gemfile +18 -10
 - data/LICENSE.txt +1 -1
 - data/README.md +47 -86
 - data/Rakefile +2 -10
 - data/SECURITY.md +5 -0
 - data/http.gemspec +9 -8
 - data/lib/http/chainable.rb +23 -17
 - data/lib/http/client.rb +44 -34
 - data/lib/http/connection.rb +11 -7
 - data/lib/http/content_type.rb +12 -7
 - data/lib/http/errors.rb +3 -0
 - data/lib/http/feature.rb +3 -1
 - data/lib/http/features/auto_deflate.rb +6 -6
 - data/lib/http/features/auto_inflate.rb +6 -7
 - data/lib/http/features/instrumentation.rb +1 -1
 - data/lib/http/features/logging.rb +19 -21
 - data/lib/http/headers.rb +50 -13
 - data/lib/http/mime_type/adapter.rb +3 -1
 - data/lib/http/mime_type/json.rb +1 -0
 - data/lib/http/options.rb +5 -8
 - data/lib/http/redirector.rb +51 -2
 - data/lib/http/request/body.rb +1 -0
 - data/lib/http/request/writer.rb +9 -4
 - data/lib/http/request.rb +28 -11
 - data/lib/http/response/body.rb +6 -4
 - data/lib/http/response/inflater.rb +1 -1
 - data/lib/http/response/parser.rb +74 -62
 - data/lib/http/response/status.rb +4 -3
 - data/lib/http/response.rb +44 -18
 - data/lib/http/timeout/global.rb +20 -36
 - data/lib/http/timeout/null.rb +2 -1
 - data/lib/http/timeout/per_operation.rb +32 -55
 - data/lib/http/uri.rb +5 -5
 - data/lib/http/version.rb +1 -1
 - data/spec/lib/http/client_spec.rb +153 -30
 - data/spec/lib/http/connection_spec.rb +8 -5
 - data/spec/lib/http/features/auto_inflate_spec.rb +3 -2
 - data/spec/lib/http/features/instrumentation_spec.rb +27 -21
 - data/spec/lib/http/features/logging_spec.rb +8 -10
 - data/spec/lib/http/headers_spec.rb +53 -18
 - data/spec/lib/http/options/headers_spec.rb +1 -1
 - data/spec/lib/http/options/merge_spec.rb +16 -16
 - data/spec/lib/http/redirector_spec.rb +107 -3
 - data/spec/lib/http/request/body_spec.rb +3 -3
 - data/spec/lib/http/request/writer_spec.rb +25 -2
 - data/spec/lib/http/request_spec.rb +5 -5
 - data/spec/lib/http/response/body_spec.rb +5 -5
 - data/spec/lib/http/response/parser_spec.rb +33 -4
 - data/spec/lib/http/response/status_spec.rb +3 -3
 - data/spec/lib/http/response_spec.rb +80 -3
 - data/spec/lib/http_spec.rb +30 -3
 - data/spec/spec_helper.rb +21 -21
 - data/spec/support/black_hole.rb +1 -1
 - data/spec/support/dummy_server/servlet.rb +17 -6
 - data/spec/support/dummy_server.rb +7 -7
 - data/spec/support/fuubar.rb +21 -0
 - data/spec/support/http_handling_shared.rb +5 -5
 - data/spec/support/simplecov.rb +19 -0
 - data/spec/support/ssl_helper.rb +4 -4
 - metadata +23 -15
 - data/.coveralls.yml +0 -1
 - data/.travis.yml +0 -39
 
| 
         @@ -1,46 +1,58 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
1 
     | 
    
         
             
            # coding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
4 
     | 
    
         
             
            require "support/http_handling_shared"
         
     | 
| 
       5 
5 
     | 
    
         
             
            require "support/dummy_server"
         
     | 
| 
       6 
6 
     | 
    
         
             
            require "support/ssl_helper"
         
     | 
| 
      
 7 
     | 
    
         
            +
            require "logger"
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
       8 
9 
     | 
    
         
             
            RSpec.describe HTTP::Client do
         
     | 
| 
       9 
10 
     | 
    
         
             
              run_server(:dummy) { DummyServer.new }
         
     | 
| 
       10 
11 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
               
     | 
| 
       12 
     | 
    
         
            -
                 
     | 
| 
       13 
     | 
    
         
            -
                   
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
      
 12 
     | 
    
         
            +
              before do
         
     | 
| 
      
 13 
     | 
    
         
            +
                stubbed_client = Class.new(HTTP::Client) do
         
     | 
| 
      
 14 
     | 
    
         
            +
                  def perform(request, options)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    stubbed = stubs[HTTP::URI::NORMALIZER.call(request.uri).to_s]
         
     | 
| 
      
 16 
     | 
    
         
            +
                    stubbed ? stubbed.call(request) : super(request, options)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
       15 
18 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def stubs
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @stubs ||= {}
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def stub(stubs)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @stubs = stubs.transform_keys do |k|
         
     | 
| 
      
 25 
     | 
    
         
            +
                      HTTP::URI::NORMALIZER.call(k).to_s
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
       19 
27 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
                  @stubs = stubs.each_with_object({}) do |(k, v), o|
         
     | 
| 
       22 
     | 
    
         
            -
                    o[HTTP::URI.parse k] = v
         
     | 
| 
      
 28 
     | 
    
         
            +
                    self
         
     | 
| 
       23 
29 
     | 
    
         
             
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
       24 
31 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
      
 32 
     | 
    
         
            +
                def redirect_response(location, status = 302)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  lambda do |request|
         
     | 
| 
      
 34 
     | 
    
         
            +
                    HTTP::Response.new(
         
     | 
| 
      
 35 
     | 
    
         
            +
                      :status  => status,
         
     | 
| 
      
 36 
     | 
    
         
            +
                      :version => "1.1",
         
     | 
| 
      
 37 
     | 
    
         
            +
                      :headers => {"Location" => location},
         
     | 
| 
      
 38 
     | 
    
         
            +
                      :body    => "",
         
     | 
| 
      
 39 
     | 
    
         
            +
                      :request => request
         
     | 
| 
      
 40 
     | 
    
         
            +
                    )
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
       26 
42 
     | 
    
         
             
                end
         
     | 
| 
       27 
     | 
    
         
            -
              end
         
     | 
| 
       28 
43 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
      
 44 
     | 
    
         
            +
                def simple_response(body, status = 200)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  lambda do |request|
         
     | 
| 
      
 46 
     | 
    
         
            +
                    HTTP::Response.new(
         
     | 
| 
      
 47 
     | 
    
         
            +
                      :status  => status,
         
     | 
| 
      
 48 
     | 
    
         
            +
                      :version => "1.1",
         
     | 
| 
      
 49 
     | 
    
         
            +
                      :body    => body,
         
     | 
| 
      
 50 
     | 
    
         
            +
                      :request => request
         
     | 
| 
      
 51 
     | 
    
         
            +
                    )
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
       37 
54 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                HTTP::Response.new(
         
     | 
| 
       40 
     | 
    
         
            -
                  :status  => status,
         
     | 
| 
       41 
     | 
    
         
            -
                  :version => "1.1",
         
     | 
| 
       42 
     | 
    
         
            -
                  :body    => body
         
     | 
| 
       43 
     | 
    
         
            -
                )
         
     | 
| 
      
 55 
     | 
    
         
            +
                stub_const("StubbedClient", stubbed_client)
         
     | 
| 
       44 
56 
     | 
    
         
             
              end
         
     | 
| 
       45 
57 
     | 
    
         | 
| 
       46 
58 
     | 
    
         
             
              describe "following redirects" do
         
     | 
| 
         @@ -104,6 +116,39 @@ RSpec.describe HTTP::Client do 
     | 
|
| 
       104 
116 
     | 
    
         
             
                end
         
     | 
| 
       105 
117 
     | 
    
         
             
              end
         
     | 
| 
       106 
118 
     | 
    
         | 
| 
      
 119 
     | 
    
         
            +
              describe "following redirects with logging" do
         
     | 
| 
      
 120 
     | 
    
         
            +
                let(:logger) do
         
     | 
| 
      
 121 
     | 
    
         
            +
                  logger           = Logger.new(logdev)
         
     | 
| 
      
 122 
     | 
    
         
            +
                  logger.formatter = ->(severity, _, _, message) { format("** %s **\n%s\n", severity, message) }
         
     | 
| 
      
 123 
     | 
    
         
            +
                  logger.level     = Logger::INFO
         
     | 
| 
      
 124 
     | 
    
         
            +
                  logger
         
     | 
| 
      
 125 
     | 
    
         
            +
                end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                let(:logdev) { StringIO.new }
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                it "logs all requests" do
         
     | 
| 
      
 130 
     | 
    
         
            +
                  client = StubbedClient.new(:follow => true, :features => { :logging => { :logger => logger } }).stub(
         
     | 
| 
      
 131 
     | 
    
         
            +
                    "http://example.com/"  => redirect_response("/1"),
         
     | 
| 
      
 132 
     | 
    
         
            +
                    "http://example.com/1" => redirect_response("/2"),
         
     | 
| 
      
 133 
     | 
    
         
            +
                    "http://example.com/2" => redirect_response("/3"),
         
     | 
| 
      
 134 
     | 
    
         
            +
                    "http://example.com/3" => simple_response("OK")
         
     | 
| 
      
 135 
     | 
    
         
            +
                  )
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                  expect { client.get("http://example.com/") }.not_to raise_error
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                  expect(logdev.string).to eq <<~OUTPUT
         
     | 
| 
      
 140 
     | 
    
         
            +
                    ** INFO **
         
     | 
| 
      
 141 
     | 
    
         
            +
                    > GET http://example.com/
         
     | 
| 
      
 142 
     | 
    
         
            +
                    ** INFO **
         
     | 
| 
      
 143 
     | 
    
         
            +
                    > GET http://example.com/1
         
     | 
| 
      
 144 
     | 
    
         
            +
                    ** INFO **
         
     | 
| 
      
 145 
     | 
    
         
            +
                    > GET http://example.com/2
         
     | 
| 
      
 146 
     | 
    
         
            +
                    ** INFO **
         
     | 
| 
      
 147 
     | 
    
         
            +
                    > GET http://example.com/3
         
     | 
| 
      
 148 
     | 
    
         
            +
                  OUTPUT
         
     | 
| 
      
 149 
     | 
    
         
            +
                end
         
     | 
| 
      
 150 
     | 
    
         
            +
              end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
       107 
152 
     | 
    
         
             
              describe "parsing params" do
         
     | 
| 
       108 
153 
     | 
    
         
             
                let(:client) { HTTP::Client.new }
         
     | 
| 
       109 
154 
     | 
    
         
             
                before { allow(client).to receive :perform }
         
     | 
| 
         @@ -193,7 +238,7 @@ RSpec.describe HTTP::Client do 
     | 
|
| 
       193 
238 
     | 
    
         
             
                context "when passing an HTTP::FormData object directly" do
         
     | 
| 
       194 
239 
     | 
    
         
             
                  it "creates url encoded form data object" do
         
     | 
| 
       195 
240 
     | 
    
         
             
                    client    = HTTP::Client.new
         
     | 
| 
       196 
     | 
    
         
            -
                    form_data = HTTP::FormData::Multipart.new(:foo => "bar")
         
     | 
| 
      
 241 
     | 
    
         
            +
                    form_data = HTTP::FormData::Multipart.new({ :foo => "bar" })
         
     | 
| 
       197 
242 
     | 
    
         | 
| 
       198 
243 
     | 
    
         
             
                    allow(client).to receive(:perform)
         
     | 
| 
       199 
244 
     | 
    
         | 
| 
         @@ -279,6 +324,75 @@ RSpec.describe HTTP::Client do 
     | 
|
| 
       279 
324 
     | 
    
         
             
                    end
         
     | 
| 
       280 
325 
     | 
    
         
             
                  end
         
     | 
| 
       281 
326 
     | 
    
         
             
                end
         
     | 
| 
      
 327 
     | 
    
         
            +
             
     | 
| 
      
 328 
     | 
    
         
            +
                context "Feature" do
         
     | 
| 
      
 329 
     | 
    
         
            +
                  let(:feature_class) do
         
     | 
| 
      
 330 
     | 
    
         
            +
                    Class.new(HTTP::Feature) do
         
     | 
| 
      
 331 
     | 
    
         
            +
                      attr_reader :captured_request, :captured_response, :captured_error
         
     | 
| 
      
 332 
     | 
    
         
            +
             
     | 
| 
      
 333 
     | 
    
         
            +
                      def wrap_request(request)
         
     | 
| 
      
 334 
     | 
    
         
            +
                        @captured_request = request
         
     | 
| 
      
 335 
     | 
    
         
            +
                      end
         
     | 
| 
      
 336 
     | 
    
         
            +
             
     | 
| 
      
 337 
     | 
    
         
            +
                      def wrap_response(response)
         
     | 
| 
      
 338 
     | 
    
         
            +
                        @captured_response = response
         
     | 
| 
      
 339 
     | 
    
         
            +
                      end
         
     | 
| 
      
 340 
     | 
    
         
            +
             
     | 
| 
      
 341 
     | 
    
         
            +
                      def on_error(request, error)
         
     | 
| 
      
 342 
     | 
    
         
            +
                        @captured_request = request
         
     | 
| 
      
 343 
     | 
    
         
            +
                        @captured_error = error
         
     | 
| 
      
 344 
     | 
    
         
            +
                      end
         
     | 
| 
      
 345 
     | 
    
         
            +
                    end
         
     | 
| 
      
 346 
     | 
    
         
            +
                  end
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
      
 348 
     | 
    
         
            +
                  it "is given a chance to wrap the Request" do
         
     | 
| 
      
 349 
     | 
    
         
            +
                    feature_instance = feature_class.new
         
     | 
| 
      
 350 
     | 
    
         
            +
             
     | 
| 
      
 351 
     | 
    
         
            +
                    response = client.use(:test_feature => feature_instance).
         
     | 
| 
      
 352 
     | 
    
         
            +
                               request(:get, dummy.endpoint)
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
                    expect(response.code).to eq(200)
         
     | 
| 
      
 355 
     | 
    
         
            +
                    expect(feature_instance.captured_request.verb).to eq(:get)
         
     | 
| 
      
 356 
     | 
    
         
            +
                    expect(feature_instance.captured_request.uri.to_s).to eq("#{dummy.endpoint}/")
         
     | 
| 
      
 357 
     | 
    
         
            +
                  end
         
     | 
| 
      
 358 
     | 
    
         
            +
             
     | 
| 
      
 359 
     | 
    
         
            +
                  it "is given a chance to wrap the Response" do
         
     | 
| 
      
 360 
     | 
    
         
            +
                    feature_instance = feature_class.new
         
     | 
| 
      
 361 
     | 
    
         
            +
             
     | 
| 
      
 362 
     | 
    
         
            +
                    response = client.use(:test_feature => feature_instance).
         
     | 
| 
      
 363 
     | 
    
         
            +
                               request(:get, dummy.endpoint)
         
     | 
| 
      
 364 
     | 
    
         
            +
             
     | 
| 
      
 365 
     | 
    
         
            +
                    expect(feature_instance.captured_response).to eq(response)
         
     | 
| 
      
 366 
     | 
    
         
            +
                  end
         
     | 
| 
      
 367 
     | 
    
         
            +
             
     | 
| 
      
 368 
     | 
    
         
            +
                  it "is given a chance to handle an error" do
         
     | 
| 
      
 369 
     | 
    
         
            +
                    sleep_url = "#{dummy.endpoint}/sleep"
         
     | 
| 
      
 370 
     | 
    
         
            +
                    feature_instance = feature_class.new
         
     | 
| 
      
 371 
     | 
    
         
            +
             
     | 
| 
      
 372 
     | 
    
         
            +
                    expect do
         
     | 
| 
      
 373 
     | 
    
         
            +
                      client.use(:test_feature => feature_instance).
         
     | 
| 
      
 374 
     | 
    
         
            +
                        timeout(0.2).
         
     | 
| 
      
 375 
     | 
    
         
            +
                        request(:post, sleep_url)
         
     | 
| 
      
 376 
     | 
    
         
            +
                    end.to raise_error(HTTP::TimeoutError)
         
     | 
| 
      
 377 
     | 
    
         
            +
             
     | 
| 
      
 378 
     | 
    
         
            +
                    expect(feature_instance.captured_error).to be_a(HTTP::TimeoutError)
         
     | 
| 
      
 379 
     | 
    
         
            +
                    expect(feature_instance.captured_request.verb).to eq(:post)
         
     | 
| 
      
 380 
     | 
    
         
            +
                    expect(feature_instance.captured_request.uri.to_s).to eq(sleep_url)
         
     | 
| 
      
 381 
     | 
    
         
            +
                  end
         
     | 
| 
      
 382 
     | 
    
         
            +
             
     | 
| 
      
 383 
     | 
    
         
            +
                  it "is given a chance to handle a connection timeout error" do
         
     | 
| 
      
 384 
     | 
    
         
            +
                    allow(TCPSocket).to receive(:open) { sleep 1 }
         
     | 
| 
      
 385 
     | 
    
         
            +
                    sleep_url = "#{dummy.endpoint}/sleep"
         
     | 
| 
      
 386 
     | 
    
         
            +
                    feature_instance = feature_class.new
         
     | 
| 
      
 387 
     | 
    
         
            +
             
     | 
| 
      
 388 
     | 
    
         
            +
                    expect do
         
     | 
| 
      
 389 
     | 
    
         
            +
                      client.use(:test_feature => feature_instance).
         
     | 
| 
      
 390 
     | 
    
         
            +
                        timeout(0.001).
         
     | 
| 
      
 391 
     | 
    
         
            +
                        request(:post, sleep_url)
         
     | 
| 
      
 392 
     | 
    
         
            +
                    end.to raise_error(HTTP::ConnectTimeoutError)
         
     | 
| 
      
 393 
     | 
    
         
            +
                    expect(feature_instance.captured_error).to be_a(HTTP::ConnectTimeoutError)
         
     | 
| 
      
 394 
     | 
    
         
            +
                  end
         
     | 
| 
      
 395 
     | 
    
         
            +
                end
         
     | 
| 
       282 
396 
     | 
    
         
             
              end
         
     | 
| 
       283 
397 
     | 
    
         | 
| 
       284 
398 
     | 
    
         
             
              include_context "HTTP handling" do
         
     | 
| 
         @@ -288,7 +402,8 @@ RSpec.describe HTTP::Client do 
     | 
|
| 
       288 
402 
     | 
    
         
             
                let(:client)  { described_class.new(options.merge(extra_options)) }
         
     | 
| 
       289 
403 
     | 
    
         
             
              end
         
     | 
| 
       290 
404 
     | 
    
         | 
| 
       291 
     | 
    
         
            -
               
     | 
| 
      
 405 
     | 
    
         
            +
              # TODO: https://github.com/httprb/http/issues/627
         
     | 
| 
      
 406 
     | 
    
         
            +
              xdescribe "working with SSL" do
         
     | 
| 
       292 
407 
     | 
    
         
             
                run_server(:dummy_ssl) { DummyServer.new(:ssl => true) }
         
     | 
| 
       293 
408 
     | 
    
         | 
| 
       294 
409 
     | 
    
         
             
                let(:extra_options) { {} }
         
     | 
| 
         @@ -331,6 +446,14 @@ RSpec.describe HTTP::Client do 
     | 
|
| 
       331 
446 
     | 
    
         
             
                  client.get(dummy.endpoint).to_s
         
     | 
| 
       332 
447 
     | 
    
         
             
                end
         
     | 
| 
       333 
448 
     | 
    
         | 
| 
      
 449 
     | 
    
         
            +
                it "provides access to the Request from the Response" do
         
     | 
| 
      
 450 
     | 
    
         
            +
                  unique_value = "20190424"
         
     | 
| 
      
 451 
     | 
    
         
            +
                  response = client.headers("X-Value" => unique_value).get(dummy.endpoint)
         
     | 
| 
      
 452 
     | 
    
         
            +
             
     | 
| 
      
 453 
     | 
    
         
            +
                  expect(response.request).to be_a(HTTP::Request)
         
     | 
| 
      
 454 
     | 
    
         
            +
                  expect(response.request.headers["X-Value"]).to eq(unique_value)
         
     | 
| 
      
 455 
     | 
    
         
            +
                end
         
     | 
| 
      
 456 
     | 
    
         
            +
             
     | 
| 
       334 
457 
     | 
    
         
             
                context "with HEAD request" do
         
     | 
| 
       335 
458 
     | 
    
         
             
                  it "does not iterates through body" do
         
     | 
| 
       336 
459 
     | 
    
         
             
                    expect_any_instance_of(HTTP::Connection).to_not receive(:readpartial)
         
     | 
| 
         @@ -421,7 +544,7 @@ RSpec.describe HTTP::Client do 
     | 
|
| 
       421 
544 
     | 
    
         
             
                      BODY
         
     | 
| 
       422 
545 
     | 
    
         
             
                    end
         
     | 
| 
       423 
546 
     | 
    
         | 
| 
       424 
     | 
    
         
            -
                     
     | 
| 
      
 547 
     | 
    
         
            +
                    xit "raises HTTP::ConnectionError" do
         
     | 
| 
       425 
548 
     | 
    
         
             
                      expect { client.get(dummy.endpoint).to_s }.to raise_error(HTTP::ConnectionError)
         
     | 
| 
       426 
549 
     | 
    
         
             
                    end
         
     | 
| 
       427 
550 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -3,9 +3,9 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            RSpec.describe HTTP::Connection do
         
     | 
| 
       4 
4 
     | 
    
         
             
              let(:req) do
         
     | 
| 
       5 
5 
     | 
    
         
             
                HTTP::Request.new(
         
     | 
| 
       6 
     | 
    
         
            -
                  :verb 
     | 
| 
       7 
     | 
    
         
            -
                  :uri 
     | 
| 
       8 
     | 
    
         
            -
                  :headers 
     | 
| 
      
 6 
     | 
    
         
            +
                  :verb    => :get,
         
     | 
| 
      
 7 
     | 
    
         
            +
                  :uri     => "http://example.com/",
         
     | 
| 
      
 8 
     | 
    
         
            +
                  :headers => {}
         
     | 
| 
       9 
9 
     | 
    
         
             
                )
         
     | 
| 
       10 
10 
     | 
    
         
             
              end
         
     | 
| 
       11 
11 
     | 
    
         
             
              let(:socket) { double(:connect => nil) }
         
     | 
| 
         @@ -20,14 +20,17 @@ RSpec.describe HTTP::Connection do 
     | 
|
| 
       20 
20 
     | 
    
         
             
                    <<-RESPONSE.gsub(/^\s*\| */, "").gsub(/\n/, "\r\n")
         
     | 
| 
       21 
21 
     | 
    
         
             
                    | HTTP/1.1 200 OK
         
     | 
| 
       22 
22 
     | 
    
         
             
                    | Content-Type: text
         
     | 
| 
      
 23 
     | 
    
         
            +
                    | foo_bar: 123
         
     | 
| 
       23 
24 
     | 
    
         
             
                    |
         
     | 
| 
       24 
25 
     | 
    
         
             
                    RESPONSE
         
     | 
| 
       25 
26 
     | 
    
         
             
                  end
         
     | 
| 
       26 
27 
     | 
    
         
             
                end
         
     | 
| 
       27 
28 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
                it " 
     | 
| 
      
 29 
     | 
    
         
            +
                it "populates headers collection, preserving casing" do
         
     | 
| 
       29 
30 
     | 
    
         
             
                  connection.read_headers!
         
     | 
| 
       30 
     | 
    
         
            -
                  expect(connection.headers).to eq("Content-Type" => "text")
         
     | 
| 
      
 31 
     | 
    
         
            +
                  expect(connection.headers).to eq("Content-Type" => "text", "foo_bar" => "123")
         
     | 
| 
      
 32 
     | 
    
         
            +
                  expect(connection.headers["Foo-Bar"]).to eq("123")
         
     | 
| 
      
 33 
     | 
    
         
            +
                  expect(connection.headers["foo_bar"]).to eq("123")
         
     | 
| 
       31 
34 
     | 
    
         
             
                end
         
     | 
| 
       32 
35 
     | 
    
         
             
              end
         
     | 
| 
       33 
36 
     | 
    
         | 
| 
         @@ -11,7 +11,8 @@ RSpec.describe HTTP::Features::AutoInflate do 
     | 
|
| 
       11 
11 
     | 
    
         
             
                  :version    => "1.1",
         
     | 
| 
       12 
12 
     | 
    
         
             
                  :status     => 200,
         
     | 
| 
       13 
13 
     | 
    
         
             
                  :headers    => headers,
         
     | 
| 
       14 
     | 
    
         
            -
                  :connection => connection
         
     | 
| 
      
 14 
     | 
    
         
            +
                  :connection => connection,
         
     | 
| 
      
 15 
     | 
    
         
            +
                  :request    => HTTP::Request.new(:verb => :get, :uri => "http://example.com")
         
     | 
| 
       15 
16 
     | 
    
         
             
                )
         
     | 
| 
       16 
17 
     | 
    
         
             
              end
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
         @@ -73,7 +74,7 @@ RSpec.describe HTTP::Features::AutoInflate do 
     | 
|
| 
       73 
74 
     | 
    
         
             
                      :status     => 200,
         
     | 
| 
       74 
75 
     | 
    
         
             
                      :headers    => {:content_encoding => "gzip"},
         
     | 
| 
       75 
76 
     | 
    
         
             
                      :connection => connection,
         
     | 
| 
       76 
     | 
    
         
            -
                      :uri 
     | 
| 
      
 77 
     | 
    
         
            +
                      :request    => HTTP::Request.new(:verb => :get, :uri => "https://example.com")
         
     | 
| 
       77 
78 
     | 
    
         
             
                    )
         
     | 
| 
       78 
79 
     | 
    
         
             
                  end
         
     | 
| 
       79 
80 
     | 
    
         | 
| 
         @@ -2,15 +2,36 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            RSpec.describe HTTP::Features::Instrumentation do
         
     | 
| 
       4 
4 
     | 
    
         
             
              subject(:feature) { HTTP::Features::Instrumentation.new(:instrumenter => instrumenter) }
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
       5 
6 
     | 
    
         
             
              let(:instrumenter) { TestInstrumenter.new }
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
      
 8 
     | 
    
         
            +
              before do
         
     | 
| 
      
 9 
     | 
    
         
            +
                test_instrumenter = Class.new(HTTP::Features::Instrumentation::NullInstrumenter) do
         
     | 
| 
      
 10 
     | 
    
         
            +
                  attr_reader :output
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def initialize
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @output = {}
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def start(_name, payload)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    output[:start] = payload
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def finish(_name, payload)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    output[:finish] = payload
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                stub_const("TestInstrumenter", test_instrumenter)
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
       7 
28 
     | 
    
         
             
              describe "logging the request" do
         
     | 
| 
       8 
29 
     | 
    
         
             
                let(:request) do
         
     | 
| 
       9 
30 
     | 
    
         
             
                  HTTP::Request.new(
         
     | 
| 
       10 
     | 
    
         
            -
                    :verb 
     | 
| 
       11 
     | 
    
         
            -
                    :uri 
     | 
| 
      
 31 
     | 
    
         
            +
                    :verb    => :post,
         
     | 
| 
      
 32 
     | 
    
         
            +
                    :uri     => "https://example.com/",
         
     | 
| 
       12 
33 
     | 
    
         
             
                    :headers => {:accept => "application/json"},
         
     | 
| 
       13 
     | 
    
         
            -
                    :body 
     | 
| 
      
 34 
     | 
    
         
            +
                    :body    => '{"hello": "world!"}'
         
     | 
| 
       14 
35 
     | 
    
         
             
                  )
         
     | 
| 
       15 
36 
     | 
    
         
             
                end
         
     | 
| 
       16 
37 
     | 
    
         | 
| 
         @@ -25,10 +46,10 @@ RSpec.describe HTTP::Features::Instrumentation do 
     | 
|
| 
       25 
46 
     | 
    
         
             
                let(:response) do
         
     | 
| 
       26 
47 
     | 
    
         
             
                  HTTP::Response.new(
         
     | 
| 
       27 
48 
     | 
    
         
             
                    :version => "1.1",
         
     | 
| 
       28 
     | 
    
         
            -
                    : 
     | 
| 
       29 
     | 
    
         
            -
                    :status => 200,
         
     | 
| 
      
 49 
     | 
    
         
            +
                    :status  => 200,
         
     | 
| 
       30 
50 
     | 
    
         
             
                    :headers => {:content_type => "application/json"},
         
     | 
| 
       31 
     | 
    
         
            -
                    :body 
     | 
| 
      
 51 
     | 
    
         
            +
                    :body    => '{"success": true}',
         
     | 
| 
      
 52 
     | 
    
         
            +
                    :request => HTTP::Request.new(:verb => :get, :uri => "https://example.com")
         
     | 
| 
       32 
53 
     | 
    
         
             
                  )
         
     | 
| 
       33 
54 
     | 
    
         
             
                end
         
     | 
| 
       34 
55 
     | 
    
         | 
| 
         @@ -38,19 +59,4 @@ RSpec.describe HTTP::Features::Instrumentation do 
     | 
|
| 
       38 
59 
     | 
    
         
             
                  expect(instrumenter.output[:finish]).to eq(:response => response)
         
     | 
| 
       39 
60 
     | 
    
         
             
                end
         
     | 
| 
       40 
61 
     | 
    
         
             
              end
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
              class TestInstrumenter < HTTP::Features::Instrumentation::NullInstrumenter
         
     | 
| 
       43 
     | 
    
         
            -
                attr_reader :output
         
     | 
| 
       44 
     | 
    
         
            -
                def initialize
         
     | 
| 
       45 
     | 
    
         
            -
                  @output = {}
         
     | 
| 
       46 
     | 
    
         
            -
                end
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
                def start(_name, payload)
         
     | 
| 
       49 
     | 
    
         
            -
                  output[:start] = payload
         
     | 
| 
       50 
     | 
    
         
            -
                end
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                def finish(_name, payload)
         
     | 
| 
       53 
     | 
    
         
            -
                  output[:finish] = payload
         
     | 
| 
       54 
     | 
    
         
            -
                end
         
     | 
| 
       55 
     | 
    
         
            -
              end
         
     | 
| 
       56 
62 
     | 
    
         
             
            end
         
     | 
| 
         @@ -4,10 +4,8 @@ require "logger" 
     | 
|
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            RSpec.describe HTTP::Features::Logging do
         
     | 
| 
       6 
6 
     | 
    
         
             
              subject(:feature) do
         
     | 
| 
       7 
     | 
    
         
            -
                logger 
     | 
| 
       8 
     | 
    
         
            -
                logger.formatter = ->(severity, _, _, message)  
     | 
| 
       9 
     | 
    
         
            -
                  format("** %s **\n%s\n", severity, message)
         
     | 
| 
       10 
     | 
    
         
            -
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
                logger           = Logger.new(logdev)
         
     | 
| 
      
 8 
     | 
    
         
            +
                logger.formatter = ->(severity, _, _, message) { format("** %s **\n%s\n", severity, message) }
         
     | 
| 
       11 
9 
     | 
    
         | 
| 
       12 
10 
     | 
    
         
             
                described_class.new(:logger => logger)
         
     | 
| 
       13 
11 
     | 
    
         
             
              end
         
     | 
| 
         @@ -17,10 +15,10 @@ RSpec.describe HTTP::Features::Logging do 
     | 
|
| 
       17 
15 
     | 
    
         
             
              describe "logging the request" do
         
     | 
| 
       18 
16 
     | 
    
         
             
                let(:request) do
         
     | 
| 
       19 
17 
     | 
    
         
             
                  HTTP::Request.new(
         
     | 
| 
       20 
     | 
    
         
            -
                    :verb 
     | 
| 
       21 
     | 
    
         
            -
                    :uri 
     | 
| 
       22 
     | 
    
         
            -
                    :headers 
     | 
| 
       23 
     | 
    
         
            -
                    :body 
     | 
| 
      
 18 
     | 
    
         
            +
                    :verb    => :post,
         
     | 
| 
      
 19 
     | 
    
         
            +
                    :uri     => "https://example.com/",
         
     | 
| 
      
 20 
     | 
    
         
            +
                    :headers => {:accept => "application/json"},
         
     | 
| 
      
 21 
     | 
    
         
            +
                    :body    => '{"hello": "world!"}'
         
     | 
| 
       24 
22 
     | 
    
         
             
                  )
         
     | 
| 
       25 
23 
     | 
    
         
             
                end
         
     | 
| 
       26 
24 
     | 
    
         | 
| 
         @@ -44,10 +42,10 @@ RSpec.describe HTTP::Features::Logging do 
     | 
|
| 
       44 
42 
     | 
    
         
             
                let(:response) do
         
     | 
| 
       45 
43 
     | 
    
         
             
                  HTTP::Response.new(
         
     | 
| 
       46 
44 
     | 
    
         
             
                    :version => "1.1",
         
     | 
| 
       47 
     | 
    
         
            -
                    :uri     => "https://example.com",
         
     | 
| 
       48 
45 
     | 
    
         
             
                    :status  => 200,
         
     | 
| 
       49 
46 
     | 
    
         
             
                    :headers => {:content_type => "application/json"},
         
     | 
| 
       50 
     | 
    
         
            -
                    :body    => '{"success": true}'
         
     | 
| 
      
 47 
     | 
    
         
            +
                    :body    => '{"success": true}',
         
     | 
| 
      
 48 
     | 
    
         
            +
                    :request => HTTP::Request.new(:verb => :get, :uri => "https://example.com")
         
     | 
| 
       51 
49 
     | 
    
         
             
                  )
         
     | 
| 
       52 
50 
     | 
    
         
             
                end
         
     | 
| 
       53 
51 
     | 
    
         | 
| 
         @@ -13,7 +13,7 @@ RSpec.describe HTTP::Headers do 
     | 
|
| 
       13 
13 
     | 
    
         
             
                  expect(headers["Accept"]).to eq "application/json"
         
     | 
| 
       14 
14 
     | 
    
         
             
                end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
                it " 
     | 
| 
      
 16 
     | 
    
         
            +
                it "allows retrieval via normalized header name" do
         
     | 
| 
       17 
17 
     | 
    
         
             
                  headers.set :content_type, "application/json"
         
     | 
| 
       18 
18 
     | 
    
         
             
                  expect(headers["Content-Type"]).to eq "application/json"
         
     | 
| 
       19 
19 
     | 
    
         
             
                end
         
     | 
| 
         @@ -35,8 +35,15 @@ RSpec.describe HTTP::Headers do 
     | 
|
| 
       35 
35 
     | 
    
         
             
                    to raise_error HTTP::HeaderError
         
     | 
| 
       36 
36 
     | 
    
         
             
                end
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
                 
     | 
| 
       39 
     | 
    
         
            -
                   
     | 
| 
      
 38 
     | 
    
         
            +
                ["foo bar", "foo bar: ok\nfoo", "evil-header: evil-value\nfoo"].each do |name|
         
     | 
| 
      
 39 
     | 
    
         
            +
                  it "fails with invalid header name (#{name.inspect})" do
         
     | 
| 
      
 40 
     | 
    
         
            +
                    expect { headers.set name, "baz" }.
         
     | 
| 
      
 41 
     | 
    
         
            +
                      to raise_error HTTP::HeaderError
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                it "fails with invalid header value" do
         
     | 
| 
      
 46 
     | 
    
         
            +
                  expect { headers.set "foo", "bar\nEvil-Header: evil-value" }.
         
     | 
| 
       40 
47 
     | 
    
         
             
                    to raise_error HTTP::HeaderError
         
     | 
| 
       41 
48 
     | 
    
         
             
                end
         
     | 
| 
       42 
49 
     | 
    
         
             
              end
         
     | 
| 
         @@ -47,7 +54,7 @@ RSpec.describe HTTP::Headers do 
     | 
|
| 
       47 
54 
     | 
    
         
             
                  expect(headers["Accept"]).to eq "application/json"
         
     | 
| 
       48 
55 
     | 
    
         
             
                end
         
     | 
| 
       49 
56 
     | 
    
         | 
| 
       50 
     | 
    
         
            -
                it " 
     | 
| 
      
 57 
     | 
    
         
            +
                it "allows retrieval via normalized header name" do
         
     | 
| 
       51 
58 
     | 
    
         
             
                  headers[:content_type] = "application/json"
         
     | 
| 
       52 
59 
     | 
    
         
             
                  expect(headers["Content-Type"]).to eq "application/json"
         
     | 
| 
       53 
60 
     | 
    
         
             
                end
         
     | 
| 
         @@ -73,7 +80,7 @@ RSpec.describe HTTP::Headers do 
     | 
|
| 
       73 
80 
     | 
    
         
             
                  expect(headers["Content-Type"]).to be_nil
         
     | 
| 
       74 
81 
     | 
    
         
             
                end
         
     | 
| 
       75 
82 
     | 
    
         | 
| 
       76 
     | 
    
         
            -
                it " 
     | 
| 
      
 83 
     | 
    
         
            +
                it "removes header that matches normalized version of specified name" do
         
     | 
| 
       77 
84 
     | 
    
         
             
                  headers.delete :content_type
         
     | 
| 
       78 
85 
     | 
    
         
             
                  expect(headers["Content-Type"]).to be_nil
         
     | 
| 
       79 
86 
     | 
    
         
             
                end
         
     | 
| 
         @@ -83,9 +90,11 @@ RSpec.describe HTTP::Headers do 
     | 
|
| 
       83 
90 
     | 
    
         
             
                    to raise_error HTTP::HeaderError
         
     | 
| 
       84 
91 
     | 
    
         
             
                end
         
     | 
| 
       85 
92 
     | 
    
         | 
| 
       86 
     | 
    
         
            -
                 
     | 
| 
       87 
     | 
    
         
            -
                   
     | 
| 
       88 
     | 
    
         
            -
                     
     | 
| 
      
 93 
     | 
    
         
            +
                ["foo bar", "foo bar: ok\nfoo"].each do |name|
         
     | 
| 
      
 94 
     | 
    
         
            +
                  it "fails with invalid header name (#{name.inspect})" do
         
     | 
| 
      
 95 
     | 
    
         
            +
                    expect { headers.delete name }.
         
     | 
| 
      
 96 
     | 
    
         
            +
                      to raise_error HTTP::HeaderError
         
     | 
| 
      
 97 
     | 
    
         
            +
                  end
         
     | 
| 
       89 
98 
     | 
    
         
             
                end
         
     | 
| 
       90 
99 
     | 
    
         
             
              end
         
     | 
| 
       91 
100 
     | 
    
         | 
| 
         @@ -95,13 +104,13 @@ RSpec.describe HTTP::Headers do 
     | 
|
| 
       95 
104 
     | 
    
         
             
                  expect(headers["Accept"]).to eq "application/json"
         
     | 
| 
       96 
105 
     | 
    
         
             
                end
         
     | 
| 
       97 
106 
     | 
    
         | 
| 
       98 
     | 
    
         
            -
                it " 
     | 
| 
      
 107 
     | 
    
         
            +
                it "allows retrieval via normalized header name" do
         
     | 
| 
       99 
108 
     | 
    
         
             
                  headers.add :content_type, "application/json"
         
     | 
| 
       100 
109 
     | 
    
         
             
                  expect(headers["Content-Type"]).to eq "application/json"
         
     | 
| 
       101 
110 
     | 
    
         
             
                end
         
     | 
| 
       102 
111 
     | 
    
         | 
| 
       103 
112 
     | 
    
         
             
                it "appends new value if header exists" do
         
     | 
| 
       104 
     | 
    
         
            -
                  headers.add  
     | 
| 
      
 113 
     | 
    
         
            +
                  headers.add "Set-Cookie", "hoo=ray"
         
     | 
| 
       105 
114 
     | 
    
         
             
                  headers.add :set_cookie, "woo=hoo"
         
     | 
| 
       106 
115 
     | 
    
         
             
                  expect(headers["Set-Cookie"]).to eq %w[hoo=ray woo=hoo]
         
     | 
| 
       107 
116 
     | 
    
         
             
                end
         
     | 
| 
         @@ -117,8 +126,20 @@ RSpec.describe HTTP::Headers do 
     | 
|
| 
       117 
126 
     | 
    
         
             
                    to raise_error HTTP::HeaderError
         
     | 
| 
       118 
127 
     | 
    
         
             
                end
         
     | 
| 
       119 
128 
     | 
    
         | 
| 
       120 
     | 
    
         
            -
                 
     | 
| 
       121 
     | 
    
         
            -
                   
     | 
| 
      
 129 
     | 
    
         
            +
                ["foo bar", "foo bar: ok\nfoo"].each do |name|
         
     | 
| 
      
 130 
     | 
    
         
            +
                  it "fails with invalid header name (#{name.inspect})" do
         
     | 
| 
      
 131 
     | 
    
         
            +
                    expect { headers.add name, "baz" }.
         
     | 
| 
      
 132 
     | 
    
         
            +
                      to raise_error HTTP::HeaderError
         
     | 
| 
      
 133 
     | 
    
         
            +
                  end
         
     | 
| 
      
 134 
     | 
    
         
            +
                end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                it "fails with invalid header value" do
         
     | 
| 
      
 137 
     | 
    
         
            +
                  expect { headers.add "foo", "bar\nEvil-Header: evil-value" }.
         
     | 
| 
      
 138 
     | 
    
         
            +
                    to raise_error HTTP::HeaderError
         
     | 
| 
      
 139 
     | 
    
         
            +
                end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                it "fails when header name is not a String or Symbol" do
         
     | 
| 
      
 142 
     | 
    
         
            +
                  expect { headers.add 2, "foo" }.
         
     | 
| 
       122 
143 
     | 
    
         
             
                    to raise_error HTTP::HeaderError
         
     | 
| 
       123 
144 
     | 
    
         
             
                end
         
     | 
| 
       124 
145 
     | 
    
         
             
              end
         
     | 
| 
         @@ -145,9 +166,11 @@ RSpec.describe HTTP::Headers do 
     | 
|
| 
       145 
166 
     | 
    
         
             
                    to raise_error HTTP::HeaderError
         
     | 
| 
       146 
167 
     | 
    
         
             
                end
         
     | 
| 
       147 
168 
     | 
    
         | 
| 
       148 
     | 
    
         
            -
                 
     | 
| 
       149 
     | 
    
         
            -
                   
     | 
| 
       150 
     | 
    
         
            -
                     
     | 
| 
      
 169 
     | 
    
         
            +
                ["foo bar", "foo bar: ok\nfoo"].each do |name|
         
     | 
| 
      
 170 
     | 
    
         
            +
                  it "fails with invalid header name (#{name.inspect})" do
         
     | 
| 
      
 171 
     | 
    
         
            +
                    expect { headers.get name }.
         
     | 
| 
      
 172 
     | 
    
         
            +
                      to raise_error HTTP::HeaderError
         
     | 
| 
      
 173 
     | 
    
         
            +
                  end
         
     | 
| 
       151 
174 
     | 
    
         
             
                end
         
     | 
| 
       152 
175 
     | 
    
         
             
              end
         
     | 
| 
       153 
176 
     | 
    
         | 
| 
         @@ -296,8 +319,19 @@ RSpec.describe HTTP::Headers do 
     | 
|
| 
       296 
319 
     | 
    
         
             
                  )
         
     | 
| 
       297 
320 
     | 
    
         
             
                end
         
     | 
| 
       298 
321 
     | 
    
         | 
| 
      
 322 
     | 
    
         
            +
                it "yields header keys specified as symbols in normalized form" do
         
     | 
| 
      
 323 
     | 
    
         
            +
                  keys = headers.each.map(&:first)
         
     | 
| 
      
 324 
     | 
    
         
            +
                  expect(keys).to eq(%w[Set-Cookie Content-Type Set-Cookie])
         
     | 
| 
      
 325 
     | 
    
         
            +
                end
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
                it "yields headers specified as strings without conversion" do
         
     | 
| 
      
 328 
     | 
    
         
            +
                  headers.add "X_kEy", "value"
         
     | 
| 
      
 329 
     | 
    
         
            +
                  keys = headers.each.map(&:first)
         
     | 
| 
      
 330 
     | 
    
         
            +
                  expect(keys).to eq(%w[Set-Cookie Content-Type Set-Cookie X_kEy])
         
     | 
| 
      
 331 
     | 
    
         
            +
                end
         
     | 
| 
      
 332 
     | 
    
         
            +
             
     | 
| 
       299 
333 
     | 
    
         
             
                it "returns self instance if block given" do
         
     | 
| 
       300 
     | 
    
         
            -
                  expect(headers.each { |*| }).to be headers
         
     | 
| 
      
 334 
     | 
    
         
            +
                  expect(headers.each { |*| }).to be headers # rubocop:disable Lint/EmptyBlock
         
     | 
| 
       301 
335 
     | 
    
         
             
                end
         
     | 
| 
       302 
336 
     | 
    
         | 
| 
       303 
337 
     | 
    
         
             
                it "returns Enumerator if no block given" do
         
     | 
| 
         @@ -472,14 +506,15 @@ RSpec.describe HTTP::Headers do 
     | 
|
| 
       472 
506 
     | 
    
         
             
                end
         
     | 
| 
       473 
507 
     | 
    
         | 
| 
       474 
508 
     | 
    
         
             
                context "with duplicate header keys (mixed case)" do
         
     | 
| 
       475 
     | 
    
         
            -
                  let(:headers) { {"Set-Cookie" => "hoo=ray", " 
     | 
| 
      
 509 
     | 
    
         
            +
                  let(:headers) { {"Set-Cookie" => "hoo=ray", "set_cookie" => "woo=hoo", :set_cookie => "ta=da"} }
         
     | 
| 
       476 
510 
     | 
    
         | 
| 
       477 
511 
     | 
    
         
             
                  it "adds all headers" do
         
     | 
| 
       478 
512 
     | 
    
         
             
                    expect(described_class.coerce(headers).to_a).
         
     | 
| 
       479 
513 
     | 
    
         
             
                      to match_array(
         
     | 
| 
       480 
514 
     | 
    
         
             
                        [
         
     | 
| 
       481 
515 
     | 
    
         
             
                          %w[Set-Cookie hoo=ray],
         
     | 
| 
       482 
     | 
    
         
            -
                          %w[ 
     | 
| 
      
 516 
     | 
    
         
            +
                          %w[set_cookie woo=hoo],
         
     | 
| 
      
 517 
     | 
    
         
            +
                          %w[Set-Cookie ta=da]
         
     | 
| 
       483 
518 
     | 
    
         
             
                        ]
         
     | 
| 
       484 
519 
     | 
    
         
             
                      )
         
     | 
| 
       485 
520 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -8,7 +8,7 @@ RSpec.describe HTTP::Options, "headers" do 
     | 
|
| 
       8 
8 
     | 
    
         
             
              end
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
              it "may be specified with with_headers" do
         
     | 
| 
       11 
     | 
    
         
            -
                opts2 = opts.with_headers( 
     | 
| 
      
 11 
     | 
    
         
            +
                opts2 = opts.with_headers(:accept => "json")
         
     | 
| 
       12 
12 
     | 
    
         
             
                expect(opts.headers).to be_empty
         
     | 
| 
       13 
13 
     | 
    
         
             
                expect(opts2.headers).to eq([%w[Accept json]])
         
     | 
| 
       14 
14 
     | 
    
         
             
              end
         
     | 
| 
         @@ -18,28 +18,28 @@ RSpec.describe HTTP::Options, "merge" do 
     | 
|
| 
       18 
18 
     | 
    
         
             
                # FIXME: yuck :(
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
       20 
20 
     | 
    
         
             
                foo = HTTP::Options.new(
         
     | 
| 
       21 
     | 
    
         
            -
                  :response 
     | 
| 
       22 
     | 
    
         
            -
                  :params 
     | 
| 
       23 
     | 
    
         
            -
                  :form 
     | 
| 
       24 
     | 
    
         
            -
                  :body 
     | 
| 
       25 
     | 
    
         
            -
                  :json 
     | 
| 
       26 
     | 
    
         
            -
                  :headers 
     | 
| 
       27 
     | 
    
         
            -
                  :proxy 
     | 
| 
       28 
     | 
    
         
            -
                  :features 
     | 
| 
      
 21 
     | 
    
         
            +
                  :response => :body,
         
     | 
| 
      
 22 
     | 
    
         
            +
                  :params   => {:baz => "bar"},
         
     | 
| 
      
 23 
     | 
    
         
            +
                  :form     => {:foo => "foo"},
         
     | 
| 
      
 24 
     | 
    
         
            +
                  :body     => "body-foo",
         
     | 
| 
      
 25 
     | 
    
         
            +
                  :json     => {:foo => "foo"},
         
     | 
| 
      
 26 
     | 
    
         
            +
                  :headers  => {:accept => "json", :foo => "foo"},
         
     | 
| 
      
 27 
     | 
    
         
            +
                  :proxy    => {},
         
     | 
| 
      
 28 
     | 
    
         
            +
                  :features => {}
         
     | 
| 
       29 
29 
     | 
    
         
             
                )
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
                bar = HTTP::Options.new(
         
     | 
| 
       32 
     | 
    
         
            -
                  :response 
     | 
| 
       33 
     | 
    
         
            -
                  :persistent 
     | 
| 
       34 
     | 
    
         
            -
                  :params 
     | 
| 
       35 
     | 
    
         
            -
                  :form 
     | 
| 
       36 
     | 
    
         
            -
                  :body 
     | 
| 
       37 
     | 
    
         
            -
                  :json 
     | 
| 
      
 32 
     | 
    
         
            +
                  :response           => :parsed_body,
         
     | 
| 
      
 33 
     | 
    
         
            +
                  :persistent         => "https://www.googe.com",
         
     | 
| 
      
 34 
     | 
    
         
            +
                  :params             => {:plop => "plip"},
         
     | 
| 
      
 35 
     | 
    
         
            +
                  :form               => {:bar => "bar"},
         
     | 
| 
      
 36 
     | 
    
         
            +
                  :body               => "body-bar",
         
     | 
| 
      
 37 
     | 
    
         
            +
                  :json               => {:bar => "bar"},
         
     | 
| 
       38 
38 
     | 
    
         
             
                  :keep_alive_timeout => 10,
         
     | 
| 
       39 
39 
     | 
    
         
             
                  :headers            => {:accept => "xml", :bar => "bar"},
         
     | 
| 
       40 
40 
     | 
    
         
             
                  :timeout_options    => {:foo => :bar},
         
     | 
| 
       41 
     | 
    
         
            -
                  :ssl 
     | 
| 
       42 
     | 
    
         
            -
                  :proxy 
     | 
| 
      
 41 
     | 
    
         
            +
                  :ssl                => {:foo => "bar"},
         
     | 
| 
      
 42 
     | 
    
         
            +
                  :proxy              => {:proxy_address => "127.0.0.1", :proxy_port => 8080}
         
     | 
| 
       43 
43 
     | 
    
         
             
                )
         
     | 
| 
       44 
44 
     | 
    
         | 
| 
       45 
45 
     | 
    
         
             
                expect(foo.merge(bar).to_hash).to eq(
         
     |