puma-simon 3.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. checksums.yaml +7 -0
  2. data/.github/issue_template.md +20 -0
  3. data/.gitignore +18 -0
  4. data/.hoeignore +12 -0
  5. data/.travis.yml +29 -0
  6. data/DEPLOYMENT.md +91 -0
  7. data/Gemfile +12 -0
  8. data/History.md +1254 -0
  9. data/LICENSE +26 -0
  10. data/Manifest.txt +78 -0
  11. data/README.md +353 -0
  12. data/Rakefile +158 -0
  13. data/Release.md +9 -0
  14. data/bin/puma +10 -0
  15. data/bin/puma-wild +31 -0
  16. data/bin/pumactl +12 -0
  17. data/docs/nginx.md +80 -0
  18. data/docs/signals.md +43 -0
  19. data/docs/systemd.md +197 -0
  20. data/examples/CA/cacert.pem +23 -0
  21. data/examples/CA/newcerts/cert_1.pem +19 -0
  22. data/examples/CA/newcerts/cert_2.pem +19 -0
  23. data/examples/CA/private/cakeypair.pem +30 -0
  24. data/examples/CA/serial +1 -0
  25. data/examples/config.rb +200 -0
  26. data/examples/plugins/redis_stop_puma.rb +46 -0
  27. data/examples/puma/cert_puma.pem +19 -0
  28. data/examples/puma/client-certs/ca.crt +19 -0
  29. data/examples/puma/client-certs/ca.key +27 -0
  30. data/examples/puma/client-certs/client.crt +19 -0
  31. data/examples/puma/client-certs/client.key +27 -0
  32. data/examples/puma/client-certs/client_expired.crt +19 -0
  33. data/examples/puma/client-certs/client_expired.key +27 -0
  34. data/examples/puma/client-certs/client_unknown.crt +19 -0
  35. data/examples/puma/client-certs/client_unknown.key +27 -0
  36. data/examples/puma/client-certs/generate.rb +78 -0
  37. data/examples/puma/client-certs/keystore.jks +0 -0
  38. data/examples/puma/client-certs/server.crt +19 -0
  39. data/examples/puma/client-certs/server.key +27 -0
  40. data/examples/puma/client-certs/server.p12 +0 -0
  41. data/examples/puma/client-certs/unknown_ca.crt +19 -0
  42. data/examples/puma/client-certs/unknown_ca.key +27 -0
  43. data/examples/puma/csr_puma.pem +11 -0
  44. data/examples/puma/keystore.jks +0 -0
  45. data/examples/puma/puma_keypair.pem +15 -0
  46. data/examples/qc_config.rb +13 -0
  47. data/ext/puma_http11/PumaHttp11Service.java +17 -0
  48. data/ext/puma_http11/ext_help.h +15 -0
  49. data/ext/puma_http11/extconf.rb +15 -0
  50. data/ext/puma_http11/http11_parser.c +1069 -0
  51. data/ext/puma_http11/http11_parser.h +65 -0
  52. data/ext/puma_http11/http11_parser.java.rl +161 -0
  53. data/ext/puma_http11/http11_parser.rl +147 -0
  54. data/ext/puma_http11/http11_parser_common.rl +54 -0
  55. data/ext/puma_http11/io_buffer.c +155 -0
  56. data/ext/puma_http11/mini_ssl.c +457 -0
  57. data/ext/puma_http11/org/jruby/puma/Http11.java +234 -0
  58. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +473 -0
  59. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +339 -0
  60. data/ext/puma_http11/puma_http11.c +500 -0
  61. data/gemfiles/2.1-Gemfile +12 -0
  62. data/lib/puma.rb +15 -0
  63. data/lib/puma/accept_nonblock.rb +23 -0
  64. data/lib/puma/app/status.rb +66 -0
  65. data/lib/puma/binder.rb +402 -0
  66. data/lib/puma/cli.rb +220 -0
  67. data/lib/puma/client.rb +434 -0
  68. data/lib/puma/cluster.rb +510 -0
  69. data/lib/puma/commonlogger.rb +106 -0
  70. data/lib/puma/compat.rb +14 -0
  71. data/lib/puma/configuration.rb +364 -0
  72. data/lib/puma/const.rb +224 -0
  73. data/lib/puma/control_cli.rb +259 -0
  74. data/lib/puma/convenient.rb +23 -0
  75. data/lib/puma/daemon_ext.rb +31 -0
  76. data/lib/puma/delegation.rb +11 -0
  77. data/lib/puma/detect.rb +13 -0
  78. data/lib/puma/dsl.rb +486 -0
  79. data/lib/puma/events.rb +152 -0
  80. data/lib/puma/io_buffer.rb +7 -0
  81. data/lib/puma/java_io_buffer.rb +45 -0
  82. data/lib/puma/jruby_restart.rb +83 -0
  83. data/lib/puma/launcher.rb +410 -0
  84. data/lib/puma/minissl.rb +221 -0
  85. data/lib/puma/null_io.rb +42 -0
  86. data/lib/puma/plugin.rb +115 -0
  87. data/lib/puma/plugin/tmp_restart.rb +35 -0
  88. data/lib/puma/rack/backports/uri/common_193.rb +33 -0
  89. data/lib/puma/rack/builder.rb +298 -0
  90. data/lib/puma/rack/urlmap.rb +91 -0
  91. data/lib/puma/rack_default.rb +7 -0
  92. data/lib/puma/reactor.rb +210 -0
  93. data/lib/puma/runner.rb +171 -0
  94. data/lib/puma/server.rb +949 -0
  95. data/lib/puma/single.rb +112 -0
  96. data/lib/puma/state_file.rb +29 -0
  97. data/lib/puma/tcp_logger.rb +39 -0
  98. data/lib/puma/thread_pool.rb +297 -0
  99. data/lib/puma/util.rb +128 -0
  100. data/lib/rack/handler/puma.rb +78 -0
  101. data/puma.gemspec +52 -0
  102. data/test/ab_rs.rb +22 -0
  103. data/test/config.rb +2 -0
  104. data/test/config/app.rb +9 -0
  105. data/test/config/plugin.rb +1 -0
  106. data/test/config/settings.rb +2 -0
  107. data/test/config/state_file_testing_config.rb +14 -0
  108. data/test/hello-bind.ru +2 -0
  109. data/test/hello-delay.ru +3 -0
  110. data/test/hello-map.ru +3 -0
  111. data/test/hello-post.ru +4 -0
  112. data/test/hello-stuck.ru +1 -0
  113. data/test/hello-tcp.ru +5 -0
  114. data/test/hello.ru +1 -0
  115. data/test/hijack.ru +6 -0
  116. data/test/hijack2.ru +5 -0
  117. data/test/lobster.ru +4 -0
  118. data/test/shell/run.sh +24 -0
  119. data/test/shell/t1.rb +19 -0
  120. data/test/shell/t1_conf.rb +3 -0
  121. data/test/shell/t2.rb +17 -0
  122. data/test/shell/t2_conf.rb +6 -0
  123. data/test/shell/t3.rb +25 -0
  124. data/test/shell/t3_conf.rb +5 -0
  125. data/test/slow.ru +4 -0
  126. data/test/ssl_config.rb +4 -0
  127. data/test/test_app_status.rb +93 -0
  128. data/test/test_binder.rb +31 -0
  129. data/test/test_cli.rb +209 -0
  130. data/test/test_config.rb +95 -0
  131. data/test/test_events.rb +161 -0
  132. data/test/test_helper.rb +50 -0
  133. data/test/test_http10.rb +27 -0
  134. data/test/test_http11.rb +186 -0
  135. data/test/test_integration.rb +247 -0
  136. data/test/test_iobuffer.rb +39 -0
  137. data/test/test_minissl.rb +29 -0
  138. data/test/test_null_io.rb +49 -0
  139. data/test/test_persistent.rb +245 -0
  140. data/test/test_puma_server.rb +626 -0
  141. data/test/test_puma_server_ssl.rb +222 -0
  142. data/test/test_rack_handler.rb +57 -0
  143. data/test/test_rack_server.rb +138 -0
  144. data/test/test_tcp_logger.rb +39 -0
  145. data/test/test_tcp_rack.rb +36 -0
  146. data/test/test_thread_pool.rb +250 -0
  147. data/test/test_unix_socket.rb +35 -0
  148. data/test/test_web_server.rb +88 -0
  149. data/tools/jungle/README.md +9 -0
  150. data/tools/jungle/init.d/README.md +59 -0
  151. data/tools/jungle/init.d/puma +421 -0
  152. data/tools/jungle/init.d/run-puma +18 -0
  153. data/tools/jungle/upstart/README.md +61 -0
  154. data/tools/jungle/upstart/puma-manager.conf +31 -0
  155. data/tools/jungle/upstart/puma.conf +69 -0
  156. data/tools/trickletest.rb +45 -0
  157. metadata +297 -0
