unicorn.git  about / heads / tags
Rack HTTP server for Unix and fast clients
blob 13e9900ebed1029c5051a2bc8de9d5feac860e06 2529 bytes (raw)
$ git show v2.0.0pre1:lib/unicorn/http_request.rb	# shows this blob on the CLI

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
 
# -*- encoding: binary -*-

require 'unicorn_http'

class Unicorn::HttpRequest

  # default parameters we merge into the request env for Rack handlers
  DEFAULTS = {
    "rack.errors" => $stderr,
    "rack.multiprocess" => true,
    "rack.multithread" => false,
    "rack.run_once" => false,
    "rack.version" => [1, 1],
    "SCRIPT_NAME" => "",

    # this is not in the Rack spec, but some apps may rely on it
    "SERVER_SOFTWARE" => "Unicorn #{Unicorn::Const::UNICORN_VERSION}"
  }

  NULL_IO = StringIO.new("")

  # :stopdoc:
  # A frozen format for this is about 15% faster
  REMOTE_ADDR = 'REMOTE_ADDR'.freeze
  RACK_INPUT = 'rack.input'.freeze
  # :startdoc:

  attr_reader :env, :parser, :buf

  def initialize
    @parser = Unicorn::HttpParser.new
    @buf = ""
    @env = {}
  end

  def response_headers?
    @parser.headers?
  end

  # Does the majority of the IO processing.  It has been written in
  # Ruby using about 8 different IO processing strategies.
  #
  # It is currently carefully constructed to make sure that it gets
  # the best possible performance for the common case: GET requests
  # that are fully complete after a single read(2)
  #
  # Anyone who thinks they can make it faster is more than welcome to
  # take a crack at it.
  #
  # returns an environment hash suitable for Rack if successful
  # This does minimal exception trapping and it is up to the caller
  # to handle any socket errors (e.g. user aborted upload).
  def read(socket)
    @env.clear
    @parser.reset

    # From http://www.ietf.org/rfc/rfc3875:
    # "Script authors should be aware that the REMOTE_ADDR and
    #  REMOTE_HOST meta-variables (see sections 4.1.8 and 4.1.9)
    #  may not identify the ultimate source of the request.  They
    #  identify the client for the immediate request to the server;
    #  that client may be a proxy, gateway, or other intermediary
    #  acting on behalf of the actual source client."
    @env[REMOTE_ADDR] = socket.kgio_addr

    # short circuit the common case with small GET requests first
    if @parser.headers(@env, socket.kgio_read!(16384, @buf)).nil?
      # Parser is not done, queue up more data to read and continue parsing
      # an Exception thrown from the PARSER will throw us out of the loop
      begin
        @buf << socket.kgio_read!(16384)
      end while @parser.headers(@env, @buf).nil?
    end
    @env[RACK_INPUT] = 0 == @parser.content_length ?
                       NULL_IO : Unicorn::TeeInput.new(socket, self)
    @env.merge!(DEFAULTS)
  end
end

git clone https://yhbt.net/unicorn.git