module Puma::Request

def prepare_response(status, headers, res_body, requests, client)

Returns:
  • (Boolean, :async) - keep-alive status or `:async`

Parameters:
  • client (Puma::Client) --
  • requests (Integer) -- number of inline requests handled
  • res_body (Array) -- the body returned by the Rack application or
  • headers (Hash) -- the headers returned by the Rack application
  • status (Integer) -- the status returned by the Rack application
def prepare_response(status, headers, res_body, requests, client)
  env = client.env
  socket = client.io
  io_buffer = client.io_buffer
  return false if closed_socket?(socket)
  # Close the connection after a reasonable number of inline requests
  # if the server is at capacity and the listener has a new connection ready.
  # This allows Puma to service connections fairly when the number
  # of concurrent connections exceeds the size of the threadpool.
  force_keep_alive = if @enable_keep_alives
    requests < @max_fast_inline ||
    @thread_pool.busy_threads < @max_threads ||
    !client.listener.to_io.wait_readable(0)
  else
    # Always set force_keep_alive to false if the server has keep-alives not enabled.
    false
  end
  resp_info = str_headers(env, status, headers, res_body, io_buffer, force_keep_alive)
  close_body = false
  response_hijack = nil
  content_length = resp_info[:content_length]
  keep_alive     = resp_info[:keep_alive]
  if res_body.respond_to?(:each) && !resp_info[:response_hijack]
    # below converts app_body into body, dependent on app_body's characteristics, and
    # content_length will be set if it can be determined
    if !content_length && !resp_info[:transfer_encoding] && status != 204
      if res_body.respond_to?(:to_ary) && (array_body = res_body.to_ary) &&
          array_body.is_a?(Array)
        body = array_body.compact
        content_length = body.sum(&:bytesize)
      elsif res_body.is_a?(File) && res_body.respond_to?(:size)
        body = res_body
        content_length = body.size
      elsif res_body.respond_to?(:to_path) && (fn = res_body.to_path) &&
          File.readable?(fn)
        body = File.open fn, 'rb'
        content_length = body.size
        close_body = true
      else
        body = res_body
      end
    elsif !res_body.is_a?(::File) && res_body.respond_to?(:to_path) &&
        (fn = res_body.to_path) && File.readable?(fn = res_body.to_path)
      body = File.open fn, 'rb'
      content_length = body.size
      close_body = true
    elsif !res_body.is_a?(::File) && res_body.respond_to?(:filename) &&
        res_body.respond_to?(:bytesize) && File.readable?(fn = res_body.filename)
      # Sprockets::Asset
      content_length = res_body.bytesize unless content_length
      if (body_str = res_body.to_hash[:source])
        body = [body_str]
      else                           # avoid each and use a File object
        body = File.open fn, 'rb'
        close_body = true
      end
    else
      body = res_body
    end
  else
    # partial hijack, from Rack spec:
    #   Servers must ignore the body part of the response tuple when the
    #   rack.hijack response header is present.
    response_hijack = resp_info[:response_hijack] || res_body
  end
  line_ending = LINE_END
  cork_socket socket
  if resp_info[:no_body]
    # 101 (Switching Protocols) doesn't return here or have content_length,
    # it should be using `response_hijack`
    unless status == 101
      if content_length && status != 204
        io_buffer.append CONTENT_LENGTH_S, content_length.to_s, line_ending
      end
      io_buffer << LINE_END
      fast_write_str socket, io_buffer.read_and_reset
      socket.flush
      return keep_alive
    end
  else
    if content_length
      io_buffer.append CONTENT_LENGTH_S, content_length.to_s, line_ending
      chunked = false
    elsif !response_hijack && resp_info[:allow_chunked]
      io_buffer << TRANSFER_ENCODING_CHUNKED
      chunked = true
    end
  end
  io_buffer << line_ending
  # partial hijack, we write headers, then hand the socket to the app via
  # response_hijack.call
  if response_hijack
    fast_write_str socket, io_buffer.read_and_reset
    uncork_socket socket
    response_hijack.call socket
    return :async
  end
  fast_write_response socket, body, io_buffer, chunked, content_length.to_i
  body.close if close_body
  keep_alive
end