Hello community, here is the log from the commit of package rubygem-puma for openSUSE:Factory checked in at 2016-03-01 09:42:49 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-puma (Old) and /work/SRC/openSUSE:Factory/.rubygem-puma.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-puma" Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-puma/rubygem-puma.changes 2015-12-14 10:13:27.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.rubygem-puma.new/rubygem-puma.changes 2016-03-01 09:42:55.000000000 +0100 @@ -1,0 +2,46 @@ +Thu Jan 28 05:31:53 UTC 2016 - [email protected] + +- updated to version 2.16.0 + see installed History.txt + + === 2.16.0 / 2016-01-27 + + * 7 minor features: + + * Add 'set_remote_address' config option + * Allow to run puma in silent mode + * Expose cli options in DSL + * Support passing JRuby keystore info in ssl_bind DSL + * Allow umask for unix:/// style control urls + * Expose `old_worker_count` in stats url + * Support TLS client auth (verify_mode) in jruby + + * 7 bug fixes: + + * Don't persist before_fork hook in state file + * Reload bundler before pulling in rack. Fixes #859 + * Remove NEWRELIC_DISPATCHER env variable + * Cleanup C code + * Use Timeout.timeout instead of Object.timeout + * Make phased restarts faster + * Ignore the case of certain headers, because HTTP + + * 1 doc changes: + + * Test against the latest Ruby 2.1, 2.2, 2.3, head and JRuby 9.0.4.0 on Travis + + * 12 merged PRs + * Merge pull request #822 from kwugirl/remove_NEWRELIC_DISPATCHER + * Merge pull request #833 from joemiller/jruby-client-tls-auth + * Merge pull request #837 from YuriSolovyov/ssl-keystore-jruby + * Merge pull request #839 from mezuka/master + * Merge pull request #845 from deepj/timeout-deprecation + * Merge pull request #846 from sriedel/strip_before_fork + * Merge pull request #850 from deepj/travis + * Merge pull request #853 from Jeffrey6052/patch-1 + * Merge pull request #857 from zendesk/faster_phased_restarts + * Merge pull request #858 from mlarraz/fix_some_warnings + * Merge pull request #860 from zendesk/expose_old_worker_count + * Merge pull request #861 from zendesk/allow_control_url_umask + +------------------------------------------------------------------- Old: ---- puma-2.15.3.gem New: ---- puma-2.16.0.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-puma.spec ++++++ --- /var/tmp/diff_new_pack.GzfKX6/_old 2016-03-01 09:42:57.000000000 +0100 +++ /var/tmp/diff_new_pack.GzfKX6/_new 2016-03-01 09:42:57.000000000 +0100 @@ -1,7 +1,7 @@ # # spec file for package rubygem-puma # -# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -24,7 +24,7 @@ # Name: rubygem-puma -Version: 2.15.3 +Version: 2.16.0 Release: 0 %define mod_name puma %define mod_full_name %{mod_name}-%{version} ++++++ puma-2.15.3.gem -> puma-2.16.0.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/History.txt new/History.txt --- old/History.txt 2015-11-07 18:17:53.000000000 +0100 +++ new/History.txt 2016-01-28 04:56:44.000000000 +0100 @@ -1,3 +1,43 @@ +=== 2.16.0 / 2016-01-27 + +* 7 minor features: + + * Add 'set_remote_address' config option + * Allow to run puma in silent mode + * Expose cli options in DSL + * Support passing JRuby keystore info in ssl_bind DSL + * Allow umask for unix:/// style control urls + * Expose `old_worker_count` in stats url + * Support TLS client auth (verify_mode) in jruby + +* 7 bug fixes: + + * Don't persist before_fork hook in state file + * Reload bundler before pulling in rack. Fixes #859 + * Remove NEWRELIC_DISPATCHER env variable + * Cleanup C code + * Use Timeout.timeout instead of Object.timeout + * Make phased restarts faster + * Ignore the case of certain headers, because HTTP + +* 1 doc changes: + + * Test against the latest Ruby 2.1, 2.2, 2.3, head and JRuby 9.0.4.0 on Travis + +* 12 merged PRs + * Merge pull request #822 from kwugirl/remove_NEWRELIC_DISPATCHER + * Merge pull request #833 from joemiller/jruby-client-tls-auth + * Merge pull request #837 from YuriSolovyov/ssl-keystore-jruby + * Merge pull request #839 from mezuka/master + * Merge pull request #845 from deepj/timeout-deprecation + * Merge pull request #846 from sriedel/strip_before_fork + * Merge pull request #850 from deepj/travis + * Merge pull request #853 from Jeffrey6052/patch-1 + * Merge pull request #857 from zendesk/faster_phased_restarts + * Merge pull request #858 from mlarraz/fix_some_warnings + * Merge pull request #860 from zendesk/expose_old_worker_count + * Merge pull request #861 from zendesk/allow_control_url_umask + === 2.15.3 / 2015-11-07 * 1 bug fix: Files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ext/puma_http11/mini_ssl.c new/ext/puma_http11/mini_ssl.c --- old/ext/puma_http11/mini_ssl.c 2015-11-07 18:17:53.000000000 +0100 +++ new/ext/puma_http11/mini_ssl.c 2016-01-28 04:56:44.000000000 +0100 @@ -248,7 +248,7 @@ VALUE engine_read(VALUE self) { ms_conn* conn; char buf[512]; - int bytes, n, error; + int bytes, error; Data_Get_Struct(self, ms_conn, conn); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ext/puma_http11/org/jruby/puma/MiniSSL.java new/ext/puma_http11/org/jruby/puma/MiniSSL.java --- old/ext/puma_http11/org/jruby/puma/MiniSSL.java 2015-11-07 18:17:53.000000000 +0100 +++ new/ext/puma_http11/org/jruby/puma/MiniSSL.java 2016-01-28 04:56:44.000000000 +0100 @@ -13,6 +13,7 @@ import org.jruby.util.ByteList; import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; @@ -136,23 +137,36 @@ public IRubyObject initialize(ThreadContext threadContext, IRubyObject miniSSLContext) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException { KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); + KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType()); char[] password = miniSSLContext.callMethod(threadContext, "keystore_pass").convertToString().asJavaString().toCharArray(); - ks.load(new FileInputStream(miniSSLContext.callMethod(threadContext, "keystore").convertToString().asJavaString()), - password); + String keystoreFile = miniSSLContext.callMethod(threadContext, "keystore").convertToString().asJavaString(); + ks.load(new FileInputStream(keystoreFile), password); + ts.load(new FileInputStream(keystoreFile), password); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, password); + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(ts); + SSLContext sslCtx = SSLContext.getInstance("TLS"); - sslCtx.init(kmf.getKeyManagers(), null, null); + sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); engine = sslCtx.createSSLEngine(); String[] protocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" }; engine.setEnabledProtocols(protocols); engine.setUseClientMode(false); + long verify_mode = miniSSLContext.callMethod(threadContext, "verify_mode").convertToInteger().getLongValue(); + if ((verify_mode & 0x1) != 0) { // 'peer' + engine.setWantClientAuth(true); + } + if ((verify_mode & 0x2) != 0) { // 'force_peer' + engine.setNeedClientAuth(true); + } + SSLSession session = engine.getSession(); inboundNetData = new MiniSSLBuffer(session.getPacketBufferSize()); outboundAppData = new MiniSSLBuffer(session.getApplicationBufferSize()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/puma/cli.rb new/lib/puma/cli.rb --- old/lib/puma/cli.rb 2015-11-07 18:17:53.000000000 +0100 +++ new/lib/puma/cli.rb 2016-01-28 04:56:44.000000000 +0100 @@ -25,6 +25,12 @@ # Handles invoke a Puma::Server in a command line style. # class CLI + KEYS_NOT_TO_PERSIST_IN_STATE = [ + :logger, :lowlevel_error_handler, + :before_worker_shutdown, :before_worker_boot, :before_worker_fork, + :after_worker_boot, :before_fork, :on_restart + ] + # Create a new CLI object using +argv+ as the command line # arguments. # @@ -42,8 +48,6 @@ @config = nil - ENV['NEWRELIC_DISPATCHER'] ||= "Puma" - setup_options generate_restart_data @@ -108,12 +112,7 @@ state = { 'pid' => Process.pid } cfg = @config.dup - [ - :logger, - :before_worker_shutdown, :before_worker_boot, :before_worker_fork, - :after_worker_boot, - :on_restart, :lowlevel_error_handler - ].each { |k| cfg.options.delete(k) } + KEYS_NOT_TO_PERSIST_IN_STATE.each { |k| cfg.options.delete(k) } state['config'] = cfg require 'yaml' @@ -573,6 +572,7 @@ home = ENV['GEM_HOME'] Bundler.with_clean_env do ENV['GEM_HOME'] = home + ENV['PUMA_BUNDLER_PRUNED'] = '1' wild = File.expand_path(File.join(puma_lib_dir, "../bin/puma-wild")) args = [Gem.ruby, wild, '-I', dirs.join(':'), deps.join(',')] + @original_argv Kernel.exec(*args) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/puma/client.rb new/lib/puma/client.rb --- old/lib/puma/client.rb 2015-11-07 18:17:53.000000000 +0100 +++ new/lib/puma/client.rb 2016-01-28 04:56:44.000000000 +0100 @@ -45,11 +45,18 @@ @requests_served = 0 @hijacked = false + + @peerip = nil + @remote_addr_header = nil end attr_reader :env, :to_io, :body, :io, :timeout_at, :ready, :hijacked, :tempfile + attr_writer :peerip + + attr_accessor :remote_addr_header + def inspect "#<Puma::Client:0x#{object_id.to_s(16)} @ready=#{@ready.inspect}>" end @@ -297,5 +304,17 @@ rescue StandardError end end + + def peerip + return @peerip if @peerip + + if @remote_addr_header + hdr = (@env[@remote_addr_header] || LOCALHOST_ADDR).split(/[\s,]/).first + @peerip = hdr + return hdr + end + + @peerip ||= @io.peeraddr.last + end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/puma/cluster.rb new/lib/puma/cluster.rb --- old/lib/puma/cluster.rb 2015-11-07 18:17:53.000000000 +0100 +++ new/lib/puma/cluster.rb 2016-01-28 04:56:44.000000000 +0100 @@ -65,6 +65,14 @@ @stage = :booted end + def dead? + @dead + end + + def dead! + @dead = true + end + def ping! @last_checkin = Time.now end @@ -155,6 +163,8 @@ @workers.delete_if { |w| w.pid == pid } end + @workers.delete_if(&:dead?) + spawn_workers if all_workers_booted? @@ -242,6 +252,7 @@ hooks = @options[:before_worker_shutdown] hooks.each { |h| h.call(index) } ensure + @worker_write << "t#{Process.pid}\n" rescue nil @worker_write.close end @@ -284,7 +295,9 @@ end def stats - %Q!{ "workers": #{@workers.size}, "phase": #{@phase}, "booted_workers": #{@workers.count{|w| w.booted?}} }! + old_worker_count = @workers.count { |w| w.phase != @phase } + booted_worker_count = @workers.count { |w| w.booted? } + %Q!{ "workers": #{@workers.size}, "phase": #{@phase}, "booted_workers": #{booted_worker_count}, "old_workers": #{old_worker_count} }! end def preload? @@ -412,6 +425,9 @@ w.boot! log "- Worker #{w.index} (pid: #{pid}) booted, phase: #{w.phase}" force_check = true + when "t" + w.dead! + force_check = true when "p" w.ping! end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/puma/configuration.rb new/lib/puma/configuration.rb --- old/lib/puma/configuration.rb 2015-11-07 18:17:53.000000000 +0100 +++ new/lib/puma/configuration.rb 2016-01-28 04:56:44.000000000 +0100 @@ -29,6 +29,7 @@ @conf[:worker_timeout] ||= DefaultWorkerTimeout @conf[:worker_boot_timeout] ||= @conf[:worker_timeout] @conf[:worker_shutdown_timeout] ||= DefaultWorkerShutdownTimeout + @conf[:remote_address] ||= :socket @options = {} end @@ -54,6 +55,7 @@ end def load + @conf.merge! @cli_options DSL.load(@conf, @cli_options[:config_file]) # Load the options in the right priority @@ -127,6 +129,15 @@ # Load and use the normal Rack builder if we can, otherwise # fallback to our minimal version. def rack_builder + # Load bundler now if we can so that we can pickup rack from + # a Gemfile + if ENV.key? 'PUMA_BUNDLER_PRUNED' + begin + require 'bundler/setup' + rescue LoadError + end + end + begin require 'rack' require 'rack/builder' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/puma/const.rb new/lib/puma/const.rb --- old/lib/puma/const.rb 2015-11-07 18:17:53.000000000 +0100 +++ new/lib/puma/const.rb 2016-01-28 04:56:44.000000000 +0100 @@ -99,8 +99,8 @@ # too taxing on performance. module Const - PUMA_VERSION = VERSION = "2.15.3".freeze - CODE_NAME = "Autumn Arbor Airbrush".freeze + PUMA_VERSION = VERSION = "2.16.0".freeze + CODE_NAME = "Midwinter Nights Trance".freeze FAST_TRACK_KA_TIMEOUT = 0.2 @@ -183,6 +183,7 @@ PORT_443 = "443".freeze LOCALHOST = "localhost".freeze LOCALHOST_IP = "127.0.0.1".freeze + LOCALHOST_ADDR = "127.0.0.1:0".freeze SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze HTTP_11 = "HTTP/1.1".freeze @@ -215,11 +216,11 @@ HTTP_10_200 = "HTTP/1.0 200 OK\r\n".freeze CLOSE = "close".freeze - KEEP_ALIVE = "Keep-Alive".freeze + KEEP_ALIVE = "keep-alive".freeze - CONTENT_LENGTH2 = "Content-Length".freeze + CONTENT_LENGTH2 = "content-length".freeze CONTENT_LENGTH_S = "Content-Length: ".freeze - TRANSFER_ENCODING = "Transfer-Encoding".freeze + TRANSFER_ENCODING = "transfer-encoding".freeze CONNECTION_CLOSE = "Connection: close\r\n".freeze CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n".freeze diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/puma/dsl.rb new/lib/puma/dsl.rb --- old/lib/puma/dsl.rb 2015-11-07 18:17:53.000000000 +0100 +++ new/lib/puma/dsl.rb 2016-01-28 04:56:44.000000000 +0100 @@ -42,6 +42,7 @@ @options[:control_auth_token] = auth_token if auth_token @options[:control_auth_token] = :none if opts[:no_token] + @options[:control_url_umask] = opts[:umask] if opts[:umask] end end @@ -140,7 +141,12 @@ end def ssl_bind(host, port, opts) - @options[:binds] << "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}" + if defined?(JRUBY_VERSION) + keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}" + @options[:binds] << "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}" + else + @options[:binds] << "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}" + end end # Use +path+ as the file to store the server info state. This is @@ -297,5 +303,46 @@ def shutdown_debug(val=true) @options[:shutdown_debug] = val end + + # Control how the remote address of the connection is set. This + # is configurable because to calculate the true socket peer address + # a kernel syscall is required which for very fast rack handlers + # slows down the handling significantly. + # + # There are 4 possible values: + # + # * :socket (the default) - read the peername from the socket using the + # syscall. This is the normal behavior. + # * :localhost - set the remote address to "127.0.0.1" + # * header: http_header - set the remote address to the value of the + # provided http header. For instance: + # `set_remote_address header: "X-Real-IP"`. + # Only the first word (as separated by spaces or comma) + # is used, allowing headers such as X-Forwarded-For + # to be used as well. + # * Any string - this allows you to hardcode remote address to any value + # you wish. Because puma never uses this field anyway, it's + # format is entirely in your hands. + def set_remote_address(val=:socket) + case val + when :socket + @options[:remote_address] = val + when :localhost + @options[:remote_address] = :value + @options[:remote_address_value] = "127.0.0.1".freeze + when String + @options[:remote_address] = :value + @options[:remote_address_value] = val + when Hash + if hdr = val[:header] + @options[:remote_address] = :header + @options[:remote_address_header] = "HTTP_" + hdr.upcase.gsub("-", "_") + else + raise "Invalid value for set_remote_address - #{val.inspect}" + end + else + raise "Invalid value for set_remote_address - #{val}" + end + end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/puma/runner.rb new/lib/puma/runner.rb --- old/lib/puma/runner.rb 2015-11-07 18:17:53.000000000 +0100 +++ new/lib/puma/runner.rb 2016-01-28 04:56:44.000000000 +0100 @@ -52,8 +52,9 @@ when "unix" log "* Starting control server on #{str}" path = "#{uri.host}#{uri.path}" + mask = @options[:control_url_umask] - control.add_unix_listener path + control.add_unix_listener path, mask else error "Invalid control URI: #{str}" end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/puma/server.rb new/lib/puma/server.rb --- old/lib/puma/server.rb 2015-11-07 18:17:53.000000000 +0100 +++ new/lib/puma/server.rb 2016-01-28 04:56:44.000000000 +0100 @@ -307,6 +307,16 @@ pool = @thread_pool queue_requests = @queue_requests + remote_addr_value = nil + remote_addr_header = nil + + case @options[:remote_address] + when :value + remote_addr_value = @options[:remote_address_value] + when :header + remote_addr_header = @options[:remote_address_header] + end + while @status == :run begin ios = IO.select sockets @@ -317,6 +327,12 @@ begin if io = sock.accept_nonblock client = Client.new io, @binder.env(sock) + if remote_addr_value + client.peerip = remote_addr_value + elsif remote_addr_header + client.remote_addr_header = remote_addr_header + end + pool << client pool.wait_until_not_full unless queue_requests end @@ -481,7 +497,7 @@ unless env.key?(REMOTE_ADDR) begin - addr = client.peeraddr.last + addr = client.peerip rescue Errno::ENOTCONN # Client disconnects can result in an inability to get the # peeraddr from the socket; default to localhost. @@ -513,7 +529,7 @@ env = req.env client = req.io - normalize_env env, client + normalize_env env, req env[PUMA_SOCKET] = client @@ -571,7 +587,7 @@ http_11 = if env[HTTP_VERSION] == HTTP_11 allow_chunked = true - keep_alive = env[HTTP_CONNECTION] != CLOSE + keep_alive = env.fetch(HTTP_CONNECTION, "").downcase != CLOSE include_keepalive_header = false # An optimization. The most common response is 200, so we can @@ -589,7 +605,7 @@ true else allow_chunked = false - keep_alive = env[HTTP_CONNECTION] == KEEP_ALIVE + keep_alive = env.fetch(HTTP_CONNECTION, "").downcase == KEEP_ALIVE include_keepalive_header = keep_alive # Same optimization as above for HTTP/1.1 @@ -608,7 +624,7 @@ response_hijack = nil headers.each do |k, vs| - case k + case k.downcase when CONTENT_LENGTH2 content_length = vs next @@ -644,7 +660,7 @@ fast_write client, lines.to_s return keep_alive end - + if content_length lines.append CONTENT_LENGTH_S, content_length.to_s, line_ending chunked = false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rack/handler/puma.rb new/lib/rack/handler/puma.rb --- old/lib/rack/handler/puma.rb 2015-11-07 18:17:53.000000000 +0100 +++ new/lib/rack/handler/puma.rb 2016-01-28 04:56:44.000000000 +0100 @@ -8,7 +8,8 @@ :Host => '0.0.0.0', :Port => 8080, :Threads => '0:16', - :Verbose => false + :Verbose => false, + :Silent => false } def self.run(app, options = {}) @@ -22,13 +23,16 @@ ENV['RACK_ENV'] = options[:environment].to_s end - server = ::Puma::Server.new(app) + events_hander = options[:Silent] ? ::Puma::Events.strings : ::Puma::Events.stdio + server = ::Puma::Server.new(app, events_hander) min, max = options[:Threads].split(':', 2) - puts "Puma #{::Puma::Const::PUMA_VERSION} starting..." - puts "* Min threads: #{min}, max threads: #{max}" - puts "* Environment: #{ENV['RACK_ENV']}" - puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}" + log = events_hander.stdout + + log.puts "Puma #{::Puma::Const::PUMA_VERSION} starting..." + log.puts "* Min threads: #{min}, max threads: #{max}" + log.puts "* Environment: #{ENV['RACK_ENV']}" + log.puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}" server.add_tcp_listener options[:Host], options[:Port] server.min_threads = min @@ -38,9 +42,9 @@ begin server.run.join rescue Interrupt - puts "* Gracefully stopping, waiting for requests to finish" + log.puts "* Gracefully stopping, waiting for requests to finish" server.stop(true) - puts "* Goodbye!" + log.puts "* Goodbye!" end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2015-11-07 18:17:53.000000000 +0100 +++ new/metadata 2016-01-28 04:56:44.000000000 +0100 @@ -1,14 +1,14 @@ --- !ruby/object:Gem::Specification name: puma version: !ruby/object:Gem::Version - version: 2.15.3 + version: 2.16.0 platform: ruby authors: - Evan Phoenix autorequire: bindir: bin cert_chain: [] -date: 2015-11-07 00:00:00.000000000 Z +date: 2016-01-28 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: rdoc @@ -191,7 +191,7 @@ version: '0' requirements: [] rubyforge_project: -rubygems_version: 2.4.5 +rubygems_version: 2.5.1 signing_key: specification_version: 4 summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
