lib/puma/server.rb
def handle_request(env, client, body, cl)
      normalize_env env, client

      if cl
        body = read_body env, client, body, cl
        return false unless body
      else
        body = EmptyBody
      end

      env[RACK_INPUT] = body
      env[RACK_URL_SCHEME] =  env[HTTPS_KEY] ? HTTPS : HTTP

      # A rack extension. If the app writes #call'ables to this
      # array, we will invoke them when the request is done.
      #
      after_reply = env[RACK_AFTER_REPLY] = []

      begin
        begin
          status, headers, res_body = @app.call(env)

          if status == -1
            unless headers.empty? and res_body == []
              raise "async response must have empty headers and body"
            end

            return :async
          end
        rescue => e
          status, headers, res_body = lowlevel_error(e)
        end

        content_length = nil
        no_body = false

        if res_body.kind_of? Array and res_body.size == 1
          content_length = res_body[0].bytesize
        end

        cork_socket client

        if env[HTTP_VERSION] == HTTP_11
          allow_chunked = true
          keep_alive = env[HTTP_CONNECTION] != CLOSE
          include_keepalive_header = false

          # An optimization. The most common response is 200, so we can
          # reply with the proper 200 status without having to compute
          # the response header.
          #
          if status == 200
            client.write HTTP_11_200
          else
            client.write "HTTP/1.1 "
            client.write status.to_s
            client.write " "
            client.write HTTP_STATUS_CODES[status]
            client.write "\r\n"

            no_body = status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
          end
        else
          allow_chunked = false
          keep_alive = env[HTTP_CONNECTION] == KEEP_ALIVE
          include_keepalive_header = keep_alive

          # Same optimization as above for HTTP/1.1
          #
          if status == 200
            client.write HTTP_10_200
          else
            client.write "HTTP/1.1 "
            client.write status.to_s
            client.write " "
            client.write HTTP_STATUS_CODES[status]
            client.write "\r\n"

            no_body = status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
          end
        end

        colon = COLON
        line_ending = LINE_END

        headers.each do |k, vs|
          case k
          when CONTENT_LENGTH2
            content_length = vs
            next
          when TRANSFER_ENCODING
            allow_chunked = false
            content_length = nil
          when CONTENT_TYPE
            next if no_body
          end

          vs.split(NEWLINE).each do |v|
            client.write k
            client.write colon
            client.write v
            client.write line_ending
          end
        end

        if no_body
          client.write line_ending
          return keep_alive
        end

        if include_keepalive_header
          client.write CONNECTION_KEEP_ALIVE
        elsif !keep_alive
          client.write CONNECTION_CLOSE
        end

        if content_length
          client.write CONTENT_LENGTH_S
          client.write content_length.to_s
          client.write line_ending
          chunked = false
        elsif allow_chunked
          client.write TRANSFER_ENCODING_CHUNKED
          chunked = true
        end

        client.write line_ending

        res_body.each do |part|
          if chunked
            client.write part.bytesize.to_s(16)
            client.write line_ending
            client.write part
            client.write line_ending
          else
            client.write part
          end

          client.flush
        end

        if chunked
          client.write CLOSE_CHUNKED
          client.flush
        end

      ensure
        uncork_socket client

        body.close
        res_body.close if res_body.respond_to? :close

        after_reply.each { |o| o.call }
      end

      return keep_alive
    end
# Given the request +env+ from +client+ and a partial request body
# in +body+, finish reading the body if there is one and invoke
# the rack app. Then construct the response and write it back to
# +client+
#
# +cl+ is the previously fetched Content-Length header if there
# was one. This is an optimization to keep from having to look
# it up again.
#


