http 0.6.3 → 0.6.4
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.
Potentially problematic release.
This version of http might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGES.md +8 -0
- data/Gemfile +3 -0
- data/lib/http/client.rb +7 -2
- data/lib/http/version.rb +1 -1
- data/spec/http/client_spec.rb +34 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/support/black_hole.rb +5 -0
- data/spec/support/create_certs.rb +57 -0
- data/spec/support/dummy_server.rb +52 -0
- data/spec/support/dummy_server/servlet.rb +30 -0
- data/spec/support/servers/config.rb +13 -0
- data/spec/support/servers/runner.rb +17 -0
- metadata +8 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d4030eeaf2d60cda70af573153fe436493061181
         | 
| 4 | 
            +
              data.tar.gz: 8c81614a50e7510eb06a0b48ddd8b140da557b88
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 71658b9dc31eb01d62e038c6f7a4e193aa030360ad65d146a5fa3ab03c563c163b9fd688f9a2496b640a143f3658a21b74bc791301b701aaa4c972250995c608
         | 
| 7 | 
            +
              data.tar.gz: 59254dd112aa7e6405b56ddc5901c564d942fdd8e12e913e1a4b6b1f64faf79257432ad85f4b6385b8b4a3f8b45ce732e36839fc78ac53f91bf9cd2bce5f66de
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/CHANGES.md
    CHANGED
    
    | @@ -1,3 +1,11 @@ | |
| 1 | 
            +
            0.6.4 (2015-03-25)
         | 
| 2 | 
            +
            ------------------
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            * SECURITY FIX: http.rb failed to call the `#post_connection_check` method on
         | 
| 5 | 
            +
              SSL connections. This method implements hostname verification, and without it
         | 
| 6 | 
            +
              `http.rb` was vulnerable to MitM attacks. The problem was corrected by calling
         | 
| 7 | 
            +
              `#post_connection_check` (CVE-2015-1828) (@zanker, backported by @nicoolas25)
         | 
| 8 | 
            +
             | 
| 1 9 | 
             
            0.6.3 (2014-11-14)
         | 
| 2 10 | 
             
            ------------------
         | 
| 3 11 |  | 
    
        data/Gemfile
    CHANGED
    
    | @@ -25,6 +25,9 @@ group :test do | |
| 25 25 | 
             
              gem 'rubocop', '~> 0.24.0', :platforms => [:ruby_19, :ruby_20, :ruby_21]
         | 
| 26 26 | 
             
              gem 'simplecov', '>= 0.9'
         | 
| 27 27 | 
             
              gem 'yardstick'
         | 
| 28 | 
            +
              gem 'certificate_authority'
         | 
| 29 | 
            +
              gem 'activemodel', '~> 3.0'
         | 
| 30 | 
            +
              gem 'i18n', '~> 0.6.0'
         | 
| 28 31 | 
             
            end
         | 
| 29 32 |  | 
| 30 33 | 
             
            # Specify your gem's dependencies in http.gemspec
         | 
    
        data/lib/http/client.rb
    CHANGED
    
    | @@ -51,7 +51,7 @@ module HTTP | |
| 51 51 |  | 
| 52 52 | 
             
                  # TODO: keep-alive support
         | 
| 53 53 | 
             
                  @socket = options[:socket_class].open(req.socket_host, req.socket_port)
         | 
| 54 | 
            -
                  @socket = start_tls(@socket, options) if uri.is_a?(URI::HTTPS)
         | 
| 54 | 
            +
                  @socket = start_tls(@socket, uri.host, options) if uri.is_a?(URI::HTTPS)
         | 
| 55 55 |  | 
| 56 56 | 
             
                  req.stream @socket
         | 
| 57 57 |  | 
| @@ -86,12 +86,17 @@ module HTTP | |
| 86 86 | 
             
              private
         | 
| 87 87 |  | 
| 88 88 | 
             
                # Initialize TLS connection
         | 
| 89 | 
            -
                def start_tls(socket, options)
         | 
| 89 | 
            +
                def start_tls(socket, host, options)
         | 
| 90 90 | 
             
                  # TODO: abstract away SSLContexts so we can use other TLS libraries
         | 
