about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-02-06 10:25:22 +0000
committerEric Wong <normalperson@yhbt.net>2011-02-06 10:42:18 +0000
commitd88a3f93dce4b75068c3137d8dd92009195d0576 (patch)
tree4af9d050f4be342b33df1459c64b563c68a71401
parentb702c53ad61c7eafef39de60d2afb9d3e856f1fa (diff)
downloadkcar-d88a3f93dce4b75068c3137d8dd92009195d0576.tar.gz
This minimizes allocations made at runtime and uses
ivars for faster access under 1.9
-rw-r--r--lib/kcar/response.rb87
1 files changed, 44 insertions, 43 deletions
diff --git a/lib/kcar/response.rb b/lib/kcar/response.rb
index 67e0286..4764d8b 100644
--- a/lib/kcar/response.rb
+++ b/lib/kcar/response.rb
@@ -1,14 +1,15 @@
 # -*- encoding: binary -*-
 
-module Kcar
 
 # This may be used to generate a Rack response
 #
-class Response < Struct.new(:sock, :hdr, :unchunk, :buf, :parser)
+class Kcar::Response
+  attr_accessor :sock, :hdr, :unchunk, :buf, :parser
 
   # :stopdoc:
   LAST_CHUNK = "0\r\n"
   CRLF = "\r\n"
+  Parser = Kcar::Parser
   # :startdoc:
 
   # By default we readpartial at most 16K off a socket at once
@@ -18,7 +19,7 @@ class Response < Struct.new(:sock, :hdr, :unchunk, :buf, :parser)
   # method.  +unchunk+ may be set to disable transparent unchunking
   # +hdr+ may be a Hash, Array, or Rack::Utils::HeaderHash
   def initialize(sock, hdr = {}, unchunk = true)
-    super(sock, hdr, unchunk, "", Parser.new)
+    @sock, @hdr, @unchunk, @buf, @parser = sock, hdr, unchunk, "", Parser.new
   end
 
   # returns a 3-element array that resembles a Rack response, but is
@@ -33,9 +34,9 @@ class Response < Struct.new(:sock, :hdr, :unchunk, :buf, :parser)
   # +unchunk+ must be true to guarantee trailers will be stored in the
   # returned +header+ object
   def read
-    buf << sock.readpartial(READ_SIZE) if buf.empty?
-    while (response = parser.headers(hdr, buf)).nil?
-      buf << sock.readpartial(READ_SIZE)
+    @buf << @sock.readpartial(READ_SIZE) if @buf.empty?
+    until response = @parser.headers(@hdr, @buf)
+      @buf << @sock.readpartial(READ_SIZE)
     end
     response << self
   end
@@ -47,7 +48,7 @@ class Response < Struct.new(:sock, :hdr, :unchunk, :buf, :parser)
   # but the body returned will be this Kcar::Response handler itself.
   # It is not guaranteed that trailers will be stored in the returned +header+
   def rack
-    self.unchunk = false
+    @unchunk = false
     read
   end
 
@@ -55,23 +56,25 @@ class Response < Struct.new(:sock, :hdr, :unchunk, :buf, :parser)
   # our given +sock+ object if keepalive is not used otherwise it
   # will just reset the parser and clear the header object
   def close
-    parser.keepalive? ? reset : sock.close
+    @parser.keepalive? ? reset : @sock.close
   end
 
   # this method allows our Kcar::Response object to be used as a Rack response
   # body.  It may only be called once (usually by a Rack server) as it streams
   # the response body off the our socket object.
-  def each(&block)
-    if parser.body_eof?
+  def each
+    if @parser.body_eof?
       return
     end
-    if unchunk
-      parser.chunked? ? each_unchunk(&block) : each_identity(&block)
+    if @unchunk
+      @parser.chunked? ? each_unchunk { |x| yield x } :
+                         each_identity { |x| yield x }
     else
-      if parser.keepalive?
-        parser.chunked? ? each_rechunk(&block) : each_identity(&block)
+      if @parser.keepalive?
+        @parser.chunked? ? each_rechunk { |x| yield x } :
+                           each_identity { |x| yield x }
       else
-        each_until_eof(&block) # fastest path
+        each_until_eof { |x| yield x } # fastest path
       end
     end
     rescue EOFError