+cl+ is the previously fetched Content-Length header if there
was one. This is an optimization to keep from having to look
it up again.
+ cl + is the previously fetched Content - Length header if there was one . This is an optimization to keep from having to look it up again .
def handle_request(env, client, body, cl)
      normalize_env env, client
      if cl
        body = read_body env, client, body, cl
        return false unless body
      else
        body = EmptyBody
      end
      env[RACK_INPUT] = body
      env[RACK_URL_SCHEME] =  env[HTTPS_KEY] ? HTTPS : HTTP
      after_reply = env[RACK_AFTER_REPLY] = []
      begin
        begin
          status, headers, res_body = @app.call(env)
          if status == -1
            unless headers.empty? and res_body == []
              raise "async response must have empty headers and body"
            end
            return :async
          end
        rescue => e
          status, headers, res_body = lowlevel_error(e)
        end
        content_length = nil
        no_body = false
        if res_body.kind_of? Array and res_body.size == 1
          content_length = res_body[0].bytesize
        end
        cork_socket client
        if env[HTTP_VERSION] == HTTP_11
          allow_chunked = true
          keep_alive = env[HTTP_CONNECTION] != CLOSE
          include_keepalive_header = false
           An optimization. The most common response is 200, so we can
           reply with the proper 200 status without having to compute
           the response header.
          if status == 200
            client.write HTTP_11_200
          else
            client.write "HTTP/1.1 "
            client.write status.to_s
            client.write " "
            client.write HTTP_STATUS_CODES[status]
            client.write "\r\n"
            no_body = status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
          end
        else
          allow_chunked = false
          keep_alive = env[HTTP_CONNECTION] == KEEP_ALIVE
          include_keepalive_header = keep_alive
           Same optimization as above for HTTP/1.1
          if status == 200
            client.write HTTP_10_200
          else
            client.write "HTTP/1.1 "
            client.write status.to_s
            client.write " "
            client.write HTTP_STATUS_CODES[status]
            client.write "\r\n"
            no_body = status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
          end
        end
        colon = COLON
        line_ending = LINE_END
        headers.each do |k, vs|
          case k
          when CONTENT_LENGTH2
            content_length = vs
            next
          when TRANSFER_ENCODING
            allow_chunked = false
            content_length = nil
          when CONTENT_TYPE
            next if no_body
          end
          vs.split(NEWLINE).each do |v|
            client.write k
            client.write colon
            client.write v
            client.write line_ending
          end
        end
        if no_body
          client.write line_ending
          return keep_alive
        end
        if include_keepalive_header
          client.write CONNECTION_KEEP_ALIVE
        elsif !keep_alive
          client.write CONNECTION_CLOSE
        end
        if content_length
          client.write CONTENT_LENGTH_S
          client.write content_length.to_s
          client.write line_ending
          chunked = false
        elsif allow_chunked
          client.write TRANSFER_ENCODING_CHUNKED
          chunked = true
        end
        client.write line_ending
        res_body.each do |part|
          if chunked
            client.write part.bytesize.to_s(16)
            client.write line_ending
            client.write part
            client.write line_ending
          else
            client.write part
          end
          client.flush
        end
        if chunked
          client.write CLOSE_CHUNKED
          client.flush
        end
      ensure
        uncork_socket client
        body.close
        res_body.close if res_body.respond_to? :close
        after_reply.each { |o| o.call }
      end
      return keep_alive
    end
def handle_request ( env , client , body , cl ) normalize_env env , client if cl body = read_body env , client , body , cl return false unless body else body = EmptyBody end env [ RACK_INPUT ] = body env [ RACK_URL_SCHEME ] = env [ HTTPS_KEY ] ? HTTPS : HTTP after_reply = env [ RACK_AFTER_REPLY ] = [ ] begin begin status , headers , res_body = @app . call ( env ) if status == - 1 unless headers . empty? and res_body == [ ] raise "async response must have empty headers and body" end return :async end rescue => e status , headers , res_body = lowlevel_error ( e ) end content_length = nil no_body = false if res_body . kind_of? Array and res_body . size == 1 content_length = res_body [ 0 ] . bytesize end cork_socket client if env [ HTTP_VERSION ] == HTTP_11 allow_chunked = true keep_alive = env [ HTTP_CONNECTION ] != CLOSE include_keepalive_header = false if status == 200 client . write HTTP_11_200 else client . write "HTTP/1.1 " client . write status . to_s client . write " " client . write HTTP_STATUS_CODES [ status ] client . write "\r\n" no_body = status < 200 || STATUS_WITH_NO_ENTITY_BODY [ status ] end else allow_chunked = false keep_alive = env [ HTTP_CONNECTION ] == KEEP_ALIVE include_keepalive_header = keep_alive if status == 200 client . write HTTP_10_200 else client . write "HTTP/1.1 " client . write status . to_s client . write " " client . write HTTP_STATUS_CODES [ status ] client . write "\r\n" no_body = status < 200 || STATUS_WITH_NO_ENTITY_BODY [ status ] end end colon = COLON line_ending = LINE_END headers . each do | k , vs | case k when CONTENT_LENGTH2 content_length = vs next when TRANSFER_ENCODING allow_chunked = false content_length = nil when CONTENT_TYPE next if no_body end vs . split ( NEWLINE ) . each do | v | client . write k client . write colon client . write v client . write line_ending end end if no_body client . write line_ending return keep_alive end if include_keepalive_header client . write CONNECTION_KEEP_ALIVE elsif ! keep_alive client . write CONNECTION_CLOSE end if content_length client . write CONTENT_LENGTH_S client . write content_length . to_s client . write line_ending chunked = false elsif allow_chunked client . write TRANSFER_ENCODING_CHUNKED chunked = true end client . write line_ending res_body . each do | part | if chunked client . write part . bytesize . to_s ( 16 ) client . write line_ending client . write part client . write line_ending else client . write part end client . flush end if chunked client . write CLOSE_CHUNKED client . flush end ensure uncork_socket client body . close res_body . close if res_body . respond_to? :close after_reply . each { | o | o . call } end return keep_alive end
Given the request +env+ from +client+ and a partial request body
in +body+, finish reading the body if there is one and invoke
the rack app.
Given the request + env + from + client + and a partial request body in + body + finish reading the body if there is one and invoke the rack app .
# A rack extension. If the app writes #call'ables to this # array, we will invoke them when the request is done. # # An optimization. The most common response is 200, so we can # reply with the proper 200 status without having to compute # the response header. # # Same optimization as above for HTTP/1.1 #
env
client
body
cl