about summary refs log tree commit homepage
path: root/lib/yahns/http_response.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/yahns/http_response.rb')
-rw-r--r--lib/yahns/http_response.rb38
1 files changed, 26 insertions, 12 deletions
diff --git a/lib/yahns/http_response.rb b/lib/yahns/http_response.rb
index b157ee4..32d1a45 100644
--- a/lib/yahns/http_response.rb
+++ b/lib/yahns/http_response.rb
@@ -4,12 +4,14 @@
 # frozen_string_literal: true
 require_relative 'stream_file'
 require_relative 'wbuf_str'
+require_relative 'chunk_body'
 
 # Writes a Rack response to your client using the HTTP/1.1 specification.
 # You use it by simply doing:
 #
+#   opt = http_response_prep(env)
 #   res = rack_app.call(env)
-#   http_response_write(res, env['REQUEST_METHOD']=='HEAD')
+#   http_response_write(res, opt)
 #
 # Most header correctness (including Content-Length and Content-Type)
 # is the job of Rack, with the exception of the "Date" header.
@@ -120,14 +122,14 @@ module Yahns::HttpResponse # :nodoc:
 
   # writes the rack_response to socket as an HTTP response
   # returns :wait_readable, :wait_writable, :forget, or nil
-  def http_response_write(res, hdr_only)
+  def http_response_write(res, opt)
     status, headers, body = res
     offset = 0
     count = hijack = nil
-    k = self.class
-    alive = @hs.next? && k.persistent_connections
+    alive = @hs.next? && self.class.persistent_connections
     flags = MSG_DONTWAIT
     term = false
+    hdr_only, chunk_ok = opt
 
     if @hs.headers?
       code = status.to_i
@@ -161,6 +163,11 @@ module Yahns::HttpResponse # :nodoc:
           kv_str(buf, key, value)
         end
       end
+      if !term && chunk_ok
+        term = true
+        body = Yahns::ChunkBody.new(body, opt)
+        buf << "Transfer-Encoding: chunked\r\n".freeze
+      end
       alive &&= term
       buf << (alive ? "Connection: keep-alive\r\n\r\n".freeze
                     : "Connection: close\r\n\r\n".freeze)
@@ -173,7 +180,7 @@ module Yahns::HttpResponse # :nodoc:
         flags = MSG_DONTWAIT
         buf = rv # unlikely, hope the skb grows
       when :wait_writable, :wait_readable # unlikely
-        if k.output_buffering
+        if self.class.output_buffering
           alive = hijack ? hijack : alive
           rv = response_header_blocked(buf, body, alive, offset, count)
           body = nil # ensure we do not close body in ensure
@@ -193,19 +200,19 @@ module Yahns::HttpResponse # :nodoc:
     end
 
     wbuf = rv = nil
-    body.each do |chunk|
+    body.each do |x|
       if wbuf
-        rv = wbuf.wbuf_write(self, chunk)
+        rv = wbuf.wbuf_write(self, x)
       else
-        case rv = kgio_trywrite(chunk)
+        case rv = String === x ? kgio_trywrite(x) : kgio_trywritev(x)
         when nil # all done, likely and good!
           break
-        when String
-          chunk = rv # hope the skb grows when we loop into the trywrite
+        when String, Array
+          x = rv # hope the skb grows when we loop into the trywrite
         when :wait_writable, :wait_readable
-          if k.output_buffering
+          if self.class.output_buffering
             wbuf = Yahns::Wbuf.new(body, alive)
-            rv = wbuf.wbuf_write(self, chunk)
+            rv = wbuf.wbuf_write(self, x)
             break
           else
             response_wait_write(rv) or return :close
@@ -278,4 +285,11 @@ module Yahns::HttpResponse # :nodoc:
       return rv
     end while true
   end
+
+  # must be called before app dispatch, since the app can
+  # do all sorts of nasty things to env
+  def http_response_prep(env)
+    [ env['REQUEST_METHOD'] == 'HEAD'.freeze, # hdr_only
+      env['HTTP_VERSION'] == 'HTTP/1.1'.freeze ] # chunk_ok
+  end
 end