@@ -79,11 +82,11 @@ class Response < Struct.new(:sock, :hdr, :unchunk, :buf, :parser)
 
   # :stopdoc:
   def reset
-    parser.reset
-    hdr.clear
+    @parser.reset
+    @hdr.clear
   end
 
-  def each_rechunk(&block)
+  def each_rechunk
     # We have to filter_body to keep track of parser state
     # (which sucks).  Also, as a benefit to clients we'll rechunk
     # to increase the likelyhood of network transfers being on
@@ -91,30 +94,30 @@ class Response < Struct.new(:sock, :hdr, :unchunk, :buf, :parser)
     # other people's code :)
     dst = ""
     begin
-      parser.filter_body(dst, buf) and break
+      @parser.filter_body(dst, @buf) and break
       size = dst.size
       if size > 0
         yield("#{size.to_s(16)}\r\n")
         yield(dst << CRLF)
       end
-      break if parser.body_eof?
-    end while buf << sock.readpartial(READ_SIZE, dst)
+      break if @parser.body_eof?
+    end while @buf << @sock.readpartial(READ_SIZE, dst)
 
     yield LAST_CHUNK
 
-    while parser.trailers(hdr, buf).nil?
-      buf << sock.readpartial(READ_SIZE, dst)
+    until @parser.trailers(@hdr, @buf)
+      @buf << @sock.readpartial(READ_SIZE, dst)
     end
 
     # since Rack does not provide a way to explicitly send trailers
     # in the response, we'll just yield a stringified version to our
     # server and pretend it's part of the body.
-    trailers = parser.extract_trailers(hdr)
+    trailers = @parser.extract_trailers(@hdr)
     yield(trailers.map! { |k,v| "#{k}: #{v}\r\n" }.join("") << CRLF)
   end
 
-  def each_until_eof(&block)
-    yield buf unless buf.empty?
+  def each_until_eof
+    yield @buf unless @buf.empty?
     # easy, just read and write everything until EOFError
     dst = sock.readpartial(READ_SIZE)
     begin
@@ -122,12 +125,12 @@ class Response < Struct.new(:sock, :hdr, :unchunk, :buf, :parser)
     end while sock.readpartial(READ_SIZE, dst)
   end
 
-  def each_identity(&block)
-    len = parser.body_bytes_left
-    if len.nil?
-      each_until_eof(&block)
+  def each_identity
+    len = @parser.body_bytes_left
+    if len == nil
+      each_until_eof { |x| yield x }
     else
-      dst = buf
+      dst = @buf
       if dst.size > 0
         # in case of keepalive we need to read the second response,
         # so modify buf so that the second response is at the front
@@ -135,7 +138,7 @@ class Response < Struct.new(:sock, :hdr, :unchunk, :buf, :parser)
         if dst.size >= len
           tmp = dst[len, dst.size]
           dst = dst[0, len]
-          buf.replace(tmp)
+          @buf.replace(tmp)
         end
 
         len -= dst.size
@@ -144,30 +147,28 @@ class Response < Struct.new(:sock, :hdr, :unchunk, :buf, :parser)
 
       if len > 0
         begin
-          len -= sock.readpartial(len > READ_SIZE ? READ_SIZE : len, dst).size
+          len -= @sock.readpartial(len > READ_SIZE ? READ_SIZE : len, dst).size
           yield dst
         end while len > 0
-        dst.respond_to?(:clear) ? dst.clear : self.buf = ''
+        dst.respond_to?(:clear) ? dst.clear : @buf = ""
       end
     end
   end
 
-  def each_unchunk(&block)
+  def each_unchunk
     dst = ""
     begin
-      parser.filter_body(dst, buf) and break
+      @parser.filter_body(dst, @buf) and break
       yield dst if dst.size > 0
-      parser.body_eof? and break
-    end while buf << sock.readpartial(READ_SIZE, dst)
+      @parser.body_eof? and break
+    end while @buf << @sock.readpartial(READ_SIZE, dst)
 
     # we can't pass trailers to the client since we unchunk
     # the response, so just read them off the socket and
     # stash them in hdr just in case...
-    while parser.headers(hdr, buf).nil?
-      buf << sock.readpartial(READ_SIZE, dst)
+    until parser.headers(@hdr, @buf)
+      @buf << @sock.readpartial(READ_SIZE, dst)
     end
   end
   # :startdoc:
-
-end # class Response
-end # module Kcar
+end