about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-01-02 22:29:12 +0000
committerEric Wong <e@80x24.org>2016-01-02 22:29:28 +0000
commit9e24bae3428f726800da2963a8f2695f7d4064cd (patch)
treedd4ce29efffa4f0da9c6d9ada903a277ec81196b
parent1105a6957eed26a922a27bd6e6dbbc457524b664 (diff)
downloadyahns-9e24bae3428f726800da2963a8f2695f7d4064cd.tar.gz
There are likely yet-to-be-discovered bugs in here.
Also, keeping explicit #freeze calls for 2.2 users, since most
users have not migrated to 2.3, yet.
-rwxr-xr-xGIT-VERSION-GEN5
-rwxr-xr-xbin/yahns1
-rwxr-xr-xbin/yahns-rackup1
-rw-r--r--extras/autoindex.rb1
-rw-r--r--extras/exec_cgi.rb1
-rw-r--r--extras/proxy_pass.rb7
-rw-r--r--extras/try_gzip_static.rb3
-rw-r--r--lib/yahns.rb1
-rw-r--r--lib/yahns/acceptor.rb1
-rw-r--r--lib/yahns/cap_input.rb1
-rw-r--r--lib/yahns/client_expire_generic.rb1
-rw-r--r--lib/yahns/client_expire_tcpi.rb1
-rw-r--r--lib/yahns/config.rb33
-rw-r--r--lib/yahns/daemon.rb1
-rw-r--r--lib/yahns/fdmap.rb1
-rw-r--r--lib/yahns/http_client.rb3
-rw-r--r--lib/yahns/http_context.rb3
-rw-r--r--lib/yahns/http_response.rb3
-rw-r--r--lib/yahns/log.rb1
-rw-r--r--lib/yahns/max_body.rb1
-rw-r--r--lib/yahns/max_body/rewindable_wrapper.rb3
-rw-r--r--lib/yahns/max_body/wrapper.rb11
-rw-r--r--lib/yahns/openssl_client.rb1
-rw-r--r--lib/yahns/openssl_server.rb1
-rw-r--r--lib/yahns/proxy_http_response.rb11
-rw-r--r--lib/yahns/proxy_pass.rb5
-rw-r--r--lib/yahns/queue.rb1
-rw-r--r--lib/yahns/queue_egg.rb1
-rw-r--r--lib/yahns/queue_epoll.rb3
-rw-r--r--lib/yahns/queue_kqueue.rb3
-rw-r--r--lib/yahns/queue_quitter.rb1
-rw-r--r--lib/yahns/queue_quitter_pipe.rb1
-rw-r--r--lib/yahns/rack.rb5
-rw-r--r--lib/yahns/rackup_handler.rb2
-rw-r--r--lib/yahns/sendfile_compat.rb3
-rw-r--r--lib/yahns/server.rb1
-rw-r--r--lib/yahns/server_mp.rb2
-rw-r--r--lib/yahns/sigevent.rb1
-rw-r--r--lib/yahns/sigevent_efd.rb1
-rw-r--r--lib/yahns/sigevent_pipe.rb1
-rw-r--r--lib/yahns/socket_helper.rb2
-rw-r--r--lib/yahns/stream_file.rb1
-rw-r--r--lib/yahns/stream_input.rb7
-rw-r--r--lib/yahns/tcp_server.rb1
-rw-r--r--lib/yahns/tee_input.rb3
-rw-r--r--lib/yahns/tmpio.rb1
-rw-r--r--lib/yahns/unix_server.rb1
-rw-r--r--lib/yahns/wbuf.rb1
-rw-r--r--lib/yahns/wbuf_common.rb1
-rw-r--r--lib/yahns/wbuf_str.rb1
-rw-r--r--lib/yahns/worker.rb1
-rw-r--r--test/covshow.rb1
-rw-r--r--test/helper.rb1
-rw-r--r--test/server_helper.rb1
-rw-r--r--test/test_bin.rb1
-rw-r--r--test/test_buffer_tmpdir.rb1
-rw-r--r--test/test_client_expire.rb5
-rw-r--r--test/test_client_max_body_size.rb3
-rw-r--r--test/test_config.rb1
-rw-r--r--test/test_expect_100.rb5
-rw-r--r--test/test_extras_autoindex.rb1
-rw-r--r--test/test_extras_exec_cgi.rb3
-rw-r--r--test/test_extras_proxy_pass.rb1
-rw-r--r--test/test_extras_try_gzip_static.rb1
-rw-r--r--test/test_fdmap.rb1
-rw-r--r--test/test_input.rb3
-rw-r--r--test/test_mt_accept.rb1
-rw-r--r--test/test_output_buffering.rb3
-rw-r--r--test/test_proxy_pass.rb25
-rw-r--r--test/test_rack.rb1
-rw-r--r--test/test_rack_hijack.rb1
-rw-r--r--test/test_reopen_logs.rb1
-rw-r--r--test/test_response.rb1
-rw-r--r--test/test_server.rb17
-rw-r--r--test/test_ssl.rb5
-rw-r--r--test/test_stream_file.rb1
-rw-r--r--test/test_tmpio.rb1
-rw-r--r--test/test_unix_socket.rb1
-rw-r--r--test/test_wbuf.rb1
79 files changed, 160 insertions, 76 deletions
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 608a76d..3109918 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,11 +1,12 @@
 #!/usr/bin/env ruby
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 CONSTANT = "Yahns::VERSION"
 RVF = "lib/yahns/version.rb"
 GVF = "GIT-VERSION-FILE"
 DEF_VER = "v1.11.0"
-vn = DEF_VER
+vn = DEF_VER.dup
 
 # First see if there is a version file (included in release tarballs),
 # then try git-describe, then default.
@@ -23,7 +24,7 @@ if File.exist?(".git")
 end
 
 vn = vn.sub!(/\Av/, "")
-new_ruby_version = "#{CONSTANT} = '#{vn}' # :nodoc:\n"
+new_ruby_version = "#{CONSTANT} = '#{vn}'.freeze # :nodoc:\n"
 cur_ruby_version = File.read(RVF) rescue nil
 if new_ruby_version != cur_ruby_version
   File.open(RVF, "w") { |fp| fp.write(new_ruby_version) }
diff --git a/bin/yahns b/bin/yahns
index 97210a4..340f145 100755
--- a/bin/yahns
+++ b/bin/yahns
@@ -2,6 +2,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require 'yahns/daemon'
 require 'optparse'
 config_file = daemonize = nil
diff --git a/bin/yahns-rackup b/bin/yahns-rackup
index 3c22725..fc1f161 100755
--- a/bin/yahns-rackup
+++ b/bin/yahns-rackup
@@ -2,6 +2,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require 'yahns/rackup_handler'
 ARGV.grep(/\A(?:-s|--server)/)[0] and abort "--server has no effect for #$0"
 ARGV[0, 0] = %w(-s yahns)