| 91 91 | 
             
                  context = options[:ssl_context] || OpenSSL::SSL::SSLContext.new
         | 
| 92 92 | 
             
                  socket  = options[:ssl_socket_class].new(socket, context)
         | 
| 93 93 |  | 
| 94 94 | 
             
                  socket.connect
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  if context.verify_mode == OpenSSL::SSL::VERIFY_PEER
         | 
| 97 | 
            +
                    socket.post_connection_check(host)
         | 
| 98 | 
            +
                  end
         | 
| 99 | 
            +
             | 
| 95 100 | 
             
                  socket
         | 
| 96 101 | 
             
                end
         | 
| 97 102 |  | 
    
        data/lib/http/version.rb
    CHANGED
    
    
    
        data/spec/http/client_spec.rb
    CHANGED
    
    | @@ -1,7 +1,9 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'support/dummy_server'
         | 
| 2 3 |  | 
| 3 4 | 
             
            describe HTTP::Client do
         | 
| 4 5 | 
             
              let(:test_endpoint) { "http://127.0.0.1:#{ExampleService::PORT}" }
         | 
| 6 | 
            +
              run_server(:dummy_ssl) { DummyServer.new(:ssl => true) }
         | 
| 5 7 |  | 
| 6 8 | 
             
              StubbedClient = Class.new(HTTP::Client) do
         | 
| 7 9 | 
             
                def perform(request, options)
         | 
| @@ -144,6 +146,38 @@ describe HTTP::Client do | |
| 144 146 | 
             
                end
         | 
| 145 147 | 
             
              end
         | 
| 146 148 |  | 
| 149 | 
            +
              describe 'SSL' do
         | 
| 150 | 
            +
                let(:client) do
         | 
| 151 | 
            +
                  described_class.new(
         | 
| 152 | 
            +
                    :ssl_context => OpenSSL::SSL::SSLContext.new.tap do |context|
         | 
| 153 | 
            +
                      context.options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                      context.verify_mode = OpenSSL::SSL::VERIFY_PEER
         | 
| 156 | 
            +
                      context.ca_file = File.join(certs_dir, 'ca.crt')
         | 
| 157 | 
            +
                      context.cert = OpenSSL::X509::Certificate.new(
         | 
| 158 | 
            +
                        File.read(File.join(certs_dir, 'client.crt'))
         | 
| 159 | 
            +
                      )
         | 
| 160 | 
            +
                      context.key = OpenSSL::PKey::RSA.new(
         | 
| 161 | 
            +
                        File.read(File.join(certs_dir, 'client.key'))
         | 
| 162 | 
            +
                      )
         | 
| 163 | 
            +
                      context
         | 
| 164 | 
            +
                    end
         | 
| 165 | 
            +
                  )
         | 
| 166 | 
            +
                end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                it 'works via SSL' do
         | 
| 169 | 
            +
                  response = client.get(dummy_ssl.endpoint)
         | 
| 170 | 
            +
                  expect(response.body.to_s).to eq('<!doctype html>')
         | 
| 171 | 
            +
                end
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                context 'with a mismatch host' do
         | 
| 174 | 
            +
                  it 'errors' do
         | 
| 175 | 
            +
                    expect { client.get(dummy_ssl.endpoint.gsub('127.0.0.1', 'localhost')) }
         | 
| 176 | 
            +
                      .to raise_error(OpenSSL::SSL::SSLError, /does not match/)
         | 
| 177 | 
            +
                  end
         | 
| 178 | 
            +
                end
         | 
| 179 | 
            +
              end
         | 
| 180 | 
            +
             | 
| 147 181 | 
             
              describe '#perform' do
         | 
| 148 182 | 
             
                let(:client) { described_class.new }
         | 
| 149 183 |  | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -14,6 +14,13 @@ require 'http' | |
| 14 14 | 
             
            require 'support/example_server'
         | 
| 15 15 | 
             
            require 'support/proxy_server'
         | 
| 16 16 |  | 
| 17 | 
            +
            # Allow testing against a SSL server
         | 
| 18 | 
            +
            def certs_dir
         | 
| 19 | 
            +
              Pathname.new File.expand_path('../../tmp/certs', __FILE__)
         | 
