Class: Rack::Handler::SingleShot

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/singleshot.rb

Constant Summary collapse

CRLF =
"\r\n"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, stdin, stdout) ⇒ SingleShot

Returns a new instance of SingleShot.



19
20
21
# File 'lib/rack/singleshot.rb', line 19

def initialize(app, stdin, stdout)
  @app, @stdin, @stdout = app, stdin, stdout
end

Class Method Details

.run(app, options = {}) ⇒ Object



9
10
11
12
13
14
15
16
17
# File 'lib/rack/singleshot.rb', line 9

def self.run(app, options = {})
  stdin   = options.fetch(:stdin, $stdin)
  stdout  = options.fetch(:stdout, $stdout)

  stdin.binmode = true  if stdin.respond_to?(:binmode=)
  stdout.binmode = true if stdout.respond_to?(:binmode=)

  new(app, stdin, stdout).run
end

Instance Method Details

#env_for(verb, path, query_string, version, headers, body) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/rack/singleshot.rb', line 98

def env_for(verb, path, query_string, version, headers, body)
  env = headers

  scheme = ['yes', 'on', '1'].include?(env['HTTPS']) ? 'https' : 'http'
  host   = env['SERVER_NAME'] || env['HTTP_HOST']

  uri = URI.parse([scheme, '://', host, path].join)

  env.update 'REQUEST_METHOD' => verb
  env.update 'SCRIPT_NAME'    => ''
  env.update 'PATH_INFO'      => uri.path
  env.update 'QUERY_STRING'   => query_string
  env.update 'SERVER_NAME'    => uri.host
  env.update 'SERVER_PORT'    => uri.port.to_s

  env.update 'rack.version'       => Rack::VERSION
  env.update 'rack.url_scheme'    => uri.scheme
  env.update 'rack.input'         => body
  env.update 'rack.errors'        => $stderr
  env.update 'rack.multithread'   => false
  env.update 'rack.multiprocess'  => false
  env.update 'rack.run_once'      => true

  env
end

#header_key(key) ⇒ Object



76
77
78
79
80
# File 'lib/rack/singleshot.rb', line 76

def header_key(key)
  key = key.upcase.gsub('-', '_')

  %w[CONTENT_TYPE CONTENT_LENGTH SERVER_NAME].include?(key) ? key : "HTTP_#{key}"
end

#parse_headers(raw_headers) ⇒ Object



70
71
72
73
74
# File 'lib/rack/singleshot.rb', line 70

def parse_headers(raw_headers)
  raw_headers.inject({}) do |h, (key,value)|
    h.update(header_key(key) => value)
  end
end

#parse_request(socket, chunksize = 1024) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/rack/singleshot.rb', line 41

def parse_request(socket, chunksize = 1024)
  finished = false
  body     = StringIO.new('')
  parser   = Http::Parser.new

  body.set_encoding(Encoding::ASCII_8BIT) if body.respond_to?(:set_encoding)

  parser.on_message_complete = lambda { finished = true }
  parser.on_body = lambda {|data| body << data }

  while(chunk = socket.readpartial(chunksize))
    parser << chunk

    break if finished
  end

  return request_parts_from(parser) << body
rescue EOFError
  return request_parts_from(parser) << body
end

#read_requestObject



35
36
37
38
39
# File 'lib/rack/singleshot.rb', line 35

def read_request
  verb, path, query_string, version, headers, body = parse_request(@stdin)

  env_for(verb, path, query_string, version, headers, body)
end

#request_parts_from(parser) ⇒ Object



62
63
64
65
66
67
68
# File 'lib/rack/singleshot.rb', line 62

def request_parts_from(parser)
  [parser.http_method,
   parser.request_path,
   parser.query_string,
   parser.http_version.join('.'),
   parse_headers(parser.headers)]
end

#runObject



23
24
25
26
27
28
29
30
31
32
# File 'lib/rack/singleshot.rb', line 23

def run
  request = read_request

  status, headers, body = @app.call(request)

  write_response(status, headers, body)
ensure
  @stdout.close
  exit
end

#write_response(status, headers, body) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/rack/singleshot.rb', line 82

def write_response(status, headers, body)
  @stdout.write(['HTTP/1.1', status, Rack::Utils::HTTP_STATUS_CODES[status.to_i]].join(' ') << CRLF)

  headers.each do |key, values|
    values.split("\n").each do |value|
      @stdout.write([key, value].join(": ") << CRLF)
    end
  end

  @stdout.write(CRLF)

  body.each do |chunk|
    @stdout.write(chunk)
  end
end