puma 3.5.0 → 3.12.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/{History.txt → History.md} +318 -75
- data/README.md +143 -227
- data/docs/architecture.md +36 -0
- data/{DEPLOYMENT.md → docs/deployment.md} +0 -0
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/plugins.md +28 -0
- data/docs/restart.md +39 -0
- data/docs/signals.md +56 -3
- data/docs/systemd.md +124 -22
- data/ext/puma_http11/extconf.rb +2 -0
- data/ext/puma_http11/http11_parser.c +85 -84
- data/ext/puma_http11/http11_parser.h +1 -0
- data/ext/puma_http11/http11_parser.rl +10 -9
- data/ext/puma_http11/io_buffer.c +7 -7
- data/ext/puma_http11/mini_ssl.c +67 -6
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +13 -16
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +15 -2
- data/ext/puma_http11/puma_http11.c +1 -0
- data/lib/puma.rb +13 -5
- data/lib/puma/app/status.rb +8 -0
- data/lib/puma/binder.rb +22 -17
- data/lib/puma/cli.rb +49 -33
- data/lib/puma/client.rb +149 -4
- data/lib/puma/cluster.rb +54 -12
- data/lib/puma/commonlogger.rb +19 -20
- data/lib/puma/compat.rb +3 -7
- data/lib/puma/configuration.rb +133 -130
- data/lib/puma/const.rb +19 -37
- data/lib/puma/control_cli.rb +38 -35
- data/lib/puma/convenient.rb +3 -3
- data/lib/puma/detect.rb +3 -1
- data/lib/puma/dsl.rb +80 -58
- data/lib/puma/events.rb +6 -8
- data/lib/puma/io_buffer.rb +1 -1
- data/lib/puma/jruby_restart.rb +0 -1
- data/lib/puma/launcher.rb +61 -30
- data/lib/puma/minissl.rb +85 -4
- data/lib/puma/null_io.rb +6 -13
- data/lib/puma/plugin.rb +12 -1
- data/lib/puma/plugin/tmp_restart.rb +1 -2
- data/lib/puma/rack/builder.rb +3 -0
- data/lib/puma/rack/urlmap.rb +9 -8
- data/lib/puma/reactor.rb +135 -0
- data/lib/puma/runner.rb +27 -1
- data/lib/puma/server.rb +134 -32
- data/lib/puma/single.rb +17 -3
- data/lib/puma/thread_pool.rb +67 -20
- data/lib/puma/util.rb +1 -5
- data/lib/rack/handler/puma.rb +58 -17
- data/tools/jungle/README.md +12 -2
- data/tools/jungle/init.d/README.md +9 -2
- data/tools/jungle/init.d/puma +32 -62
- data/tools/jungle/init.d/run-puma +5 -1
- data/tools/jungle/rc.d/README.md +74 -0
- data/tools/jungle/rc.d/puma +61 -0
- data/tools/jungle/rc.d/puma.conf +10 -0
- data/tools/trickletest.rb +1 -1
- metadata +22 -92
- data/Gemfile +0 -13
- data/Manifest.txt +0 -77
- data/Rakefile +0 -158
- data/lib/puma/rack/backports/uri/common_18.rb +0 -59
- data/lib/puma/rack/backports/uri/common_192.rb +0 -55
- data/puma.gemspec +0 -52
data/lib/puma.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# Standard libraries
|
2
2
|
require 'socket'
|
3
3
|
require 'tempfile'
|
4
|
-
require 'yaml'
|
5
4
|
require 'time'
|
6
5
|
require 'etc'
|
7
6
|
require 'uri'
|
@@ -9,7 +8,16 @@ require 'stringio'
|
|
9
8
|
|
10
9
|
require 'thread'
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
module Puma
|
12
|
+
autoload :Const, 'puma/const'
|
13
|
+
autoload :Server, 'puma/server'
|
14
|
+
autoload :Launcher, 'puma/launcher'
|
15
|
+
|
16
|
+
def self.stats_object=(val)
|
17
|
+
@get_stats = val
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.stats
|
21
|
+
@get_stats.stats
|
22
|
+
end
|
23
|
+
end
|
data/lib/puma/app/status.rb
CHANGED
@@ -55,6 +55,14 @@ module Puma
|
|
55
55
|
return rack_response(200, OK_STATUS)
|
56
56
|
end
|
57
57
|
|
58
|
+
when /\/gc$/
|
59
|
+
GC.start
|
60
|
+
return rack_response(200, OK_STATUS)
|
61
|
+
|
62
|
+
when /\/gc-stats$/
|
63
|
+
json = "{" + GC.stat.map { |k, v| "\"#{k}\": #{v}" }.join(",") + "}"
|
64
|
+
return rack_response(200, json)
|
65
|
+
|
58
66
|
when /\/stats$/
|
59
67
|
return rack_response(200, @cli.stats)
|
60
68
|
else
|
data/lib/puma/binder.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
require 'puma/const'
|
2
1
|
require 'uri'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
require 'puma/const'
|
5
|
+
require 'puma/util'
|
3
6
|
|
4
7
|
module Puma
|
5
8
|
class Binder
|
@@ -102,7 +105,7 @@ module Puma
|
|
102
105
|
io = add_tcp_listener uri.host, uri.port, opt, bak
|
103
106
|
end
|
104
107
|
|
105
|
-
@listeners << [str, io]
|
108
|
+
@listeners << [str, io] if io
|
106
109
|
when "unix"
|
107
110
|
path = "#{uri.host}#{uri.path}".gsub("%20", " ")
|
108
111
|
|
@@ -117,7 +120,7 @@ module Puma
|
|
117
120
|
|
118
121
|
umask = nil
|
119
122
|
mode = nil
|
120
|
-
backlog =
|
123
|
+
backlog = 1024
|
121
124
|
|
122
125
|
if uri.query
|
123
126
|
params = Util.parse_query uri.query
|
@@ -140,11 +143,11 @@ module Puma
|
|
140
143
|
|
141
144
|
@listeners << [str, io]
|
142
145
|
when "ssl"
|
143
|
-
MiniSSL.check
|
144
|
-
|
145
146
|
params = Util.parse_query uri.query
|
146
147
|
require 'puma/minissl'
|
147
148
|
|
149
|
+
MiniSSL.check
|
150
|
+
|
148
151
|
ctx = MiniSSL::Context.new
|
149
152
|
|
150
153
|
if defined?(JRUBY_VERSION)
|
@@ -159,6 +162,7 @@ module Puma
|
|
159
162
|
end
|
160
163
|
|
161
164
|
ctx.keystore_pass = params['keystore-pass']
|
165
|
+
ctx.ssl_cipher_list = params['ssl_cipher_list'] if params['ssl_cipher_list']
|
162
166
|
else
|
163
167
|
unless params['key']
|
164
168
|
@events.error "Please specify the SSL key via 'key='"
|
@@ -179,9 +183,10 @@ module Puma
|
|
179
183
|
end
|
180
184
|
|
181
185
|
ctx.ca = params['ca'] if params['ca']
|
186
|
+
ctx.ssl_cipher_filter = params['ssl_cipher_filter'] if params['ssl_cipher_filter']
|
182
187
|
end
|
183
188
|
|
184
|
-
if
|
189
|
+
if params['verify_mode']
|
185
190
|
ctx.verify_mode = case params['verify_mode']
|
186
191
|
when "peer"
|
187
192
|
MiniSSL::VERIFY_PEER
|
@@ -193,8 +198,6 @@ module Puma
|
|
193
198
|
@events.error "Please specify a valid verify_mode="
|
194
199
|
MiniSSL::VERIFY_NONE
|
195
200
|
end
|
196
|
-
else
|
197
|
-
ctx.verify_mode = MiniSSL::VERIFY_PEER
|
198
201
|
end
|
199
202
|
|
200
203
|
if fd = @inherited_fds.delete(str)
|
@@ -208,7 +211,7 @@ module Puma
|
|
208
211
|
io = add_ssl_listener uri.host, uri.port, ctx
|
209
212
|
end
|
210
213
|
|
211
|
-
@listeners << [str, io]
|
214
|
+
@listeners << [str, io] if io
|
212
215
|
else
|
213
216
|
logger.error "Invalid URI: #{str}"
|
214
217
|
end
|
@@ -244,9 +247,10 @@ module Puma
|
|
244
247
|
end
|
245
248
|
end
|
246
249
|
|
247
|
-
def
|
248
|
-
|
249
|
-
|
250
|
+
def loopback_addresses
|
251
|
+
Socket.ip_address_list.select do |addrinfo|
|
252
|
+
addrinfo.ipv6_loopback? || addrinfo.ipv4_loopback?
|
253
|
+
end.map { |addrinfo| addrinfo.ip_address }.uniq
|
250
254
|
end
|
251
255
|
|
252
256
|
# Tell the server to listen on host +host+, port +port+.
|
@@ -258,7 +262,7 @@ module Puma
|
|
258
262
|
#
|
259
263
|
def add_tcp_listener(host, port, optimize_for_latency=true, backlog=1024)
|
260
264
|
if host == "localhost"
|
261
|
-
|
265
|
+
loopback_addresses.each do |addr|
|
262
266
|
add_tcp_listener addr, port, optimize_for_latency, backlog
|
263
267
|
end
|
264
268
|
return
|
@@ -297,8 +301,8 @@ module Puma
|
|
297
301
|
MiniSSL.check
|
298
302
|
|
299
303
|
if host == "localhost"
|
300
|
-
|
301
|
-
add_ssl_listener addr, port, optimize_for_latency, backlog
|
304
|
+
loopback_addresses.each do |addr|
|
305
|
+
add_ssl_listener addr, port, ctx, optimize_for_latency, backlog
|
302
306
|
end
|
303
307
|
return
|
304
308
|
end
|
@@ -311,6 +315,7 @@ module Puma
|
|
311
315
|
s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
|
312
316
|
s.listen backlog
|
313
317
|
|
318
|
+
|
314
319
|
ssl = MiniSSL::Server.new s, ctx
|
315
320
|
env = @proto_env.dup
|
316
321
|
env[HTTPS_KEY] = HTTPS
|
@@ -342,7 +347,7 @@ module Puma
|
|
342
347
|
|
343
348
|
# Tell the server to listen on +path+ as a UNIX domain socket.
|
344
349
|
#
|
345
|
-
def add_unix_listener(path, umask=nil, mode=nil, backlog=
|
350
|
+
def add_unix_listener(path, umask=nil, mode=nil, backlog=1024)
|
346
351
|
@unix_paths << path
|
347
352
|
|
348
353
|
# Let anyone connect by default
|
@@ -363,7 +368,7 @@ module Puma
|
|
363
368
|
end
|
364
369
|
|
365
370
|
s = UNIXServer.new(path)
|
366
|
-
s.listen backlog
|
371
|
+
s.listen backlog
|
367
372
|
@ios << s
|
368
373
|
ensure
|
369
374
|
File.umask old_mask
|
data/lib/puma/cli.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
require 'uri'
|
3
3
|
|
4
|
+
require 'puma'
|
5
|
+
require 'puma/configuration'
|
4
6
|
require 'puma/launcher'
|
7
|
+
require 'puma/const'
|
8
|
+
require 'puma/events'
|
5
9
|
|
6
10
|
module Puma
|
7
11
|
class << self
|
@@ -44,21 +48,21 @@ module Puma
|
|
44
48
|
@parser.parse! @argv
|
45
49
|
|
46
50
|
if file = @argv.shift
|
47
|
-
@conf.configure do |
|
48
|
-
|
51
|
+
@conf.configure do |user_config, file_config|
|
52
|
+
file_config.rackup file
|
49
53
|
end
|
50
54
|
end
|
51
55
|
rescue UnsupportedOption
|
52
56
|
exit 1
|
53
57
|
end
|
54
58
|
|
55
|
-
@conf.configure do |
|
59
|
+
@conf.configure do |user_config, file_config|
|
56
60
|
if @stdout || @stderr
|
57
|
-
|
61
|
+
user_config.stdout_redirect @stdout, @stderr, @append
|
58
62
|
end
|
59
63
|
|
60
64
|
if @control_url
|
61
|
-
|
65
|
+
user_config.activate_control_app @control_url, @control_options
|
62
66
|
end
|
63
67
|
end
|
64
68
|
|
@@ -80,27 +84,35 @@ module Puma
|
|
80
84
|
raise UnsupportedOption
|
81
85
|
end
|
82
86
|
|
87
|
+
def configure_control_url(command_line_arg)
|
88
|
+
if command_line_arg
|
89
|
+
@control_url = command_line_arg
|
90
|
+
elsif Puma.jruby?
|
91
|
+
unsupported "No default url available on JRuby"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
83
95
|
# Build the OptionParser object to handle the available options.
|
84
96
|
#
|
85
97
|
|
86
98
|
def setup_options
|
87
|
-
@conf = Configuration.new do |
|
99
|
+
@conf = Configuration.new do |user_config, file_config|
|
88
100
|
@parser = OptionParser.new do |o|
|
89
101
|
o.on "-b", "--bind URI", "URI to bind to (tcp://, unix://, ssl://)" do |arg|
|
90
|
-
|
102
|
+
user_config.bind arg
|
91
103
|
end
|
92
104
|
|
93
105
|
o.on "-C", "--config PATH", "Load PATH as a config file" do |arg|
|
94
|
-
|
106
|
+
file_config.load arg
|
95
107
|
end
|
96
108
|
|
97
|
-
o.on "--control URL", "The bind url to use for the control server"
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
109
|
+
o.on "--control-url URL", "The bind url to use for the control server. Use 'auto' to use temp unix server" do |arg|
|
110
|
+
configure_control_url(arg)
|
111
|
+
end
|
112
|
+
|
113
|
+
# alias --control-url for backwards-compatibility
|
114
|
+
o.on "--control URL", "DEPRECATED alias for --control-url" do |arg|
|
115
|
+
configure_control_url(arg)
|
104
116
|
end
|
105
117
|
|
106
118
|
o.on "--control-token TOKEN",
|
@@ -109,21 +121,21 @@ module Puma
|
|
109
121
|
end
|
110
122
|
|
111
123
|
o.on "-d", "--daemon", "Daemonize the server into the background" do
|
112
|
-
|
113
|
-
|
124
|
+
user_config.daemonize
|
125
|
+
user_config.quiet
|
114
126
|
end
|
115
127
|
|
116
128
|
o.on "--debug", "Log lowlevel debugging information" do
|
117
|
-
|
129
|
+
user_config.debug
|
118
130
|
end
|
119
131
|
|
120
132
|
o.on "--dir DIR", "Change to DIR before starting" do |d|
|
121
|
-
|
133
|
+
user_config.directory d
|
122
134
|
end
|
123
135
|
|
124
136
|
o.on "-e", "--environment ENVIRONMENT",
|
125
137
|
"The environment to run the Rack app on (default development)" do |arg|
|
126
|
-
|
138
|
+
user_config.environment arg
|
127
139
|
end
|
128
140
|
|
129
141
|
o.on "-I", "--include PATH", "Specify $LOAD_PATH directories" do |arg|
|
@@ -132,50 +144,54 @@ module Puma
|
|
132
144
|
|
133
145
|
o.on "-p", "--port PORT", "Define the TCP port to bind to",
|
134
146
|
"Use -b for more advanced options" do |arg|
|
135
|
-
|
147
|
+
user_config.bind "tcp://#{Configuration::DefaultTCPHost}:#{arg}"
|
136
148
|
end
|
137
149
|
|
138
150
|
o.on "--pidfile PATH", "Use PATH as a pidfile" do |arg|
|
139
|
-
|
151
|
+
user_config.pidfile arg
|
140
152
|
end
|
141
153
|
|
142
154
|
o.on "--preload", "Preload the app. Cluster mode only" do
|
143
|
-
|
155
|
+
user_config.preload_app!
|
144
156
|
end
|
145
157
|
|
146
158
|
o.on "--prune-bundler", "Prune out the bundler env if possible" do
|
147
|
-
|
159
|
+
user_config.prune_bundler
|
148
160
|
end
|
149
161
|
|
150
162
|
o.on "-q", "--quiet", "Do not log requests internally (default true)" do
|
151
|
-
|
163
|
+
user_config.quiet
|
152
164
|
end
|
153
165
|
|
154
166
|
o.on "-v", "--log-requests", "Log requests as they occur" do
|
155
|
-
|
167
|
+
user_config.log_requests
|
156
168
|
end
|
157
169
|
|
158
170
|
o.on "-R", "--restart-cmd CMD",
|
159
171
|
"The puma command to run during a hot restart",
|
160
172
|
"Default: inferred" do |cmd|
|
161
|
-
|
173
|
+
user_config.restart_command cmd
|
162
174
|
end
|
163
175
|
|
164
176
|
o.on "-S", "--state PATH", "Where to store the state details" do |arg|
|
165
|
-
|
177
|
+
user_config.state_path arg
|
166
178
|
end
|
167
179
|
|
168
180
|
o.on '-t', '--threads INT', "min:max threads to use (default 0:16)" do |arg|
|
169
181
|
min, max = arg.split(":")
|
170
182
|
if max
|
171
|
-
|
183
|
+
user_config.threads min, max
|
172
184
|
else
|
173
|
-
|
185
|
+
user_config.threads min, min
|
174
186
|
end
|
175
187
|
end
|
176
188
|
|
177
189
|
o.on "--tcp-mode", "Run the app in raw TCP mode instead of HTTP mode" do
|
178
|
-
|
190
|
+
user_config.tcp_mode!
|
191
|
+
end
|
192
|
+
|
193
|
+
o.on "--early-hints", "Enable early hints support" do
|
194
|
+
user_config.early_hints
|
179
195
|
end
|
180
196
|
|
181
197
|
o.on "-V", "--version", "Print the version information" do
|
@@ -185,11 +201,11 @@ module Puma
|
|
185
201
|
|
186
202
|
o.on "-w", "--workers COUNT",
|
187
203
|
"Activate cluster mode: How many worker processes to create" do |arg|
|
188
|
-
|
204
|
+
user_config.workers arg
|
189
205
|
end
|
190
206
|
|
191
207
|
o.on "--tag NAME", "Additional text to display in process listing" do |arg|
|
192
|
-
|
208
|
+
user_config.tag arg
|
193
209
|
end
|
194
210
|
|
195
211
|
o.on "--redirect-stdout FILE", "Redirect STDOUT to a specific file" do |arg|
|
data/lib/puma/client.rb
CHANGED
@@ -8,6 +8,7 @@ end
|
|
8
8
|
|
9
9
|
require 'puma/detect'
|
10
10
|
require 'puma/delegation'
|
11
|
+
require 'tempfile'
|
11
12
|
|
12
13
|
if Puma::IS_JRUBY
|
13
14
|
# We have to work around some OpenSSL buffer/io-readiness bugs
|
@@ -20,6 +21,17 @@ module Puma
|
|
20
21
|
|
21
22
|
class ConnectionError < RuntimeError; end
|
22
23
|
|
24
|
+
# An instance of this class represents a unique request from a client.
|
25
|
+
# For example a web request from a browser or from CURL. This
|
26
|
+
#
|
27
|
+
# An instance of `Puma::Client` can be used as if it were an IO object
|
28
|
+
# for example it is passed into `IO.select` inside of the `Puma::Reactor`.
|
29
|
+
# This is accomplished by the `to_io` method which gets called on any
|
30
|
+
# non-IO objects being used with the IO api such as `IO.select.
|
31
|
+
#
|
32
|
+
# Instances of this class are responsible for knowing if
|
33
|
+
# the header and body are fully buffered via the `try_to_finish` method.
|
34
|
+
# They can be used to "time out" a response via the `timeout_at` reader.
|
23
35
|
class Client
|
24
36
|
include Puma::Const
|
25
37
|
extend Puma::Delegation
|
@@ -110,6 +122,7 @@ module Puma
|
|
110
122
|
begin
|
111
123
|
@io.close
|
112
124
|
rescue IOError
|
125
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
113
126
|
end
|
114
127
|
end
|
115
128
|
|
@@ -117,9 +130,123 @@ module Puma
|
|
117
130
|
# no body share this one object since it has no state.
|
118
131
|
EmptyBody = NullIO.new
|
119
132
|
|
133
|
+
def setup_chunked_body(body)
|
134
|
+
@chunked_body = true
|
135
|
+
@partial_part_left = 0
|
136
|
+
@prev_chunk = ""
|
137
|
+
|
138
|
+
@body = Tempfile.new(Const::PUMA_TMP_BASE)
|
139
|
+
@body.binmode
|
140
|
+
@tempfile = @body
|
141
|
+
|
142
|
+
return decode_chunk(body)
|
143
|
+
end
|
144
|
+
|
145
|
+
def decode_chunk(chunk)
|
146
|
+
if @partial_part_left > 0
|
147
|
+
if @partial_part_left <= chunk.size
|
148
|
+
@body << chunk[0..(@partial_part_left-3)] # skip the \r\n
|
149
|
+
chunk = chunk[@partial_part_left..-1]
|
150
|
+
else
|
151
|
+
@body << chunk
|
152
|
+
@partial_part_left -= chunk.size
|
153
|
+
return false
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
if @prev_chunk.empty?
|
158
|
+
io = StringIO.new(chunk)
|
159
|
+
else
|
160
|
+
io = StringIO.new(@prev_chunk+chunk)
|
161
|
+
@prev_chunk = ""
|
162
|
+
end
|
163
|
+
|
164
|
+
while !io.eof?
|
165
|
+
line = io.gets
|
166
|
+
if line.end_with?("\r\n")
|
167
|
+
len = line.strip.to_i(16)
|
168
|
+
if len == 0
|
169
|
+
@body.rewind
|
170
|
+
rest = io.read
|
171
|
+
@buffer = rest.empty? ? nil : rest
|
172
|
+
@requests_served += 1
|
173
|
+
@ready = true
|
174
|
+
return true
|
175
|
+
end
|
176
|
+
|
177
|
+
len += 2
|
178
|
+
|
179
|
+
part = io.read(len)
|
180
|
+
|
181
|
+
unless part
|
182
|
+
@partial_part_left = len
|
183
|
+
next
|
184
|
+
end
|
185
|
+
|
186
|
+
got = part.size
|
187
|
+
|
188
|
+
case
|
189
|
+
when got == len
|
190
|
+
@body << part[0..-3] # to skip the ending \r\n
|
191
|
+
when got <= len - 2
|
192
|
+
@body << part
|
193
|
+
@partial_part_left = len - part.size
|
194
|
+
when got == len - 1 # edge where we get just \r but not \n
|
195
|
+
@body << part[0..-2]
|
196
|
+
@partial_part_left = len - part.size
|
197
|
+
end
|
198
|
+
else
|
199
|
+
@prev_chunk = line
|
200
|
+
return false
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
return false
|
205
|
+
end
|
206
|
+
|
207
|
+
def read_chunked_body
|
208
|
+
while true
|
209
|
+
begin
|
210
|
+
chunk = @io.read_nonblock(4096)
|
211
|
+
rescue Errno::EAGAIN
|
212
|
+
return false
|
213
|
+
rescue SystemCallError, IOError
|
214
|
+
raise ConnectionError, "Connection error detected during read"
|
215
|
+
end
|
216
|
+
|
217
|
+
# No chunk means a closed socket
|
218
|
+
unless chunk
|
219
|
+
@body.close
|
220
|
+
@buffer = nil
|
221
|
+
@requests_served += 1
|
222
|
+
@ready = true
|
223
|
+
raise EOFError
|
224
|
+
end
|
225
|
+
|
226
|
+
return true if decode_chunk(chunk)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
120
230
|
def setup_body
|
121
|
-
@
|
231
|
+
if @env[HTTP_EXPECT] == CONTINUE
|
232
|
+
# TODO allow a hook here to check the headers before
|
233
|
+
# going forward
|
234
|
+
@io << HTTP_11_100
|
235
|
+
@io.flush
|
236
|
+
end
|
237
|
+
|
238
|
+
@read_header = false
|
239
|
+
|
122
240
|
body = @parser.body
|
241
|
+
|
242
|
+
te = @env[TRANSFER_ENCODING2]
|
243
|
+
|
244
|
+
if te && CHUNKED.casecmp(te) == 0
|
245
|
+
return setup_chunked_body(body)
|
246
|
+
end
|
247
|
+
|
248
|
+
@chunked_body = false
|
249
|
+
|
123
250
|
cl = @env[CONTENT_LENGTH]
|
124
251
|
|
125
252
|
unless cl
|
@@ -154,8 +281,6 @@ module Puma
|
|
154
281
|
|
155
282
|
@body_remain = remain
|
156
283
|
|
157
|
-
@read_header = false
|
158
|
-
|
159
284
|
return false
|
160
285
|
end
|
161
286
|
|
@@ -170,6 +295,14 @@ module Puma
|
|
170
295
|
raise ConnectionError, "Connection error detected during read"
|
171
296
|
end
|
172
297
|
|
298
|
+
# No data means a closed socket
|
299
|
+
unless data
|
300
|
+
@buffer = nil
|
301
|
+
@requests_served += 1
|
302
|
+
@ready = true
|
303
|
+
raise EOFError
|
304
|
+
end
|
305
|
+
|
173
306
|
if @buffer
|
174
307
|
@buffer << data
|
175
308
|
else
|
@@ -184,7 +317,7 @@ module Puma
|
|
184
317
|
raise HttpParserError,
|
185
318
|
"HEADER is longer than allowed, aborting client early."
|
186
319
|
end
|
187
|
-
|
320
|
+
|
188
321
|
false
|
189
322
|
end
|
190
323
|
|
@@ -199,6 +332,14 @@ module Puma
|
|
199
332
|
raise e
|
200
333
|
end
|
201
334
|
|
335
|
+
# No data means a closed socket
|
336
|
+
unless data
|
337
|
+
@buffer = nil
|
338
|
+
@requests_served += 1
|
339
|
+
@ready = true
|
340
|
+
raise EOFError
|
341
|
+
end
|
342
|
+
|
202
343
|
if @buffer
|
203
344
|
@buffer << data
|
204
345
|
else
|
@@ -246,6 +387,10 @@ module Puma
|
|
246
387
|
end
|
247
388
|
|
248
389
|
def read_body
|
390
|
+
if @chunked_body
|
391
|
+
return read_chunked_body
|
392
|
+
end
|
393
|
+
|
249
394
|
# Read an odd sized chunk so we can read even sized ones
|
250
395
|
# after this
|
251
396
|
remain = @body_remain
|