| 20 | 
            +
            end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            require 'support/create_certs'
         | 
| 23 | 
            +
             | 
| 17 24 | 
             
            RSpec.configure do |config|
         | 
| 18 25 | 
             
              config.expect_with :rspec do |c|
         | 
| 19 26 | 
             
                c.syntax = :expect
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            require 'fileutils'
         | 
| 2 | 
            +
            require 'certificate_authority'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            FileUtils.mkdir_p(certs_dir)
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            # Certificate Authority
         | 
| 8 | 
            +
            #
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            ca = CertificateAuthority::Certificate.new
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ca.subject.common_name  = 'honestachmed.com'
         | 
| 13 | 
            +
            ca.serial_number.number = 1
         | 
| 14 | 
            +
            ca.key_material.generate_key
         | 
| 15 | 
            +
            ca.signing_entity = true
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            ca.sign! 'extensions' => {'keyUsage' => {'usage' => %w[critical keyCertSign]}}
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            ca_cert_path = File.join(certs_dir, 'ca.crt')
         | 
| 20 | 
            +
            ca_key_path  = File.join(certs_dir, 'ca.key')
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            File.write ca_cert_path, ca.to_pem
         | 
| 23 | 
            +
            File.write ca_key_path,  ca.key_material.private_key.to_pem
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            #
         | 
| 26 | 
            +
            # Server Certificate
         | 
| 27 | 
            +
            #
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            server_cert = CertificateAuthority::Certificate.new
         | 
| 30 | 
            +
            server_cert.subject.common_name  = '127.0.0.1'
         | 
| 31 | 
            +
            server_cert.serial_number.number = 1
         | 
| 32 | 
            +
            server_cert.key_material.generate_key
         | 
| 33 | 
            +
            server_cert.parent = ca
         | 
| 34 | 
            +
            server_cert.sign!
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            server_cert_path = File.join(certs_dir, 'server.crt')
         | 
| 37 | 
            +
            server_key_path  = File.join(certs_dir, 'server.key')
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            File.write server_cert_path, server_cert.to_pem
         | 
| 40 | 
            +
            File.write server_key_path,  server_cert.key_material.private_key.to_pem
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            #
         | 
| 43 | 
            +
            # Client Certificate
         | 
| 44 | 
            +
            #
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            client_cert = CertificateAuthority::Certificate.new
         | 
| 47 | 
            +
            client_cert.subject.common_name  = '127.0.0.1'
         | 
| 48 | 
            +
            client_cert.serial_number.number = 1
         | 
| 49 | 
            +
            client_cert.key_material.generate_key
         | 
| 50 | 
            +
            client_cert.parent = ca
         | 
| 51 | 
            +
            client_cert.sign!
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            client_cert_path = File.join(certs_dir, 'client.crt')
         | 
| 54 | 
            +
            client_key_path  = File.join(certs_dir, 'client.key')
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            File.write client_cert_path, client_cert.to_pem
         | 
| 57 | 
            +
            File.write client_key_path,  client_cert.key_material.private_key.to_pem
         | 
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            require 'webrick'
         | 
| 2 | 
            +
            require 'webrick/ssl'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'support/black_hole'
         | 
| 5 | 
            +
            require 'support/dummy_server/servlet'
         | 
| 6 | 
            +
            require 'support/servers/config'
         | 
| 7 | 
            +
            require 'support/servers/runner'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            class DummyServer < WEBrick::HTTPServer
         | 
| 10 | 
            +
              include ServerConfig
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              CONFIG = {
         | 
| 13 | 
            +
                :BindAddress  => '127.0.0.1',
         | 
| 14 | 
            +
                :Port         => 0,
         | 
| 15 | 
            +
                :AccessLog    => BlackHole,
         | 
| 16 | 
            +
                :Logger       => BlackHole
         | 
| 17 | 
            +
              }.freeze
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def initialize(options = {})
         | 
| 20 | 
            +
                if options[:ssl]
         | 
| 21 | 
            +
                  override_config = {
         | 
| 22 | 
            +
                    :SSLEnable            => true,
         | 
| 23 | 
            +
                    :SSLStartImmediately  => true
         | 
| 24 | 
            +
                  }
         | 
| 25 | 
            +
                else
         | 