@@ -0,0 +1,220 @@
1
+ require 'optparse'
2
+ require 'uri'
3
+
4
+ require 'puma/configuration'
5
+ require 'puma/launcher'
6
+ require 'puma/const'
7
+ require 'puma/events'
8
+
9
+ module Puma
10
+ class << self
11
+ # The CLI exports its Puma::Configuration object here to allow
12
+ # apps to pick it up. An app needs to use it conditionally though
13
+ # since it is not set if the app is launched via another
14
+ # mechanism than the CLI class.
15
+ attr_accessor :cli_config
16
+ end
17
+
18
+ # Handles invoke a Puma::Server in a command line style.
19
+ #
20
+ class CLI
21
+ KEYS_NOT_TO_PERSIST_IN_STATE = Launcher::KEYS_NOT_TO_PERSIST_IN_STATE
22
+
23
+ # Create a new CLI object using +argv+ as the command line
24
+ # arguments.
25
+ #
26
+ # +stdout+ and +stderr+ can be set to IO-like objects which
27
+ # this object will report status on.
28
+ #
29
+ def initialize(argv, events=Events.stdio)
30
+ @debug = false
31
+ @argv = argv.dup
32
+
33
+ @events = events
34
+
35
+ @conf = nil
36
+
37
+ @stdout = nil
38
+ @stderr = nil
39
+ @append = false
40
+
41
+ @control_url = nil
42
+ @control_options = {}
43
+
44
+ setup_options
45
+
46
+ begin
47
+ @parser.parse! @argv
48
+
49
+ if file = @argv.shift
50
+ @conf.configure do |c|
51
+ c.rackup file
52
+ end
53
+ end
54
+ rescue UnsupportedOption
55
+ exit 1
56
+ end
57
+
58
+ @conf.configure do |c|
59
+ if @stdout || @stderr
60
+ c.stdout_redirect @stdout, @stderr, @append
61
+ end
62
+
63
+ if @control_url
64
+ c.activate_control_app @control_url, @control_options
65
+ end
66
+ end
67
+
68
+ @launcher = Puma::Launcher.new(@conf, :events => @events, :argv => argv)
69
+ end
70
+
71
+ attr_reader :launcher
72
+
73
+ # Parse the options, load the rackup, start the server and wait
74
+ # for it to finish.
75
+ #
76
+ def run
77
+ @launcher.run
78
+ end
79
+
80
+ private
81
+ def unsupported(str)
82
+ @events.error(str)
83
+ raise UnsupportedOption
84
+ end
85
+
86
+ # Build the OptionParser object to handle the available options.
87
+ #
88
+
89
+ def setup_options
90
+ @conf = Configuration.new do |c|
91
+ @parser = OptionParser.new do |o|
92
+ o.on "-b", "--bind URI", "URI to bind to (tcp://, unix://, ssl://)" do |arg|
93
+ c.bind arg
94
+ end
95
+
96
+ o.on "-C", "--config PATH", "Load PATH as a config file" do |arg|
97
+ c.load arg
98
+ end
99
+
100
+ o.on "--control URL", "The bind url to use for the control server",
101
+ "Use 'auto' to use temp unix server" do |arg|
102
+ if arg
103
+ @control_url = arg
104
+ elsif Puma.jruby?
105
+ unsupported "No default url available on JRuby"
106
+ end
107
+ end
108
+
109
+ o.on "--control-token TOKEN",
110
+ "The token to use as authentication for the control server" do |arg|
111
+ @control_options[:auth_token] = arg
112
+ end
113
+
114
+ o.on "-d", "--daemon", "Daemonize the server into the background" do
115
+ c.daemonize
116
+ c.quiet
117
+ end
118
+
119
+ o.on "--debug", "Log lowlevel debugging information" do
120
+ c.debug
121
+ end
122
+
123
+ o.on "--dir DIR", "Change to DIR before starting" do |d|
124
+ c.directory d
125
+ end
126
+
127
+ o.on "-e", "--environment ENVIRONMENT",
128
+ "The environment to run the Rack app on (default development)" do |arg|
129
+ c.environment arg
130
+ end
131
+
132
+ o.on "-I", "--include PATH", "Specify $LOAD_PATH directories" do |arg|
133
+ $LOAD_PATH.unshift(*arg.split(':'))
134
+ end
135
+
136
+ o.on "-p", "--port PORT", "Define the TCP port to bind to",
137
+ "Use -b for more advanced options" do |arg|
138
+ c.bind "tcp://#{Configuration::DefaultTCPHost}:#{arg}"
139
+ end
140
+
141
+ o.on "--pidfile PATH", "Use PATH as a pidfile" do |arg|
142
+ c.pidfile arg
143
+ end
144
+
145
+ o.on "--preload", "Preload the app. Cluster mode only" do
146
+ c.preload_app!
147
+ end
148
+
149
+ o.on "--prune-bundler", "Prune out the bundler env if possible" do
150
+ c.prune_bundler
151
+ end
152
+
153
+ o.on "-q", "--quiet", "Do not log requests internally (default true)" do
154
+ c.quiet
155
+ end
156
+
157
+ o.on "-v", "--log-requests", "Log requests as they occur" do
158
+ c.log_requests
159
+ end
160
+
161
+ o.on "-R", "--restart-cmd CMD",
162
+ "The puma command to run during a hot restart",
163
+ "Default: inferred" do |cmd|
164
+ c.restart_command cmd
165
+ end
166
+
167
+ o.on "-S", "--state PATH", "Where to store the state details" do |arg|
168
+ c.state_path arg
169
+ end
170
+
171
+ o.on '-t', '--threads INT', "min:max threads to use (default 0:16)" do |arg|
172
+ min, max = arg.split(":")
173
+ if max
174
+ c.threads min, max
175
+ else
176
+ c.threads min, min
177
+ end
178
+ end
179
+
180
+ o.on "--tcp-mode", "Run the app in raw TCP mode instead of HTTP mode" do
181
+ c.tcp_mode!
182
+ end
183
+
184
+ o.on "-V", "--version", "Print the version information" do
185
+ puts "puma version #{Puma::Const::VERSION}"
186
+ exit 0
187
+ end
188
+
189
+ o.on "-w", "--workers COUNT",
190
+ "Activate cluster mode: How many worker processes to create" do |arg|
191
+ c.workers arg
192
+ end
193
+
194
+ o.on "--tag NAME", "Additional text to display in process listing" do |arg|
195
+ c.tag arg
196
+ end
197
+
198
+ o.on "--redirect-stdout FILE", "Redirect STDOUT to a specific file" do |arg|
199
+ @stdout = arg.to_s
200
+ end
201
+
202
+ o.on "--redirect-stderr FILE", "Redirect STDERR to a specific file" do |arg|
203
+ @stderr = arg.to_s
204
+ end
205
+
206
+ o.on "--[no-]redirect-append", "Append to redirected files" do |val|
207
+ @append = val
208
+ end
209
+
210
+ o.banner = "puma <options> <rackup file>"
211
+
212
+ o.on_tail "-h", "--help", "Show help" do
213
+ $stdout.puts o
214
+ exit 0
215
+ end
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,434 @@
1
+ class IO
2
+ # We need to use this for a jruby work around on both 1.8 and 1.9.
3
+ # So this either creates the constant (on 1.8), or harmlessly
4
+ # reopens it (on 1.9).
5
+ module WaitReadable
6
+ end
7
+ end
8
+
9
+ require 'puma/detect'
10
+ require 'puma/delegation'
11
+ require 'tempfile'
12
+
13
+ if Puma::IS_JRUBY
14
+ # We have to work around some OpenSSL buffer/io-readiness bugs
15
+ # so we pull it in regardless of if the user is binding
16
+ # to an SSL socket
17
+ require 'openssl'
18
+ end
19
+
20
+ module Puma
21
+
22
+ class ConnectionError < RuntimeError; end
23
+
24
+ class Client
25
+ include Puma::Const
26
+ extend Puma::Delegation
27
+
28
+ def initialize(io, env=nil)
29
+ @io = io
30
+ @to_io = io.to_io
31
+ @proto_env = env
32
+ if !env
33
+ @env = nil
34
+ else
35
+ @env = env.dup
36
+ end
37
+
38
+ @parser = HttpParser.new
39
+ @parsed_bytes = 0
40
+ @read_header = true
41
+ @ready = false
42
+
43
+ @body = nil
44
+ @buffer = nil
45
+ @tempfile = nil
46
+
47
+ @timeout_at = nil
48
+
49
+ @requests_served = 0
50
+ @hijacked = false
51
+
52
+ @peerip = nil
53
+ @remote_addr_header = nil
54
+ end
55
+
56
+ attr_reader :env, :to_io, :body, :io, :timeout_at, :ready, :hijacked,
57
+ :tempfile
58
+
59
+ attr_writer :peerip
60
+
61
+ attr_accessor :remote_addr_header
62
+
63
+ forward :closed?, :@io
64
+
65
+ def inspect
66
+ "#<Puma::Client:0x#{object_id.to_s(16)} @ready=#{@ready.inspect}>"
67
+ end
68
+
69
+ # For the hijack protocol (allows us to just put the Client object
70
+ # into the env)
71
+ def call
72
+ @hijacked = true
73
+ env[HIJACK_IO] ||= @io
74
+ end
75
+
76
+ def in_data_phase
77
+ !@read_header
78
+ end
79
+
80
+ def set_timeout(val)
81
+ @timeout_at = Time.now + val
82
+ end
83
+
84
+ def reset(fast_check=true)
85
+ @parser.reset
86
+ @read_header = true
87
+ @env = @proto_env.dup
88
+ @body = nil
89
+ @tempfile = nil
90
+ @parsed_bytes = 0
91
+ @ready = false
92
+
93
+ if @buffer
94
+ @parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
95
+
96
+ if @parser.finished?
97
+ return setup_body
98
+ elsif @parsed_bytes >= MAX_HEADER
99
+ raise HttpParserError,
100
+ "HEADER is longer than allowed, aborting client early."
101
+ end
102
+
103
+ return false
104
+ elsif fast_check &&
105
+ IO.select([@to_io], nil, nil, FAST_TRACK_KA_TIMEOUT)
106
+ return try_to_finish
107
+ end
108
+ end
109
+
110
+ def close
111
+ begin
112
+ @io.close
113
+ rescue IOError
114
+ end
115
+ end
116
+
117
+ # The object used for a request with no body. All requests with
118
+ # no body share this one object since it has no state.
119
+ EmptyBody = NullIO.new
120
+
121
+ def setup_chunked_body(body)
122
+ @chunked_body = true
123
+ @partial_part_left = 0
124
+ @prev_chunk = ""
125
+
126
+ @body = Tempfile.new(Const::PUMA_TMP_BASE)
127
+ @body.binmode
128
+ @tempfile = @body
129
+
130
+ return decode_chunk(body)
131
+ end
132
+
133
+ def decode_chunk(chunk)
134
+ if @partial_part_left > 0
135
+ if @partial_part_left <= chunk.size
136
+ @body << chunk[0..(@partial_part_left-3)] # skip the \r\n
137
+ chunk = chunk[@partial_part_left..-1]
138
+ else
139
+ @body << chunk
140
+ @partial_part_left -= chunk.size
141
+ return false
142
+ end
143
+ end
144
+
145
+ if @prev_chunk.empty?
146
+ io = StringIO.new(chunk)
147
+ else
148
+ io = StringIO.new(@prev_chunk+chunk)
149
+ @prev_chunk = ""
150
+ end
151
+
152
+ while !io.eof?
153
+ line = io.gets
154
+ if line.end_with?("\r\n")
155
+ len = line.strip.to_i(16)
156
+ if len == 0
157
+ @body.rewind
158
+ rest = io.read
159
+ @buffer = rest.empty? ? nil : rest
160
+ @requests_served += 1
161
+ @ready = true
162
+ return true
163
+ end
164
+
165
+ len += 2
166
+
167
+ part = io.read(len)
168
+
169
+ unless part
170
+ @partial_part_left = len
171
+ next
172
+ end
173
+
174
+ got = part.size
175
+
176
+ case
177
+ when got == len
178
+ @body << part[0..-3] # to skip the ending \r\n
179
+ when got <= len - 2
180
+ @body << part
181
+ @partial_part_left = len - part.size
182
+ when got == len - 1 # edge where we get just \r but not \n
183
+ @body << part[0..-2]
184
+ @partial_part_left = len - part.size
185
+ end
186
+ else
187
+ @prev_chunk = line
188
+ return false
189
+ end
190
+ end
191
+
192
+ return false
193
+ end
194
+
195
+ def read_chunked_body
196
+ while true
197
+ begin
198
+ chunk = @io.read_nonblock(4096)
199
+ rescue Errno::EAGAIN
200
+ return false
201
+ rescue SystemCallError, IOError
202
+ raise ConnectionError, "Connection error detected during read"
203
+ end
204
+
205
+ # No chunk means a closed socket
206
+ unless chunk
207
+ @body.close
208
+ @buffer = nil
209
+ @requests_served += 1
210
+ @ready = true
211
+ raise EOFError
212
+ end
213
+
214
+ return true if decode_chunk(chunk)
215
+ end
216
+ end
217
+
218
+ def setup_body
219
+ @read_header = false
220
+
221
+ body = @parser.body
222
+
223
+ te = @env[TRANSFER_ENCODING2]
224
+
225
+ if te && CHUNKED.casecmp(te) == 0
226
+ return setup_chunked_body(body)
227
+ end
228
+
229
+ @chunked_body = false
230
+
231
+ cl = @env[CONTENT_LENGTH]
232
+
233
+ unless cl
234
+ @buffer = body.empty? ? nil : body
235
+ @body = EmptyBody
236
+ @requests_served += 1
237
+ @ready = true
238
+ return true
239
+ end
240
+
241
+ remain = cl.to_i - body.bytesize
242
+
243
+ if remain <= 0
244
+ @body = StringIO.new(body)
245
+ @buffer = nil
246
+ @requests_served += 1
247
+ @ready = true
248
+ return true
249
+ end
250
+
251
+ if remain > MAX_BODY
252
+ @body = Tempfile.new(Const::PUMA_TMP_BASE)
253
+ @body.binmode
254
+ @tempfile = @body
255
+ else
256
+ # The body[0,0] trick is to get an empty string in the same
257
+ # encoding as body.
258
+ @body = StringIO.new body[0,0]
259
+ end
260
+
261
+ @body.write body
262
+
263
+ @body_remain = remain
264
+
265
+ return false
266
+ end
267
+
268
+ def try_to_finish
269
+ return read_body unless @read_header
270
+
271
+ begin
272
+ data = @io.read_nonblock(CHUNK_SIZE)
273
+ rescue Errno::EAGAIN
274
+ return false
275
+ rescue SystemCallError, IOError
276
+ raise ConnectionError, "Connection error detected during read"
277
+ end
278
+
279
+ if @buffer
280
+ @buffer << data
281
+ else
282
+ @buffer = data
283
+ end
284
+
285
+ @parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
286
+
287
+ if @parser.finished?
288
+ return setup_body
289
+ elsif @parsed_bytes >= MAX_HEADER
290
+ raise HttpParserError,
291
+ "HEADER is longer than allowed, aborting client early."
292
+ end
293
+
294
+ false
295
+ end
296
+
297
+ if IS_JRUBY
298
+ def jruby_start_try_to_finish
299
+ return read_body unless @read_header
300
+
301
+ begin
302
+ data = @io.sysread_nonblock(CHUNK_SIZE)
303
+ rescue OpenSSL::SSL::SSLError => e
304
+ return false if e.kind_of? IO::WaitReadable
305
+ raise e
306
+ end
307
+
308
+ if @buffer
309
+ @buffer << data
310
+ else
311
+ @buffer = data
312
+ end
313
+
314
+ @parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
315
+
316
+ if @parser.finished?
317
+ return setup_body
318
+ elsif @parsed_bytes >= MAX_HEADER
319
+ raise HttpParserError,
320
+ "HEADER is longer than allowed, aborting client early."
321
+ end
322
+
323
+ false
324
+ end
325
+
326
+ def eagerly_finish
327
+ return true if @ready
328
+
329
+ if @io.kind_of? OpenSSL::SSL::SSLSocket
330
+ return true if jruby_start_try_to_finish
331
+ end
332
+
333
+ return false unless IO.select([@to_io], nil, nil, 0)
334
+ try_to_finish
335
+ end
336
+
337
+ else
338
+
339
+ def eagerly_finish
340
+ return true if @ready
341
+ return false unless IO.select([@to_io], nil, nil, 0)
342
+ try_to_finish
343
+ end
344
+ end # IS_JRUBY
345
+
346
+ def finish
347
+ return true if @ready
348
+ until try_to_finish
349
+ IO.select([@to_io], nil, nil)
350
+ end
351
+ true
352
+ end
353
+
354
+ def read_body
355
+ if @chunked_body
356
+ return read_chunked_body
357
+ end
358
+
359
+ # Read an odd sized chunk so we can read even sized ones
360
+ # after this
361
+ remain = @body_remain
362
+
363
+ if remain > CHUNK_SIZE
364
+ want = CHUNK_SIZE
365
+ else
366
+ want = remain
367
+ end
368
+
369
+ begin
370
+ chunk = @io.read_nonblock(want)
371
+ rescue Errno::EAGAIN
372
+ return false
373
+ rescue SystemCallError, IOError
374
+ raise ConnectionError, "Connection error detected during read"
375
+ end
376
+
377
+ # No chunk means a closed socket
378
+ unless chunk
379
+ @body.close
380
+ @buffer = nil
381
+ @requests_served += 1
382
+ @ready = true
383
+ raise EOFError
384
+ end
385
+
386
+ remain -= @body.write(chunk)
387
+
388
+ if remain <= 0
389
+ @body.rewind
390
+ @buffer = nil
391
+ @requests_served += 1
392
+ @ready = true
393
+ return true
394
+ end
395
+
396
+ @body_remain = remain
397
+
398
+ false
399
+ end
400
+
401
+ def write_400
402
+ begin
403
+ @io << ERROR_400_RESPONSE
404
+ rescue StandardError
405
+ end
406
+ end
407
+
408
+ def write_408
409
+ begin
410
+ @io << ERROR_408_RESPONSE
411
+ rescue StandardError
412
+ end
413
+ end
414
+
415
+ def write_500
416
+ begin
417
+ @io << ERROR_500_RESPONSE
418
+ rescue StandardError
419
+ end
420
+ end
421
+
422
+ def peerip
423
+ return @peerip if @peerip
424
+
425
+ if @remote_addr_header
426
+ hdr = (@env[@remote_addr_header] || LOCALHOST_ADDR).split(/[\s,]/).first
427
+ @peerip = hdr
428
+ return hdr
429
+ end
430
+
431
+ @peerip ||= @io.peeraddr.last
432
+ end
433
+ end
434
+ end