module Puma::Request

def fast_write_response(socket, body, io_buffer, chunked, content_length)

Raises:
  • (ConnectionError) -

Parameters:
  • chunked (Boolean) --
  • io_buffer (Puma::IOBuffer) -- contains headers
  • body (Enumerable, File) -- the body object
  • socket (#write) -- the response socket
def fast_write_response(socket, body, io_buffer, chunked, content_length)
  if body.is_a?(::File) && body.respond_to?(:read)
    if chunked  # would this ever happen?
      while chunk = body.read(BODY_LEN_MAX)
        io_buffer.append chunk.bytesize.to_s(16), LINE_END, chunk, LINE_END
      end
      fast_write_str socket, CLOSE_CHUNKED
    else
      if content_length <= IO_BODY_MAX
        io_buffer.write body.read(content_length)
        fast_write_str socket, io_buffer.read_and_reset
      else
        fast_write_str socket, io_buffer.read_and_reset
        IO.copy_stream body, socket
      end
    end
  elsif body.is_a?(::Array) && body.length == 1
    body_first = nil
    # using body_first = body.first causes issues?
    body.each { |str| body_first ||= str }
    if body_first.is_a?(::String) && body_first.bytesize < BODY_LEN_MAX
      # smaller body, write to io_buffer first
      io_buffer.write body_first
      fast_write_str socket, io_buffer.read_and_reset
    else
      # large body, write both header & body to socket
      fast_write_str socket, io_buffer.read_and_reset
      fast_write_str socket, body_first
    end
  elsif body.is_a?(::Array)
    # for array bodies, flush io_buffer to socket when size is greater than
    # IO_BUFFER_LEN_MAX
    if chunked
      body.each do |part|
        next if (byte_size = part.bytesize).zero?
        io_buffer.append byte_size.to_s(16), LINE_END, part, LINE_END
        if io_buffer.length > IO_BUFFER_LEN_MAX
          fast_write_str socket, io_buffer.read_and_reset
        end
      end
      io_buffer.write CLOSE_CHUNKED
    else
      body.each do |part|
        next if part.bytesize.zero?
        io_buffer.write part
        if io_buffer.length > IO_BUFFER_LEN_MAX
          fast_write_str socket, io_buffer.read_and_reset
        end
      end
    end
    # may write last body part for non-chunked, also headers if array is empty
    fast_write_str(socket, io_buffer.read_and_reset) unless io_buffer.length.zero?
  else
    # for enum bodies
    if chunked
      empty_body = true
      body.each do |part|
        next if part.nil? || (byte_size = part.bytesize).zero?
        empty_body = false
        io_buffer.append byte_size.to_s(16), LINE_END, part, LINE_END
        fast_write_str socket, io_buffer.read_and_reset
      end
      if empty_body
        io_buffer << CLOSE_CHUNKED
        fast_write_str socket, io_buffer.read_and_reset
      else
        fast_write_str socket, CLOSE_CHUNKED
      end
    else
      fast_write_str socket, io_buffer.read_and_reset
      body.each do |part|
        next if part.bytesize.zero?
        fast_write_str socket, part
      end
    end
  end
  socket.flush
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
  raise ConnectionError, SOCKET_WRITE_ERR_MSG
rescue  Errno::EPIPE, SystemCallError, IOError
  raise ConnectionError, SOCKET_WRITE_ERR_MSG
end