| 26 | 
            +
                  override_config = {}
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                super CONFIG.merge(override_config)
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                mount('/', Servlet)
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def endpoint
         | 
| 35 | 
            +
                "#{ssl? ? 'https' : 'http'}://#{addr}:#{port}"
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              def ssl_context
         | 
| 39 | 
            +
                @ssl_context ||= begin
         | 
| 40 | 
            +
                  context = OpenSSL::SSL::SSLContext.new
         | 
| 41 | 
            +
                  context.verify_mode = OpenSSL::SSL::VERIFY_PEER
         | 
| 42 | 
            +
                  context.key = OpenSSL::PKey::RSA.new(
         | 
| 43 | 
            +
                    File.read(File.join(certs_dir, 'server.key'))
         | 
| 44 | 
            +
                  )
         | 
| 45 | 
            +
                  context.cert = OpenSSL::X509::Certificate.new(
         | 
| 46 | 
            +
                    File.read(File.join(certs_dir, 'server.crt'))
         | 
| 47 | 
            +
                  )
         | 
| 48 | 
            +
                  context.ca_file = File.join(certs_dir, 'ca.crt')
         | 
| 49 | 
            +
                  context
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            class DummyServer < WEBrick::HTTPServer
         | 
| 2 | 
            +
              class Servlet < WEBrick::HTTPServlet::AbstractServlet
         | 
| 3 | 
            +
                def not_found(_req, res)
         | 
| 4 | 
            +
                  res.status = 404
         | 
| 5 | 
            +
                  res.body   = 'Not Found'
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def self.handlers
         | 
| 9 | 
            +
                  @handlers ||= {}
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                %w[get post head].each do |method|
         | 
| 13 | 
            +
                  class_eval <<-RUBY, __FILE__, __LINE__
         | 
| 14 | 
            +
                    def self.#{method}(path, &block)
         | 
| 15 | 
            +
                      handlers["#{method}:\#{path}"] = block
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                    def do_#{method.upcase}(req, res)
         | 
| 18 | 
            +
                      handler = self.class.handlers["#{method}:\#{req.path}"]
         | 
| 19 | 
            +
                      return instance_exec(req, res, &handler) if handler
         | 
| 20 | 
            +
                      not_found
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  RUBY
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                get '/' do |_req, res|
         | 
| 26 | 
            +
                  res.status = 200
         | 
| 27 | 
            +
                  res.body   = '<!doctype html>'
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module ServerRunner
         | 
| 2 | 
            +
              def run_server(name, &block)
         | 
| 3 | 
            +
                let! name do
         | 
| 4 | 
            +
                  server = block.call
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  Thread.new { server.start }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  server
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                after do
         | 
| 12 | 
            +
                  send(name).shutdown
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            RSpec.configure { |c| c.extend ServerRunner }
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: http
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.6. | 
| 4 | 
            +
              version: 0.6.4
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Tony
         | 
| @@ -9,7 +9,7 @@ authors: | |
| 9 9 | 
             
            autorequire: 
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date:  | 
| 12 | 
            +
            date: 2015-03-25 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: http_parser.rb
         | 
| @@ -109,8 +109,14 @@ files: | |
| 109 109 | 
             
            - spec/http/response_spec.rb
         | 
| 110 110 | 
             
            - spec/http_spec.rb
         | 
| 111 111 | 
             
            - spec/spec_helper.rb
         | 
| 112 | 
            +
            - spec/support/black_hole.rb
         | 
| 113 | 
            +
            - spec/support/create_certs.rb
         | 
| 114 | 
            +
            - spec/support/dummy_server.rb
         | 
| 115 | 
            +
            - spec/support/dummy_server/servlet.rb
         | 
| 112 116 | 
             
            - spec/support/example_server.rb
         | 
| 113 117 | 
             
            - spec/support/proxy_server.rb
         | 
| 118 | 
            +
            - spec/support/servers/config.rb
         | 
| 119 | 
            +
            - spec/support/servers/runner.rb
         | 
| 114 120 | 
             
            homepage: https://github.com/tarcieri/http
         | 
| 115 121 | 
             
            licenses:
         | 
| 116 122 | 
             
            - MIT
         |