diff --git a/extras/autoindex.rb b/extras/autoindex.rb
index 1cfde7b..0e47fd4 100644
--- a/extras/autoindex.rb
+++ b/extras/autoindex.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require 'time'
 require 'rack/utils'
 require 'rack/request'
diff --git a/extras/exec_cgi.rb b/extras/exec_cgi.rb
index 3b63e93..c7f2ba9 100644
--- a/extras/exec_cgi.rb
+++ b/extras/exec_cgi.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv2 or later (https://www.gnu.org/licenses/gpl-2.0.txt)
+# frozen_string_literal: true
 #
 # if running under yahns, worker_processes is recommended to avoid conflicting
 # with the SIGCHLD handler in yahns.
diff --git a/extras/proxy_pass.rb b/extras/proxy_pass.rb
index 29dd995..ca5a6b2 100644
--- a/extras/proxy_pass.rb
+++ b/extras/proxy_pass.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require 'time'
 require 'socket'
 require 'kgio'
@@ -45,7 +46,7 @@ class ProxyPass # :nodoc:
       tout
     end
 
-    def readpartial(bytes, buf = Thread.current[:proxy_pass_buf] ||= "")
+    def readpartial(bytes, buf = Thread.current[:proxy_pass_buf] ||= ''.dup)
       case rv = kgio_read!(bytes, buf)
       when String
         @expiry += @timeout # bump expiry when we succeed
@@ -145,7 +146,7 @@ class ProxyPass # :nodoc:
     req = Rack::Request.new(env)
     path = @path.gsub(/\$(\w+)/) { req.__send__($1) }
     req = "#{request_method} #{path} HTTP/1.1\r\n" \
-          "X-Forwarded-For: #{env["REMOTE_ADDR"]}\r\n"
+          "X-Forwarded-For: #{env["REMOTE_ADDR"]}\r\n".dup
 
     # pass most HTTP_* headers through as-is
     chunked = false
@@ -198,7 +199,7 @@ class ProxyPass # :nodoc:
   end
 
   def send_body(input, ures, chunked)
-    buf = Thread.current[:proxy_pass_buf] ||= ""
+    buf = Thread.current[:proxy_pass_buf] ||= ''.dup
 
     if chunked # unlikely
       while input.read(16384, buf)
diff --git a/extras/try_gzip_static.rb b/extras/try_gzip_static.rb
index 4c6a59b..851744b 100644
--- a/extras/try_gzip_static.rb
+++ b/extras/try_gzip_static.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require 'time'
 require 'rack/utils'
 require 'rack/mime'
@@ -15,7 +16,7 @@ class TryGzipStatic
     # we actually hit this if serving the gzipped file in the first place,
     # _and_ Rack::Deflater is used in the middleware stack.  Oh well...
     def each
-      buf = ""
+      buf = ''.dup
       rsize = 8192
       if @sf_range
         file.seek(@sf_range.begin)
diff --git a/lib/yahns.rb b/lib/yahns.rb
index bbf86f2..b5f325b 100644
--- a/lib/yahns.rb
+++ b/lib/yahns.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 $stdout.sync = $stderr.sync = true
 
 require 'unicorn' # pulls in raindrops, kgio, fcntl, etc, stringio, and logger
diff --git a/lib/yahns/acceptor.rb b/lib/yahns/acceptor.rb
index 5745b73..6aea333 100644
--- a/lib/yahns/acceptor.rb
+++ b/lib/yahns/acceptor.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (see COPYING for details)
+# frozen_string_literal: true
 require_relative 'client_expire_tcpi'
 require_relative 'client_expire_generic'
 module Yahns::Acceptor # :nodoc:
diff --git a/lib/yahns/cap_input.rb b/lib/yahns/cap_input.rb
index a501958..ea0dc2d 100644
--- a/lib/yahns/cap_input.rb
+++ b/lib/yahns/cap_input.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv2 or later (https://www.gnu.org/licenses/gpl-2.0.txt)
+# frozen_string_literal: true
 
 # This is used as the @input/env["rack.input"] when
 # input_buffering == true or :lazy
diff --git a/lib/yahns/client_expire_generic.rb b/lib/yahns/client_expire_generic.rb
index 5ffc779..6625b83 100644
--- a/lib/yahns/client_expire_generic.rb
+++ b/lib/yahns/client_expire_generic.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 module Yahns::ClientExpireGeneric # :nodoc:
   def __timestamp
     Yahns.now
diff --git a/lib/yahns/client_expire_tcpi.rb b/lib/yahns/client_expire_tcpi.rb
index c310800..d8a6ca6 100644
--- a/lib/yahns/client_expire_tcpi.rb
+++ b/lib/yahns/client_expire_tcpi.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require 'raindrops'
 
 # included in Yahns::HttpClient
diff --git a/lib/yahns/config.rb b/lib/yahns/config.rb
index 2b71fe5..5f0a2fd 100644
--- a/lib/yahns/config.rb
+++ b/lib/yahns/config.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 #
 # Implements a DSL for configuring a yahns server.
 # See http://yahns.yhbt.net/examples/yahns_multi.conf.rb for a full
@@ -98,10 +99,10 @@ class Yahns::Config # :nodoc:
 
   %w(atfork_prepare atfork_parent atfork_child).each do |fn|
     eval(
-    %Q(def #{fn}(*args, &blk);) <<
-    %Q(  _check_in_block([:worker_processes,:app], :#{fn});) <<
-    %Q(  _add_hook(:#{fn}, block_given? ? blk : args[0]);) <<
-    %Q(end)
+    "def #{fn}(*args, &blk);" \
+    "  _check_in_block([:worker_processes,:app], :#{fn});" \
+    "  _add_hook(:#{fn}, block_given? ? blk : args[0]);" \
+    'end'
     )
   end
 
@@ -279,10 +280,10 @@ class Yahns::Config # :nodoc:
   # queue parameters (Yahns::QueueEgg)
   %w(max_events worker_threads).each do |_v|
     eval(
-    %Q(def #{_v}(val);) <<
-    %Q(  _check_in_block(:queue, :#{_v});) <<
-    %Q(  @block.ctx.__send__("#{_v}=", _check_int(:#{_v}, val, 1));) <<
-    %Q(end)
+    "def #{_v}(val);" \
+    "  _check_in_block(:queue, :#{_v});" \
+    "  @block.ctx.__send__(%Q(#{_v}=), _check_int(:#{_v}, val, 1));" \
+    'end'
     )
   end
 
@@ -345,10 +346,10 @@ class Yahns::Config # :nodoc:
   # boolean config directives for app
   %w(check_client_connection persistent_connections).each do |_v|
     eval(
-    %Q(def #{_v}(bool);) <<
-    %Q(  _check_in_block(:app, :#{_v});) <<
-    %Q(  @block.ctx.__send__("#{_v}=", _check_bool(:#{_v}, bool));) <<
-    %Q(end)
+    "def #{_v}(bool);" \
+    "  _check_in_block(:app, :#{_v});" \
+    "  @block.ctx.__send__(%Q(#{_v}=), _check_bool(:#{_v}, bool));" \
+    'end'
     )
   end
 
@@ -374,10 +375,10 @@ class Yahns::Config # :nodoc:
     client_header_buffer_size: 1,
   }.each do |_v,minval|
     eval(
-    %Q(def #{_v}(val);) <<
-    %Q(  _check_in_block(:app, :#{_v});) <<
-    %Q(  @block.ctx.__send__("#{_v}=", _check_int(:#{_v}, val, #{minval}));) <<
-    %Q(end)
+    "def #{_v}(val);" \
+    "  _check_in_block(:app, :#{_v});" \
+    "  @block.ctx.__send__(%Q(#{_v}=), _check_int(:#{_v}, val, #{minval}));" \
+    'end'
     )
   end
 
diff --git a/lib/yahns/daemon.rb b/lib/yahns/daemon.rb
index fde384c..3abf47f 100644
--- a/lib/yahns/daemon.rb
+++ b/lib/yahns/daemon.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2014, all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative '../yahns'
 
 module Yahns::Daemon # :nodoc:
diff --git a/lib/yahns/fdmap.rb b/lib/yahns/fdmap.rb
index 8ff1319..d930e3b 100644
--- a/lib/yahns/fdmap.rb
+++ b/lib/yahns/fdmap.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require 'thread'
 
 # only initialize this after forking, this is highly volatile and won't
diff --git a/lib/yahns/http_client.rb b/lib/yahns/http_client.rb
index 8a341f9..d8b4c6e 100644
--- a/lib/yahns/http_client.rb
+++ b/lib/yahns/http_client.rb
@@ -1,8 +1,9 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 class Yahns::HttpClient < Kgio::Socket # :nodoc:
-  NULL_IO = StringIO.new('') # :nodoc:
+  NULL_IO = StringIO.new.binmode # :nodoc:
 
   include Yahns::HttpResponse
   QEV_FLAGS = Yahns::Queue::QEV_RD # used by acceptor
diff --git a/lib/yahns/http_context.rb b/lib/yahns/http_context.rb
index eabc667..dc1c5d6 100644
--- a/lib/yahns/http_context.rb
+++ b/lib/yahns/http_context.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 
 # subclasses of Yahns::HttpClient will class extend this
 
@@ -79,7 +80,7 @@ module Yahns::HttpContext # :nodoc:
 
   def tmpio_for(len, env)
     # short requests are most common
-    return StringIO.new('') if len && len <= @client_body_buffer_size;
+    return StringIO.new.binmode if len && len <= @client_body_buffer_size;
 
     # too big or chunked, unknown length
     tmp = @input_buffer_tmpdir
diff --git a/lib/yahns/http_response.rb b/lib/yahns/http_response.rb
index 99bf664..57910b0 100644
--- a/lib/yahns/http_response.rb
+++ b/lib/yahns/http_response.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'stream_file'
 require_relative 'wbuf_str'
 
@@ -134,7 +135,7 @@ module Yahns::HttpResponse # :nodoc:
       code = status.to_i
       msg = Rack::Utils::HTTP_STATUS_CODES[code]
       buf = "#{response_start}#{msg ? %Q(#{code} #{msg}) : status}\r\n" \
-            "Date: #{httpdate}\r\n"
+            "Date: #{httpdate}\r\n".dup
       headers.each do |key, value|
         case key
         when %r{\ADate\z}i
diff --git a/lib/yahns/log.rb b/lib/yahns/log.rb
index b8015c4..990978f 100644
--- a/lib/yahns/log.rb
+++ b/lib/yahns/log.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 
 # logging-related utility functions for all of yahns
 module Yahns::Log # :nodoc:
diff --git a/lib/yahns/max_body.rb b/lib/yahns/max_body.rb
index 101a4fb..1ff4a76 100644
--- a/lib/yahns/max_body.rb
+++ b/lib/yahns/max_body.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv2 or later (https://www.gnu.org/licenses/gpl-2.0.txt)
+# frozen_string_literal: true
 
 # Middleware used to enforce client_max_body_size for TeeInput users.
 #
diff --git a/lib/yahns/max_body/rewindable_wrapper.rb b/lib/yahns/max_body/rewindable_wrapper.rb
index c8ea412..b7419e4 100644
--- a/lib/yahns/max_body/rewindable_wrapper.rb
+++ b/lib/yahns/max_body/rewindable_wrapper.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv2 or later (https://www.gnu.org/licenses/gpl-2.0.txt)
+# frozen_string_literal: true
 class Yahns::MaxBody::RewindableWrapper < Yahns::MaxBody::Wrapper # :nodoc:
   def initialize(rack_input, limit)
     @orig_limit = limit
@@ -9,7 +10,7 @@ class Yahns::MaxBody::RewindableWrapper < Yahns::MaxBody::Wrapper # :nodoc:
 
   def rewind
     @limit = @orig_limit
-    @rbuf = ''
+    @rbuf = ''.dup
     @input.rewind
   end
 
diff --git a/lib/yahns/max_body/wrapper.rb b/lib/yahns/max_body/wrapper.rb
index e618568..b8ed8a6 100644
--- a/lib/yahns/max_body/wrapper.rb
+++ b/lib/yahns/max_body/wrapper.rb
@@ -1,11 +1,14 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv2 or later (https://www.gnu.org/licenses/gpl-2.0.txt)
+# frozen_string_literal: true
 #
 # This is only used for chunked request bodies, which are rare
 class Yahns::MaxBody::Wrapper # :nodoc:
   def initialize(rack_input, limit)
-    @input, @limit, @rbuf = rack_input, limit, ''
+    @input = rack_input
+    @limit = limit
+    @rbuf = ''.dup
   end
 
   def each
@@ -16,7 +19,7 @@ class Yahns::MaxBody::Wrapper # :nodoc:
 
   # chunked encoding means this method behaves more like readpartial,
   # since Rack does not support a method named "readpartial"
-  def read(length = nil, rv = '')
+  def read(length = nil, rv = ''.dup)
     if length
       if length <= @rbuf.size
         length < 0 and raise ArgumentError, "negative length #{length} given"
@@ -53,7 +56,7 @@ class Yahns::MaxBody::Wrapper # :nodoc:
     end while true
   end
 
-  def checked_read(length = 16384, buf = '')
+  def checked_read(length = 16384, buf = ''.dup)
     if @input.read(length, buf)
       throw :yahns_EFBIG if ((@limit -= buf.size) < 0)
       return buf
@@ -62,7 +65,7 @@ class Yahns::MaxBody::Wrapper # :nodoc:
 
   def read_all
     rv = @rbuf.slice!(0, @rbuf.size)
-    tmp = ''
+    tmp = ''.dup
     while checked_read(16384, tmp)
       rv << tmp
     end
diff --git a/lib/yahns/openssl_client.rb b/lib/yahns/openssl_client.rb
index 246b407..c899f67 100644
--- a/lib/yahns/openssl_client.rb
+++ b/lib/yahns/openssl_client.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2014, all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (see COPYING for details)
+# frozen_string_literal: true
 
 require_relative 'sendfile_compat'
 
diff --git a/lib/yahns/openssl_server.rb b/lib/yahns/openssl_server.rb
index 3940892..ff372df 100644
--- a/lib/yahns/openssl_server.rb
+++ b/lib/yahns/openssl_server.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2014, all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (see COPYING for details)
+# frozen_string_literal: true
 
 require_relative 'acceptor'
 require_relative 'openssl_client'
diff --git a/lib/yahns/proxy_http_response.rb b/lib/yahns/proxy_http_response.rb
index 3858456..bfd6501 100644
--- a/lib/yahns/proxy_http_response.rb
+++ b/lib/yahns/proxy_http_response.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 
 # loaded by yahns/proxy_pass, this relies on Yahns::HttpResponse for
 # constants.
@@ -69,7 +70,7 @@ module Yahns::HttpResponse # :nodoc:
     alive = @hs.next? && self.class.persistent_connections
     response_headers = env['yahns.proxy_pass.response_headers']
 
-    res = "HTTP/1.1 #{msg ? %Q(#{code} #{msg}) : status}\r\n"
+    res = "HTTP/1.1 #{msg ? %Q(#{code} #{msg}) : status}\r\n".dup
     headers.each do |key,value| # n.b.: headers is an Array of 2-element Arrays
       case key
       when /\A(?:Connection|Keep-Alive)\z/i
@@ -123,7 +124,7 @@ module Yahns::HttpResponse # :nodoc:
 
       elsif kcar.chunked? # nasty chunked body
         req_res.proxy_trailers = nil # define to avoid warnings for now
-        buf = ''
+        buf = ''.dup
         case tmp = tip.shift || req_res.kgio_tryread(0x2000, rbuf)
         when String
           kcar.filter_body(buf, tmp)
@@ -136,7 +137,7 @@ module Yahns::HttpResponse # :nodoc:
 
         buf = tmp
         req_res.proxy_trailers = [ buf, tlr = [] ]
-        rbuf = Thread.current[:yahns_rbuf] = ''
+        rbuf = Thread.current[:yahns_rbuf] = ''.dup
         until kcar.trailers(tlr, buf)
           case rv = req_res.kgio_tryread(0x2000, rbuf)
           when String
@@ -186,7 +187,7 @@ module Yahns::HttpResponse # :nodoc:
       end while len != 0
 
     elsif kcar.chunked? # nasty chunked body
-      buf = ''
+      buf = ''.dup
 
       unless req_res.proxy_trailers
         # are we done dechunking the main body, yet?
@@ -200,7 +201,7 @@ module Yahns::HttpResponse # :nodoc:
           return :wait_readable # self remains in :ignore, wait on upstream
         end until kcar.body_eof?
         req_res.proxy_trailers = [ tmp, [] ] # onto trailers!
-        rbuf = Thread.current[:yahns_rbuf] = ''
+        rbuf = Thread.current[:yahns_rbuf] = ''.dup
       end
 
       buf, tlr = *req_res.proxy_trailers
diff --git a/lib/yahns/proxy_pass.rb b/lib/yahns/proxy_pass.rb
index 728ab3e..c8eec84 100644
--- a/lib/yahns/proxy_pass.rb
+++ b/lib/yahns/proxy_pass.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require 'socket'
 require 'kgio'
 require 'kcar' # gem install kcar
@@ -24,7 +25,7 @@ class Yahns::ProxyPass # :nodoc:
     # we must reinitialize the thread-local rbuf if it may get beyond the
     # current thread
     def detach_rbuf!
-      Thread.current[:yahns_rbuf] = ''
+      Thread.current[:yahns_rbuf] = ''.dup
     end
 
     def yahns_step # yahns event loop entry point
@@ -225,7 +226,7 @@ class Yahns::ProxyPass # :nodoc:
     end
 
     req = "#{env['REQUEST_METHOD']} #{req} #{ver}\r\n" \
-          "X-Forwarded-For: #{env["REMOTE_ADDR"]}\r\n"
+          "X-Forwarded-For: #{env["REMOTE_ADDR"]}\r\n".dup
 
     # pass most HTTP_* headers through as-is
     chunked = false
diff --git a/lib/yahns/queue.rb b/lib/yahns/queue.rb
index 2abdc27..b49ff35 100644
--- a/lib/yahns/queue.rb
+++ b/lib/yahns/queue.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2014, all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 if SleepyPenguin.const_defined?(:Epoll)
   require_relative 'queue_epoll'
 else
diff --git a/lib/yahns/queue_egg.rb b/lib/yahns/queue_egg.rb
index 0d62c2e..c8f1670 100644
--- a/lib/yahns/queue_egg.rb
+++ b/lib/yahns/queue_egg.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 
 # this represents a Yahns::Queue before its vivified.  This only
 # lives in the parent process and should be clobbered after qc_vivify
diff --git a/lib/yahns/queue_epoll.rb b/lib/yahns/queue_epoll.rb
index c685fae..ba32bdc 100644
--- a/lib/yahns/queue_epoll.rb
+++ b/lib/yahns/queue_epoll.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 #
 # This is the dangerous, low-level epoll interface for sleepy_penguin
 # It is safe as long as you're aware of all potential concurrency
@@ -32,7 +33,7 @@ class Yahns::Queue < SleepyPenguin::Epoll::IO # :nodoc:
   end
 
   def thr_init
-    Thread.current[:yahns_rbuf] = ""
+    Thread.current[:yahns_rbuf] = ''.dup
     Thread.current[:yahns_fdmap] = @fdmap
     Thread.current[:yahns_queue] = self
   end
diff --git a/lib/yahns/queue_kqueue.rb b/lib/yahns/queue_kqueue.rb
index 2636cee..73e25ad 100644
--- a/lib/yahns/queue_kqueue.rb
+++ b/lib/yahns/queue_kqueue.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 #
 # This is the dangerous, low-level kqueue interface for sleepy_penguin
 # It is safe as long as you're aware of all potential concurrency
@@ -41,7 +42,7 @@ class Yahns::Queue < SleepyPenguin::Kqueue::IO # :nodoc:
   end
 
   def thr_init
-    Thread.current[:yahns_rbuf] = ""
+    Thread.current[:yahns_rbuf] = ''.dup
     Thread.current[:yahns_fdmap] = @fdmap
     Thread.current[:yahns_queue] = self
   end
diff --git a/lib/yahns/queue_quitter.rb b/lib/yahns/queue_quitter.rb
index f91ff58..34dc922 100644
--- a/lib/yahns/queue_quitter.rb
+++ b/lib/yahns/queue_quitter.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 
 require 'sleepy_penguin'
 
diff --git a/lib/yahns/queue_quitter_pipe.rb b/lib/yahns/queue_quitter_pipe.rb
index a886957..e5806e9 100644
--- a/lib/yahns/queue_quitter_pipe.rb
+++ b/lib/yahns/queue_quitter_pipe.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 #
 # POSIX pipe version, see queue_quitter.rb for the (preferred) eventfd one
 class Yahns::QueueQuitter # :nodoc:
diff --git a/lib/yahns/rack.rb b/lib/yahns/rack.rb
index 3ec3582..a2af3b3 100644
--- a/lib/yahns/rack.rb
+++ b/lib/yahns/rack.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require 'rack'
 class Yahns::Rack # :nodoc:
   attr_reader :preload
@@ -62,10 +63,10 @@ class Yahns::Rack # :nodoc:
       "rack.run_once" => false,
       "rack.hijack?" => true,
       "rack.version" => [ 1, 2 ],
-      "SCRIPT_NAME" => "",
+      "SCRIPT_NAME" => ''.dup,
 
       # this is not in the Rack spec, but some apps may rely on it
-      "SERVER_SOFTWARE" => "yahns"
+      "SERVER_SOFTWARE" => 'yahns'.dup
     }
   end
 
diff --git a/lib/yahns/rackup_handler.rb b/lib/yahns/rackup_handler.rb
index 3d7beab..a0756bb 100644
--- a/lib/yahns/rackup_handler.rb
+++ b/lib/yahns/rackup_handler.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2014, all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative '../yahns'
 
 module Yahns::RackupHandler # :nodoc:
@@ -38,6 +39,7 @@ module Yahns::RackupHandler # :nodoc:
     Yahns::Server.new(cfg).start.join
   end
 
+  # this is called by Rack::Server
   def self.valid_options
     # these should be the most common options
     {
diff --git a/lib/yahns/sendfile_compat.rb b/lib/yahns/sendfile_compat.rb
index bd79c0c..c0269e9 100644
--- a/lib/yahns/sendfile_compat.rb
+++ b/lib/yahns/sendfile_compat.rb
@@ -1,12 +1,13 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 
 module Yahns::SendfileCompat # :nodoc:
   def trysendfile(io, offset, count)
     return 0 if count == 0
     count = 0x4000 if count > 0x4000
-    buf = Thread.current[:yahns_sfbuf] ||= ''
+    buf = Thread.current[:yahns_sfbuf] ||= ''.dup
     io.pos = offset
     str = io.read(count, buf) or return # nil for EOF
     n = 0
diff --git a/lib/yahns/server.rb b/lib/yahns/server.rb
index 2db8baf..441d9de 100644
--- a/lib/yahns/server.rb
+++ b/lib/yahns/server.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'queue_quitter'
 require_relative 'tcp_server'
 require_relative 'unix_server'
diff --git a/lib/yahns/server_mp.rb b/lib/yahns/server_mp.rb
index 6b5f4b6..f583812 100644
--- a/lib/yahns/server_mp.rb
+++ b/lib/yahns/server_mp.rb
@@ -1,6 +1,8 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
+
 module Yahns::ServerMP # :nodoc:
   EXIT_SIGS = [ :QUIT, :TERM, :INT ]
 
diff --git a/lib/yahns/sigevent.rb b/lib/yahns/sigevent.rb
index ff4ac27..b866ddd 100644
--- a/lib/yahns/sigevent.rb
+++ b/lib/yahns/sigevent.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 if SleepyPenguin.const_defined?(:EventFD)
   require_relative 'sigevent_efd'
 else
diff --git a/lib/yahns/sigevent_efd.rb b/lib/yahns/sigevent_efd.rb
index ce3bf1b..001e669 100644
--- a/lib/yahns/sigevent_efd.rb
+++ b/lib/yahns/sigevent_efd.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 class Yahns::Sigevent < SleepyPenguin::EventFD # :nodoc:
   include Kgio::DefaultWaiters
   def self.new
diff --git a/lib/yahns/sigevent_pipe.rb b/lib/yahns/sigevent_pipe.rb
index cfdab37..59ac808 100644
--- a/lib/yahns/sigevent_pipe.rb
+++ b/lib/yahns/sigevent_pipe.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 class Yahns::Sigevent # :nodoc:
   attr_reader :to_io
   def initialize
diff --git a/lib/yahns/socket_helper.rb b/lib/yahns/socket_helper.rb
index c786801..3fa5ab6 100644
--- a/lib/yahns/socket_helper.rb
+++ b/lib/yahns/socket_helper.rb
@@ -1,6 +1,8 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
+
 # this is only meant for Yahns::Server
 module Yahns::SocketHelper # :nodoc:
 
diff --git a/lib/yahns/stream_file.rb b/lib/yahns/stream_file.rb
index acc9f12..834e30e 100644
--- a/lib/yahns/stream_file.rb
+++ b/lib/yahns/stream_file.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'wbuf_common'
 
 class Yahns::StreamFile # :nodoc:
diff --git a/lib/yahns/stream_input.rb b/lib/yahns/stream_input.rb
index c913ae4..8c0964e 100644
--- a/lib/yahns/stream_input.rb
+++ b/lib/yahns/stream_input.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv2 or later (https://www.gnu.org/licenses/gpl-2.0.txt)
+# frozen_string_literal: true
 
 # When processing uploads, Yahns may expose a StreamInput object under
 # "rack.input" of the (future) Rack (2.x) environment.
@@ -12,7 +13,7 @@ class Yahns::StreamInput # :nodoc:
     @client = client
     @parser = request
     @buf = request.buf
-    @rbuf = ''
+    @rbuf = ''.dup
     @bytes_read = 0
     filter_body(@rbuf, @buf) unless @buf.empty?
   end
@@ -36,7 +37,7 @@ class Yahns::StreamInput # :nodoc:
   # ios.read(length [, buffer]) will return immediately if there is
   # any data and only block when nothing is available (providing
   # IO#readpartial semantics).
-  def read(length = nil, rv = '')
+  def read(length = nil, rv = ''.dup)
     if length
       if length <= @rbuf.size
         length < 0 and raise ArgumentError, "negative length #{length} given"
@@ -79,7 +80,7 @@ class Yahns::StreamInput # :nodoc:
   def gets
     sep = $/
     if sep.nil?
-      read_all(rv = '')
+      read_all(rv = ''.dup)
       return rv.empty? ? nil : rv
     end
     re = /\A(.*?#{Regexp.escape(sep)})/
diff --git a/lib/yahns/tcp_server.rb b/lib/yahns/tcp_server.rb
index 20e1a35..a836d1f 100644
--- a/lib/yahns/tcp_server.rb
+++ b/lib/yahns/tcp_server.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (see COPYING for details)
+# frozen_string_literal: true
 require_relative 'acceptor'
 class Yahns::TCPServer < Kgio::TCPServer # :nodoc:
   include Yahns::Acceptor
diff --git a/lib/yahns/tee_input.rb b/lib/yahns/tee_input.rb
index 31ad9cc..7b69f13 100644
--- a/lib/yahns/tee_input.rb
+++ b/lib/yahns/tee_input.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv2 or later (https://www.gnu.org/licenses/gpl-2.0.txt)
+# frozen_string_literal: true
 
 # acts like tee(1) on an input input to provide a input-like stream
 # while providing rewindable semantics through a File/StringIO backing
@@ -96,7 +97,7 @@ class Yahns::TeeInput < Yahns::StreamInput # :nodoc:
 
   # consumes the stream of the socket
   def consume!
-    junk = ""
+    junk = ''.dup
     rsize = __rsize
     nil while read(rsize, junk)
   end
diff --git a/lib/yahns/tmpio.rb b/lib/yahns/tmpio.rb
index dae3b30..33dc710 100644
--- a/lib/yahns/tmpio.rb
+++ b/lib/yahns/tmpio.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv2 or later (https://www.gnu.org/licenses/gpl-2.0.txt)
+# frozen_string_literal: true
 require 'tmpdir'
 
 # some versions of Ruby had a broken Tempfile which didn't work
diff --git a/lib/yahns/unix_server.rb b/lib/yahns/unix_server.rb
index 9a4e72e..eb6d6a0 100644
--- a/lib/yahns/unix_server.rb
+++ b/lib/yahns/unix_server.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (see COPYING for details)
+# frozen_string_literal: true
 require_relative 'acceptor'
 class Yahns::UNIXServer < Kgio::UNIXServer # :nodoc:
   include Yahns::Acceptor
diff --git a/lib/yahns/wbuf.rb b/lib/yahns/wbuf.rb
index 1a24aab..565ac2d 100644
--- a/lib/yahns/wbuf.rb
+++ b/lib/yahns/wbuf.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'wbuf_common'
 
 # This class is triggered whenever we need write buffering for clients
diff --git a/lib/yahns/wbuf_common.rb b/lib/yahns/wbuf_common.rb
index 8d81c0b..e80068b 100644
--- a/lib/yahns/wbuf_common.rb
+++ b/lib/yahns/wbuf_common.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 begin
   raise LoadError, "SENDFILE_BROKEN env set" if ENV["SENDFILE_BROKEN"]
   require 'sendfile'
diff --git a/lib/yahns/wbuf_str.rb b/lib/yahns/wbuf_str.rb
index 89dfd33..47c34b4 100644
--- a/lib/yahns/wbuf_str.rb
+++ b/lib/yahns/wbuf_str.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'wbuf_common'
 
 # we only use this for buffering the tiniest responses (which are already
diff --git a/lib/yahns/worker.rb b/lib/yahns/worker.rb
index d6e7364..14aba5f 100644
--- a/lib/yahns/worker.rb
+++ b/lib/yahns/worker.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 class Yahns::Worker # :nodoc:
   attr_accessor :nr
   attr_reader :to_io
diff --git a/test/covshow.rb b/test/covshow.rb
index 1d6367d..63f37ee 100644
--- a/test/covshow.rb
+++ b/test/covshow.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 #
 # this works with the __covmerge method in test/helper.rb
 # run this file after all tests are run
diff --git a/test/helper.rb b/test/helper.rb
index 5dca23f..445a0e6 100644
--- a/test/helper.rb
+++ b/test/helper.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 $stdout.sync = $stderr.sync = Thread.abort_on_exception = true
 $-w = true if RUBY_VERSION.to_f >= 2.0
 require 'thread'
diff --git a/test/server_helper.rb b/test/server_helper.rb
index cc34f4a..16a3ae3 100644
--- a/test/server_helper.rb
+++ b/test/server_helper.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'helper'
 require 'timeout'
 require 'socket'
diff --git a/test/test_bin.rb b/test/test_bin.rb
index 97e672e..20031b3 100644
--- a/test/test_bin.rb
+++ b/test/test_bin.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 class TestBin < Testcase
   ENV["N"].to_i > 1 and parallelize_me!
diff --git a/test/test_buffer_tmpdir.rb b/test/test_buffer_tmpdir.rb
index f1af602..0c5fa5f 100644
--- a/test/test_buffer_tmpdir.rb
+++ b/test/test_buffer_tmpdir.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 require 'sleepy_penguin'
 
diff --git a/test/test_client_expire.rb b/test/test_client_expire.rb
index 0260850..9cc85c2 100644
--- a/test/test_client_expire.rb
+++ b/test/test_client_expire.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 
 class TestClientExpire < Testcase
@@ -53,7 +54,7 @@ class TestClientExpire < Testcase
     s = get_tcp_client(host, port)
     req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
     s.write(req)
-    str = ""
+    str = ''.dup
     Timeout.timeout(20) { str << s.readpartial(666) until str =~ /\r\n\r\n/ }
     assert_match(%r{keep-alive}, str)
     sleep 2
@@ -113,7 +114,7 @@ class TestClientExpire < Testcase
     s = get_tcp_client(host, port)
     req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
     s.write(req)
-    str = ""
+    str = ''.dup
     Timeout.timeout(20) { str << s.readpartial(666) until str =~ /\r\n\r\n/ }
     assert_match(%r{keep-alive}, str)
     sleep 1
diff --git a/test/test_client_max_body_size.rb b/test/test_client_max_body_size.rb
index 8be2856..9ea91ad 100644
--- a/test/test_client_max_body_size.rb
+++ b/test/test_client_max_body_size.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 
 class TestClientMaxBodySize < Testcase
@@ -11,7 +12,7 @@ class TestClientMaxBodySize < Testcase
 
   DRAINER = lambda do |e|
     input = e["rack.input"]
-    buf = ""
+    buf = ''.dup
     nr = 0
     while rv = input.read(16384, buf)
       nr += rv.size
diff --git a/test/test_config.rb b/test/test_config.rb
index 08c33db..088a253 100644
--- a/test/test_config.rb
+++ b/test/test_config.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'helper'
 require 'rack/lobster'
 
diff --git a/test/test_expect_100.rb b/test/test_expect_100.rb
index 1701bca..f34c29e 100644
--- a/test/test_expect_100.rb
+++ b/test/test_expect_100.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 
 class TestExpect100 < Testcase
@@ -161,8 +162,8 @@ class TestExpect100 < Testcase
     end
     c = get_tcp_client(host, port)
     if body.size > 0
-      r = "PUT / HTTP/1.0\r\nExpect: 100-continue\r\n"
-      r << "Content-Length: #{body.size}\r\n\r\n#{body}"
+      r = "PUT / HTTP/1.0\r\nExpect: 100-continue\r\n" \
+          "Content-Length: #{body.size}\r\n\r\n#{body}"
     else
       r = "PUT / HTTP/1.0\r\nExpect: 100-continue\r\n\r\n"
     end
diff --git a/test/test_extras_autoindex.rb b/test/test_extras_autoindex.rb
index 5471598..998b280 100644
--- a/test/test_extras_autoindex.rb
+++ b/test/test_extras_autoindex.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 require 'zlib'
 require 'time'
diff --git a/test/test_extras_exec_cgi.rb b/test/test_extras_exec_cgi.rb
index a9bcd34..5b2f2ff 100644
--- a/test/test_extras_exec_cgi.rb
+++ b/test/test_extras_exec_cgi.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 
 # note: we use worker_processes to avoid polling/excessive wakeup issues
@@ -160,7 +161,7 @@ class TestExtrasExecCGI < Testcase
         poke_until_dead exec_pid
       when 11 # pid of executable, persistent
         c.write "GET /pid HTTP/1.0\r\nConnection: keep-alive\r\n\r\n"
-        buf = ""
+        buf = ''.dup
         begin
           buf << c.readpartial(666)
         end until buf =~ /\r\n\r\n\d+\n/
diff --git a/test/test_extras_proxy_pass.rb b/test/test_extras_proxy_pass.rb
index 851b6aa..cda302a 100644
--- a/test/test_extras_proxy_pass.rb
+++ b/test/test_extras_proxy_pass.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 begin
   require 'kcar'
diff --git a/test/test_extras_try_gzip_static.rb b/test/test_extras_try_gzip_static.rb
index 874f700..7051d68 100644
--- a/test/test_extras_try_gzip_static.rb
+++ b/test/test_extras_try_gzip_static.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 require 'zlib'
 require 'time'
diff --git a/test/test_fdmap.rb b/test/test_fdmap.rb
index e611862..05eac07 100644
--- a/test/test_fdmap.rb
+++ b/test/test_fdmap.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'helper'
 
 class TestFdmap < Testcase
diff --git a/test/test_input.rb b/test/test_input.rb
index add7598..802e099 100644
--- a/test/test_input.rb
+++ b/test/test_input.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 require 'digest/md5'
 
@@ -22,7 +23,7 @@ class TestInput < Testcase
       abort "unrecognized input type: #{input.class}"
     end
 
-    buf = ""
+    buf = ''.dup
     md5 = Digest::MD5.new
     while input.read(16384, buf)
       md5 << buf
diff --git a/test/test_mt_accept.rb b/test/test_mt_accept.rb
index fb02430..9f28078 100644
--- a/test/test_mt_accept.rb
+++ b/test/test_mt_accept.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 require 'rack/lobster'
 
diff --git a/test/test_output_buffering.rb b/test/test_output_buffering.rb
index 7f75702..8134b53 100644
--- a/test/test_output_buffering.rb
+++ b/test/test_output_buffering.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 require 'digest/md5'
 require 'rack/file'
@@ -88,7 +89,7 @@ class TestOutputBuffering < Testcase
 
   def md5sum(c)
     dig = Digest::MD5.new
-    buf = ""
+    buf = ''.dup
     nr = 0
     while c.read(8192, buf)
       dig << buf
diff --git a/test/test_proxy_pass.rb b/test/test_proxy_pass.rb
index 7f752e3..29c5a61 100644
--- a/test/test_proxy_pass.rb
+++ b/test/test_proxy_pass.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 require 'json'
 require 'digest'
@@ -390,9 +391,9 @@ class TestProxyPass < Testcase
 
   def check_pipelining(host, port)
     pl = TCPSocket.new(host, port)
-    r1 = ''
-    r2 = ''
-    r3 = ''
+    r1 = ''.dup
+    r2 = ''.dup
+    r3 = ''.dup
     Timeout.timeout(60) do
       pl.write "GET / HTTP/1.1\r\nHost: example.com\r\n\r\nGET /"
       until r1 =~ /hi\n/
@@ -415,7 +416,7 @@ class TestProxyPass < Testcase
 
       # ensure stuff still works after a chunked upload:
       pl.write "GET / HTTP/1.1\r\nHost: example.com\r\n\r\nP"
-      after_up = ''
+      after_up = ''.dup
       until after_up =~ /hi\n/
         after_up << pl.readpartial(666)
       end
@@ -426,7 +427,7 @@ class TestProxyPass < Testcase
       pl.write "UT / HTTP/1.1\r\nHost: example.com\r\n"
       pl.write "Content-Length: 8\r\n\r\n"
       pl.write "identity"
-      identity = ''
+      identity = ''.dup
 
       until identity =~ /identity/
         identity << pl.readpartial(666)
@@ -436,7 +437,7 @@ class TestProxyPass < Testcase
 
       # ensure stuff still works after an identity upload:
       pl.write "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
-      after_up = ''
+      after_up = ''.dup
       until after_up =~ /hi\n/
         after_up << pl.readpartial(666)
       end
@@ -509,8 +510,8 @@ class TestProxyPass < Testcase
     s = TCPSocket.new(host, port)
     s.write "GET /giant-body HTTP/1.0\r\n\r\n"
     sleep 0.1
-    str = ''
-    buf = ''
+    str = ''.dup
+    buf = ''.dup
     assert_raises(EOFError) { loop { str << s.readpartial(400, buf) } }
     h, b = str.split(/\r\n\r\n/, 2)
     assert_equal OMFG, b
@@ -523,8 +524,8 @@ class TestProxyPass < Testcase
     s = TCPSocket.new(host, port)
     s.write "GET /big-headers HTTP/1.1\r\nHost: example.com\r\n\r\n"
     s.write "HEAD /big-headers HTTP/1.0\r\n\r\n"
-    buf = ''
-    res = ''
+    buf = ''.dup
+    res = ''.dup
     sleep 0.1
     begin
       res << s.readpartial(32786, buf)
@@ -552,8 +553,8 @@ class TestProxyPass < Testcase
         s = TCPSocket.new(host, port)
         s.write "GET /response-trailer HTTP/1.1\r\n#{x}" \
                 "Host: example.com\r\n\r\n"
-        res = ''
-        buf = ''
+        res = ''.dup
+        buf = ''.dup
         Timeout.timeout(60) do
           until res =~ /Foo: bar\r\n\r\n\z/
             res << s.readpartial(16384, buf)
diff --git a/test/test_rack.rb b/test/test_rack.rb
index f601425..82a5fb7 100644
--- a/test/test_rack.rb
+++ b/test/test_rack.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'helper'
 require 'rack/lobster'
 require 'yahns/rack'
diff --git a/test/test_rack_hijack.rb b/test/test_rack_hijack.rb
index d326bcd..23858b8 100644
--- a/test/test_rack_hijack.rb
+++ b/test/test_rack_hijack.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 
 class TestRackHijack < Testcase
diff --git a/test/test_reopen_logs.rb b/test/test_reopen_logs.rb
index f8aa7b8..e4e076b 100644
--- a/test/test_reopen_logs.rb
+++ b/test/test_reopen_logs.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 require 'rack/commonlogger'
 
diff --git a/test/test_response.rb b/test/test_response.rb
index 19adbd6..a46c286 100644
--- a/test/test_response.rb
+++ b/test/test_response.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 
 class TestResponse < Testcase
diff --git a/test/test_server.rb b/test/test_server.rb
index c753919..a2c5ea2 100644
--- a/test/test_server.rb
+++ b/test/test_server.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 
 class TestServer < Testcase
@@ -25,7 +26,7 @@ class TestServer < Testcase
     # test pipelining
     r = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
     c.write(r + r)
-    buf = ""
+    buf = ''.dup
     Timeout.timeout(10) do
       until buf =~ /HI.+HI/m
         buf << c.readpartial(4096)
@@ -34,7 +35,7 @@ class TestServer < Testcase
 
     # trickle pipelining
     c.write(r + "GET ")
-    buf = ""
+    buf = ''.dup
     Timeout.timeout(10) do
       until buf =~ /HI\z/
         buf << c.readpartial(4096)
@@ -91,7 +92,7 @@ class TestServer < Testcase
     buf = "PUT / HTTP/1.1\r\nContent-Length: 2\r\n\r\nHI"
     c = get_tcp_client(host, port)
     c.write(buf + buf)
-    buf = ""
+    buf = ''.dup
     Timeout.timeout(10) do
       until buf =~ /HI.+HI/m
         buf << c.readpartial(4096)
@@ -110,7 +111,7 @@ class TestServer < Testcase
       sleep(0.01) if b.chr == ":"
       Thread.pass
     end
-    buf = ""
+    buf = ''.dup
     Timeout.timeout(10) do
       until buf =~ /HIBYE.+HIBYE/m
         buf << c.readpartial(4096)
@@ -709,7 +710,7 @@ class TestServer < Testcase
     c = get_tcp_client(host, port)
     c.write "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
     assert_equal c, c.wait(30)
-    buf = ""
+    buf = ''.dup
     re = /\r\n\r\nOK\z/
     Timeout.timeout(30) do
       begin
@@ -781,7 +782,7 @@ class TestServer < Testcase
 
     # normal response
     c.write "GET /keep-alive HTTP/1.1\r\nHost: example.com\r\n\r\n"
-    buf = ""
+    buf = ''.dup
     Timeout.timeout(30) do
       buf << c.readpartial(4096) until buf =~ /HI\z/
     end
@@ -790,7 +791,7 @@ class TestServer < Testcase
 
     # we allow whatever in the response, but don't send it
     c.write "GET /whatever HTTP/1.1\r\nHost: example.com\r\n\r\n"
-    buf = ""
+    buf = ''.dup
     Timeout.timeout(30) do
       buf << c.readpartial(4096) until buf =~ /HI\z/
     end
@@ -798,7 +799,7 @@ class TestServer < Testcase
     assert_raises(Errno::EAGAIN,IO::WaitReadable) { c.read_nonblock(666) }
 
     c.write "GET /close HTTP/1.1\r\nHost: example.com\r\n\r\n"
-    buf = ""
+    buf = ''.dup
     Timeout.timeout(30) do
       buf << c.readpartial(4096) until buf =~ /HI\z/
     end
diff --git a/test/test_ssl.rb b/test/test_ssl.rb
index c54cc3c..1379e93 100644
--- a/test/test_ssl.rb
+++ b/test/test_ssl.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2014,  all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 require 'openssl'
 class TestSSL < Testcase
@@ -72,7 +73,7 @@ AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC
     end
     client = ssl_client(host, port)
     client.write("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
-    buf = ''
+    buf = ''.dup
     Timeout.timeout(60) do
       buf << client.readpartial(111) until buf =~ /HI\z/
     end
@@ -104,7 +105,7 @@ AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC
             when "remote_address\n"
               s.puts(s.remote_address.inspect)
             when "each\n"
-              line = ''
+              line = ''.dup
               s.each do |l|
                 l.strip!
                 line << l
diff --git a/test/test_stream_file.rb b/test/test_stream_file.rb
index 4bc3b2e..4219836 100644
--- a/test/test_stream_file.rb
+++ b/test/test_stream_file.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'helper'
 require 'timeout'
 
diff --git a/test/test_tmpio.rb b/test/test_tmpio.rb
index 79c9f32..5e49cce 100644
--- a/test/test_tmpio.rb
+++ b/test/test_tmpio.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2009-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-2.0.txt)
+# frozen_string_literal: true
 require_relative 'helper'
 
 class TestTmpIO < Testcase
diff --git a/test/test_unix_socket.rb b/test/test_unix_socket.rb
index 712e99f..3bda4df 100644
--- a/test/test_unix_socket.rb
+++ b/test/test_unix_socket.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'server_helper'
 
 class TestUnixSocket < Testcase
diff --git a/test/test_wbuf.rb b/test/test_wbuf.rb
index 0d7959c..4905eff 100644
--- a/test/test_wbuf.rb
+++ b/test/test_wbuf.rb
@@ -1,5 +1,6 @@
 # Copyright (C) 2013-2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# frozen_string_literal: true
 require_relative 'helper'
 require 'timeout'