puma 4.3.12 → 6.0.2

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.

Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1618 -521
  3. data/LICENSE +23 -20
  4. data/README.md +130 -42
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +63 -26
  7. data/docs/compile_options.md +55 -0
  8. data/docs/deployment.md +60 -69
  9. data/docs/fork_worker.md +31 -0
  10. data/docs/jungle/README.md +9 -0
  11. data/{tools → docs}/jungle/rc.d/README.md +1 -1
  12. data/{tools → docs}/jungle/rc.d/puma +2 -2
  13. data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  14. data/docs/kubernetes.md +66 -0
  15. data/docs/nginx.md +2 -2
  16. data/docs/plugins.md +15 -15
  17. data/docs/rails_dev_mode.md +28 -0
  18. data/docs/restart.md +46 -23
  19. data/docs/signals.md +13 -11
  20. data/docs/stats.md +142 -0
  21. data/docs/systemd.md +85 -128
  22. data/docs/testing_benchmarks_local_files.md +150 -0
  23. data/docs/testing_test_rackup_ci_files.md +36 -0
  24. data/ext/puma_http11/PumaHttp11Service.java +2 -4
  25. data/ext/puma_http11/ext_help.h +1 -1
  26. data/ext/puma_http11/extconf.rb +49 -12
  27. data/ext/puma_http11/http11_parser.c +46 -48
  28. data/ext/puma_http11/http11_parser.h +2 -2
  29. data/ext/puma_http11/http11_parser.java.rl +3 -3
  30. data/ext/puma_http11/http11_parser.rl +3 -3
  31. data/ext/puma_http11/http11_parser_common.rl +2 -2
  32. data/ext/puma_http11/mini_ssl.c +250 -93
  33. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  34. data/ext/puma_http11/org/jruby/puma/Http11.java +6 -6
  35. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +4 -6
  36. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +241 -96
  37. data/ext/puma_http11/puma_http11.c +46 -57
  38. data/lib/puma/app/status.rb +52 -38
  39. data/lib/puma/binder.rb +232 -119
  40. data/lib/puma/cli.rb +33 -33
  41. data/lib/puma/client.rb +129 -88
  42. data/lib/puma/cluster/worker.rb +175 -0
  43. data/lib/puma/cluster/worker_handle.rb +97 -0
  44. data/lib/puma/cluster.rb +224 -231
  45. data/lib/puma/commonlogger.rb +2 -2
  46. data/lib/puma/configuration.rb +112 -87
  47. data/lib/puma/const.rb +86 -91
  48. data/lib/puma/control_cli.rb +99 -79
  49. data/lib/puma/detect.rb +31 -2
  50. data/lib/puma/dsl.rb +426 -110
  51. data/lib/puma/error_logger.rb +112 -0
  52. data/lib/puma/events.rb +16 -115
  53. data/lib/puma/io_buffer.rb +44 -2
  54. data/lib/puma/jruby_restart.rb +2 -59
  55. data/lib/puma/json_serialization.rb +96 -0
  56. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  57. data/lib/puma/launcher.rb +170 -148
  58. data/lib/puma/log_writer.rb +137 -0
  59. data/lib/puma/minissl/context_builder.rb +35 -19
  60. data/lib/puma/minissl.rb +213 -55
  61. data/lib/puma/null_io.rb +18 -1
  62. data/lib/puma/plugin/tmp_restart.rb +1 -1
  63. data/lib/puma/plugin.rb +3 -12
  64. data/lib/puma/rack/builder.rb +5 -9
  65. data/lib/puma/rack_default.rb +1 -1
  66. data/lib/puma/reactor.rb +85 -369
  67. data/lib/puma/request.rb +644 -0
  68. data/lib/puma/runner.rb +86 -76
  69. data/lib/puma/server.rb +306 -793
  70. data/lib/puma/single.rb +18 -74
  71. data/lib/puma/state_file.rb +45 -8
  72. data/lib/puma/systemd.rb +47 -0
  73. data/lib/puma/thread_pool.rb +136 -68
  74. data/lib/puma/util.rb +21 -4
  75. data/lib/puma.rb +54 -7
  76. data/lib/rack/handler/puma.rb +11 -12
  77. data/tools/{docker/Dockerfile → Dockerfile} +1 -1
  78. metadata +31 -23
  79. data/docs/tcp_mode.md +0 -96
  80. data/ext/puma_http11/io_buffer.c +0 -155
  81. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  82. data/lib/puma/accept_nonblock.rb +0 -29
  83. data/lib/puma/tcp_logger.rb +0 -41
  84. data/tools/jungle/README.md +0 -19
  85. data/tools/jungle/init.d/README.md +0 -61
  86. data/tools/jungle/init.d/puma +0 -421
  87. data/tools/jungle/init.d/run-puma +0 -18
  88. data/tools/jungle/upstart/README.md +0 -61
  89. data/tools/jungle/upstart/puma-manager.conf +0 -31
  90. data/tools/jungle/upstart/puma.conf +0 -69
@@ -3,7 +3,7 @@
3
3
  module Puma
4
4
  # Rack::CommonLogger forwards every request to the given +app+, and
5
5
  # logs a line in the
6
- # {Apache common log format}[http://httpd.apache.org/docs/1.3/logs.html#common]
6
+ # {Apache common log format}[https://httpd.apache.org/docs/1.3/logs.html#common]
7
7
  # to the +logger+.
8
8
  #
9
9
  # If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
@@ -16,7 +16,7 @@ module Puma
16
16
  # (which is called without arguments in order to make the error appear for
17
17
  # sure)
18
18
  class CommonLogger
19
- # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
19
+ # Common Log Format: https://httpd.apache.org/docs/1.3/logs.html#common
20
20
  #
21
21
  # lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
22
22
  #
@@ -1,20 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/rack/builder'
4
- require 'puma/plugin'
5
- require 'puma/const'
3
+ require_relative 'rack/builder'
4
+ require_relative 'plugin'
5
+ require_relative 'const'
6
+ # note that dsl is loaded at end of file, requires ConfigDefault constants
6
7
 
7
8
  module Puma
8
-
9
- module ConfigDefault
10
- DefaultRackup = "config.ru"
11
-
12
- DefaultTCPHost = "0.0.0.0"
13
- DefaultTCPPort = 9292
14
- DefaultWorkerTimeout = 60
15
- DefaultWorkerShutdownTimeout = 30
16
- end
17
-
18
9
  # A class used for storing "leveled" configuration options.
19
10
  #
20
11
  # In this class any "user" specified options take precedence over any
@@ -54,9 +45,7 @@ module Puma
54
45
  attr_reader :user_options, :file_options, :default_options
55
46
 
56
47
  def [](key)
57
- return user_options[key] if user_options.key?(key)
58
- return file_options[key] if file_options.key?(key)
59
- return default_options[key] if default_options.key?(key)
48
+ fetch(key)
60
49
  end
61
50
 
62
51
  def []=(key, value)
@@ -64,7 +53,11 @@ module Puma
64
53
  end
65
54
 
66
55
  def fetch(key, default_value = nil)
67
- self[key] || default_value
56
+ return user_options[key] if user_options.key?(key)
57
+ return file_options[key] if file_options.key?(key)
58
+ return default_options[key] if default_options.key?(key)
59
+
60
+ default_value
68
61
  end
69
62
 
70
63
  def all_of(key)
@@ -90,6 +83,12 @@ module Puma
90
83
  end
91
84
  end
92
85
  end
86
+
87
+ def final_options
88
+ default_options
89
+ .merge(file_options)
90
+ .merge(user_options)
91
+ end
93
92
  end
94
93
 
95
94
  # The main configuration class of Puma.
@@ -106,16 +105,17 @@ module Puma
106
105
  #
107
106
  # It also handles loading plugins.
108
107
  #
109
- # > Note: `:port` and `:host` are not valid keys. By they time they make it to the
108
+ # [Note:]
109
+ # `:port` and `:host` are not valid keys. By the time they make it to the
110
110
  # configuration options they are expected to be incorporated into a `:binds` key.
111
111
  # Under the hood the DSL maps `port` and `host` calls to `:binds`
112
112
  #
113
- # config = Configuration.new({}) do |user_config, file_config, default_config|
114
- # user_config.port 3003
115
- # end
116
- # config.load
117
- # puts config.options[:port]
118
- # # => 3003
113
+ # config = Configuration.new({}) do |user_config, file_config, default_config|
114
+ # user_config.port 3003
115
+ # end
116
+ # config.load
117
+ # puts config.options[:port]
118
+ # # => 3003
119
119
  #
120
120
  # It is expected that `load` is called on the configuration instance after setting
121
121
  # config. This method expands any values in `config_file` and puts them into the
@@ -126,7 +126,48 @@ module Puma
126
126
  # is done because an environment variable may have been modified while loading
127
127
  # configuration files.
128
128
  class Configuration
129
- include ConfigDefault
129
+ DEFAULTS = {
130
+ auto_trim_time: 30,
131
+ binds: ['tcp://0.0.0.0:9292'.freeze],
132
+ clean_thread_locals: false,
133
+ debug: false,
134
+ early_hints: nil,
135
+ environment: 'development'.freeze,
136
+ # Number of seconds to wait until we get the first data for the request
137
+ first_data_timeout: 30,
138
+ io_selector_backend: :auto,
139
+ log_requests: false,
140
+ logger: STDOUT,
141
+ # How many requests to attempt inline before sending a client back to
142
+ # the reactor to be subject to normal ordering. The idea here is that
143
+ # we amortize the cost of going back to the reactor for a well behaved
144
+ # but very "greedy" client across 10 requests. This prevents a not
145
+ # well behaved client from monopolizing the thread forever.
146
+ max_fast_inline: 10,
147
+ max_threads: Puma.mri? ? 5 : 16,
148
+ min_threads: 0,
149
+ mode: :http,
150
+ mutate_stdout_and_stderr_to_sync_on_write: true,
151
+ out_of_band: [],
152
+ # Number of seconds for another request within a persistent session.
153
+ persistent_timeout: 20,
154
+ queue_requests: true,
155
+ rackup: 'config.ru'.freeze,
156
+ raise_exception_on_sigterm: true,
157
+ reaping_time: 1,
158
+ remote_address: :socket,
159
+ silence_single_worker_warning: false,
160
+ tag: File.basename(Dir.getwd),
161
+ tcp_host: '0.0.0.0'.freeze,
162
+ tcp_port: 9292,
163
+ wait_for_less_busy_worker: 0.005,
164
+ worker_boot_timeout: 60,
165
+ worker_check_interval: 5,
166
+ worker_culling_strategy: :youngest,
167
+ worker_shutdown_timeout: 30,
168
+ worker_timeout: 60,
169
+ workers: 0,
170
+ }
130
171
 
131
172
  def initialize(user_options={}, default_options = {}, &block)
132
173
  default_options = self.puma_default_options.merge(default_options)
@@ -137,6 +178,10 @@ module Puma
137
178
  @file_dsl = DSL.new(@options.file_options, self)
138
179
  @default_dsl = DSL.new(@options.default_options, self)
139
180
 
181
+ if !@options[:prune_bundler]
182
+ default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
183
+ end
184
+
140
185
  if block
141
186
  configure(&block)
142
187
  end
@@ -168,26 +213,21 @@ module Puma
168
213
  end
169
214
 
170
215
  def puma_default_options
216
+ defaults = DEFAULTS.dup
217
+ puma_options_from_env.each { |k,v| defaults[k] = v if v }
218
+ defaults
219
+ end
220
+
221
+ def puma_options_from_env
222
+ min = ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS']
223
+ max = ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS']
224
+ workers = ENV['WEB_CONCURRENCY']
225
+
171
226
  {
172
- :min_threads => 0,
173
- :max_threads => 16,
174
- :log_requests => false,
175
- :debug => false,
176
- :binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
177
- :workers => 0,
178
- :daemon => false,
179
- :mode => :http,
180
- :worker_timeout => DefaultWorkerTimeout,
181
- :worker_boot_timeout => DefaultWorkerTimeout,
182
- :worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
183
- :remote_address => :socket,
184
- :tag => method(:infer_tag),
185
- :environment => -> { ENV['RACK_ENV'] || "development" },
186
- :rackup => DefaultRackup,
187
- :logger => STDOUT,
188
- :persistent_timeout => Const::PERSISTENT_TIMEOUT,
189
- :first_data_timeout => Const::FIRST_DATA_TIMEOUT,
190
- :raise_exception_on_sigterm => true
227
+ min_threads: min && Integer(min),
228
+ max_threads: max && Integer(max),
229
+ workers: workers && Integer(workers),
230
+ environment: ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'],
191
231
  }
192
232
  end
193
233
 
@@ -203,7 +243,7 @@ module Puma
203
243
  return [] if files == ['-']
204
244
  return files if files.any?
205
245
 
206
- first_default_file = %W(config/puma/#{environment_str}.rb config/puma.rb).find do |f|
246
+ first_default_file = %W(config/puma/#{@options[:environment]}.rb config/puma.rb).find do |f|
207
247
  File.exist?(f)
208
248
  end
209
249
 
@@ -245,16 +285,8 @@ module Puma
245
285
  def app
246
286
  found = options[:app] || load_rackup
247
287
 
248
- if @options[:mode] == :tcp
249
- require 'puma/tcp_logger'
250
-
251
- logger = @options[:logger]
252
- quiet = !@options[:log_requests]
253
- return TCPLogger.new(logger, found, quiet)
254
- end
255
-
256
288
  if @options[:log_requests]
257
- require 'puma/commonlogger'
289
+ require_relative 'commonlogger'
258
290
  logger = @options[:logger]
259
291
  found = CommonLogger.new(found, logger)
260
292
  end
@@ -267,16 +299,31 @@ module Puma
267
299
  @options[:environment]
268
300
  end
269
301
 
270
- def environment_str
271
- environment.respond_to?(:call) ? environment.call : environment
272
- end
273
-
274
302
  def load_plugin(name)
275
303
  @plugins.create name
276
304
  end
277
305
 
278
- def run_hooks(key, arg)
279
- @options.all_of(key).each { |b| b.call arg }
306
+ # @param key [:Symbol] hook to run
307
+ # @param arg [Launcher, Int] `:on_restart` passes Launcher
308
+ #
309
+ def run_hooks(key, arg, log_writer, hook_data = nil)
310
+ @options.all_of(key).each do |b|
311
+ begin
312
+ if Array === b
313
+ hook_data[b[1]] ||= Hash.new
314
+ b[0].call arg, hook_data[b[1]]
315
+ else
316
+ b.call arg
317
+ end
318
+ rescue => e
319
+ log_writer.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
320
+ log_writer.debug e.backtrace.join("\n")
321
+ end
322
+ end
323
+ end
324
+
325
+ def final_options
326
+ @options.final_options
280
327
  end
281
328
 
282
329
  def self.temp_path
@@ -288,10 +335,6 @@ module Puma
288
335
 
289
336
  private
290
337
 
291
- def infer_tag
292
- File.basename(Dir.getwd)
293
- end
294
-
295
338
  # Load and use the normal Rack builder if we can, otherwise
296
339
  # fallback to our minimal version.
297
340
  def rack_builder
@@ -319,6 +362,8 @@ module Puma
319
362
  raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
320
363
 
321
364
  rack_app, rack_options = rack_builder.parse_file(rackup)
365
+ rack_options = rack_options || {}
366
+
322
367
  @options.file_options.merge!(rack_options)
323
368
 
324
369
  config_ru_binds = []
@@ -332,31 +377,11 @@ module Puma
332
377
  end
333
378
 
334
379
  def self.random_token
335
- begin
336
- require 'openssl'
337
- rescue LoadError
338
- end
339
-
340
- count = 16
341
-
342
- bytes = nil
343
-
344
- if defined? OpenSSL::Random
345
- bytes = OpenSSL::Random.random_bytes(count)
346
- elsif File.exist?("/dev/urandom")
347
- File.open('/dev/urandom') { |f| bytes = f.read(count) }
348
- end
349
-
350
- if bytes
351
- token = "".dup
352
- bytes.each_byte { |b| token << b.to_s(16) }
353
- else
354
- token = (0..count).to_a.map { rand(255).to_s(16) }.join
355
- end
380
+ require 'securerandom' unless defined?(SecureRandom)
356
381
 
357
- return token
382
+ SecureRandom.hex(16)
358
383
  end
359
384
  end
360
385
  end
361
386
 
362
- require 'puma/dsl'
387
+ require_relative 'dsl'
data/lib/puma/const.rb CHANGED
@@ -5,7 +5,6 @@ module Puma
5
5
  class UnsupportedOption < RuntimeError
6
6
  end
7
7
 
8
-
9
8
  # Every standard HTTP code mapped to the appropriate message. These are
10
9
  # used so frequently that they are placed directly in Puma for easy
11
10
  # access rather than Puma::Const itself.
@@ -100,54 +99,40 @@ module Puma
100
99
  # too taxing on performance.
101
100
  module Const
102
101
 
103
- PUMA_VERSION = VERSION = "4.3.12".freeze
104
- CODE_NAME = "Mysterious Traveller".freeze
105
- PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
106
-
107
- FAST_TRACK_KA_TIMEOUT = 0.2
102
+ PUMA_VERSION = VERSION = "6.0.2"
103
+ CODE_NAME = "Sunflower"
108
104
 
109
- # The default number of seconds for another request within a persistent
110
- # session.
111
- PERSISTENT_TIMEOUT = 20
105
+ PUMA_SERVER_STRING = ["puma", PUMA_VERSION, CODE_NAME].join(" ").freeze
112
106
 
113
- # The default number of seconds to wait until we get the first data
114
- # for the request
115
- FIRST_DATA_TIMEOUT = 30
107
+ FAST_TRACK_KA_TIMEOUT = 0.2
116
108
 
117
109
  # How long to wait when getting some write blocking on the socket when
118
110
  # sending data back
119
111
  WRITE_TIMEOUT = 10
120
112
 
121
- # How many requests to attempt inline before sending a client back to
122
- # the reactor to be subject to normal ordering. The idea here is that
123
- # we amortize the cost of going back to the reactor for a well behaved
124
- # but very "greedy" client across 10 requests. This prevents a not
125
- # well behaved client from monopolizing the thread forever.
126
- MAX_FAST_INLINE = 10
127
-
128
113
  # The original URI requested by the client.
129
- REQUEST_URI= 'REQUEST_URI'.freeze
130
- REQUEST_PATH = 'REQUEST_PATH'.freeze
131
- QUERY_STRING = 'QUERY_STRING'.freeze
132
- CONTENT_LENGTH = "CONTENT_LENGTH".freeze
114
+ REQUEST_URI= "REQUEST_URI"
115
+ REQUEST_PATH = "REQUEST_PATH"
116
+ QUERY_STRING = "QUERY_STRING"
117
+ CONTENT_LENGTH = "CONTENT_LENGTH"
133
118
 
134
- PATH_INFO = 'PATH_INFO'.freeze
119
+ PATH_INFO = "PATH_INFO"
135
120
 
136
- PUMA_TMP_BASE = "puma".freeze
121
+ PUMA_TMP_BASE = "puma"
137
122
 
138
123
  ERROR_RESPONSE = {
139
124
  # Indicate that we couldn't parse the request
140
- 400 => "HTTP/1.1 400 Bad Request\r\n\r\n".freeze,
125
+ 400 => "HTTP/1.1 400 Bad Request\r\n\r\n",
141
126
  # The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
142
- 404 => "HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\nNOT FOUND".freeze,
127
+ 404 => "HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\nNOT FOUND",
143
128
  # The standard empty 408 response for requests that timed out.
144
- 408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\n".freeze,
129
+ 408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\n",
145
130
  # Indicate that there was an internal error, obviously.
146
- 500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n".freeze,
131
+ 500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n",
147
132
  # Incorrect or invalid header value
148
- 501 => "HTTP/1.1 501 Not Implemented\r\n\r\n".freeze,
133
+ 501 => "HTTP/1.1 501 Not Implemented\r\n\r\n",
149
134
  # A common header for indicating the server is too busy. Not used yet.
150
- 503 => "HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY".freeze
135
+ 503 => "HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY"
151
136
  }.freeze
152
137
 
153
138
  # The basic max request size we'll try to read.
@@ -160,86 +145,96 @@ module Puma
160
145
  # Maximum request body size before it is moved out of memory and into a tempfile for reading.
161
146
  MAX_BODY = MAX_HEADER
162
147
 
163
- REQUEST_METHOD = "REQUEST_METHOD".freeze
164
- HEAD = "HEAD".freeze
148
+ REQUEST_METHOD = "REQUEST_METHOD"
149
+ HEAD = "HEAD"
150
+ SUPPORTED_HTTP_METHODS = %w[HEAD GET POST PUT DELETE OPTIONS TRACE PATCH].freeze
165
151
  # ETag is based on the apache standard of hex mtime-size-inode (inode is 0 on win32)
166
- LINE_END = "\r\n".freeze
167
- REMOTE_ADDR = "REMOTE_ADDR".freeze
168
- HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze
169
- HTTP_X_FORWARDED_SSL = "HTTP_X_FORWARDED_SSL".freeze
170
- HTTP_X_FORWARDED_SCHEME = "HTTP_X_FORWARDED_SCHEME".freeze
171
- HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO".freeze
152
+ LINE_END = "\r\n"
153
+ REMOTE_ADDR = "REMOTE_ADDR"
154
+ HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
155
+ HTTP_X_FORWARDED_SSL = "HTTP_X_FORWARDED_SSL"
156
+ HTTP_X_FORWARDED_SCHEME = "HTTP_X_FORWARDED_SCHEME"
157
+ HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO"
158
+
159
+ SERVER_NAME = "SERVER_NAME"
160
+ SERVER_PORT = "SERVER_PORT"
161
+ HTTP_HOST = "HTTP_HOST"
162
+ PORT_80 = "80"
163
+ PORT_443 = "443"
164
+ LOCALHOST = "localhost"
165
+ LOCALHOST_IPV4 = "127.0.0.1"
166
+ LOCALHOST_IPV6 = "::1"
167
+ UNSPECIFIED_IPV4 = "0.0.0.0"
168
+ UNSPECIFIED_IPV6 = "::"
172
169
 
173
- SERVER_NAME = "SERVER_NAME".freeze
174
- SERVER_PORT = "SERVER_PORT".freeze
175
- HTTP_HOST = "HTTP_HOST".freeze
176
- PORT_80 = "80".freeze
177
- PORT_443 = "443".freeze
178
- LOCALHOST = "localhost".freeze
179
- LOCALHOST_IP = "127.0.0.1".freeze
180
- LOCALHOST_ADDR = "127.0.0.1:0".freeze
170
+ SERVER_PROTOCOL = "SERVER_PROTOCOL"
171
+ HTTP_11 = "HTTP/1.1"
181
172
 
182
- SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
183
- HTTP_11 = "HTTP/1.1".freeze
173
+ SERVER_SOFTWARE = "SERVER_SOFTWARE"
174
+ GATEWAY_INTERFACE = "GATEWAY_INTERFACE"
175
+ CGI_VER = "CGI/1.2"
184
176
 
185
- SERVER_SOFTWARE = "SERVER_SOFTWARE".freeze
186
- GATEWAY_INTERFACE = "GATEWAY_INTERFACE".freeze
187
- CGI_VER = "CGI/1.2".freeze
177
+ STOP_COMMAND = "?"
178
+ HALT_COMMAND = "!"
179
+ RESTART_COMMAND = "R"
188
180
 
189
- STOP_COMMAND = "?".freeze
190
- HALT_COMMAND = "!".freeze
191
- RESTART_COMMAND = "R".freeze
181
+ RACK_INPUT = "rack.input"
182
+ RACK_URL_SCHEME = "rack.url_scheme"
183
+ RACK_AFTER_REPLY = "rack.after_reply"
184
+ PUMA_SOCKET = "puma.socket"
185
+ PUMA_CONFIG = "puma.config"
186
+ PUMA_PEERCERT = "puma.peercert"
192
187
 
193
- RACK_INPUT = "rack.input".freeze
194
- RACK_URL_SCHEME = "rack.url_scheme".freeze
195
- RACK_AFTER_REPLY = "rack.after_reply".freeze
196
- PUMA_SOCKET = "puma.socket".freeze
197
- PUMA_CONFIG = "puma.config".freeze
198
- PUMA_PEERCERT = "puma.peercert".freeze
188
+ HTTP = "http"
189
+ HTTPS = "https"
199
190
 
200
- HTTP = "http".freeze
201
- HTTPS = "https".freeze
191
+ HTTPS_KEY = "HTTPS"
202
192
 
203
- HTTPS_KEY = "HTTPS".freeze
193
+ HTTP_VERSION = "HTTP_VERSION"
194
+ HTTP_CONNECTION = "HTTP_CONNECTION"
195
+ HTTP_EXPECT = "HTTP_EXPECT"
196
+ CONTINUE = "100-continue"
204
197
 
205
- HTTP_VERSION = "HTTP_VERSION".freeze
206
- HTTP_CONNECTION = "HTTP_CONNECTION".freeze
207
- HTTP_EXPECT = "HTTP_EXPECT".freeze
208
- CONTINUE = "100-continue".freeze
198
+ HTTP_11_100 = "HTTP/1.1 100 Continue\r\n\r\n"
199
+ HTTP_11_200 = "HTTP/1.1 200 OK\r\n"
200
+ HTTP_10_200 = "HTTP/1.0 200 OK\r\n"
209
201
 
210
- HTTP_11_100 = "HTTP/1.1 100 Continue\r\n\r\n".freeze
211
- HTTP_11_200 = "HTTP/1.1 200 OK\r\n".freeze
212
- HTTP_10_200 = "HTTP/1.0 200 OK\r\n".freeze
202
+ CLOSE = "close"
203
+ KEEP_ALIVE = "keep-alive"
213
204
 
214
- CLOSE = "close".freeze
215
- KEEP_ALIVE = "keep-alive".freeze
205
+ CONTENT_LENGTH2 = "content-length"
206
+ CONTENT_LENGTH_S = "Content-Length: "
207
+ TRANSFER_ENCODING = "transfer-encoding"
208
+ TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING"
216
209
 
217
- CONTENT_LENGTH2 = "content-length".freeze
218
- CONTENT_LENGTH_S = "Content-Length: ".freeze
219
- TRANSFER_ENCODING = "transfer-encoding".freeze
220
- TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING".freeze
210
+ CONNECTION_CLOSE = "Connection: close\r\n"
211
+ CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n"
221
212
 
222
- CONNECTION_CLOSE = "Connection: close\r\n".freeze
223
- CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n".freeze
213
+ TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n"
214
+ CLOSE_CHUNKED = "0\r\n\r\n"
224
215
 
225
- TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n".freeze
226
- CLOSE_CHUNKED = "0\r\n\r\n".freeze
216
+ CHUNKED = "chunked"
227
217
 
228
- CHUNKED = "chunked".freeze
218
+ COLON = ": "
229
219
 
230
- COLON = ": ".freeze
220
+ NEWLINE = "\n"
231
221
 
232
- NEWLINE = "\n".freeze
233
- HTTP_INJECTION_REGEX = /[\r\n]/.freeze
222
+ HIJACK_P = "rack.hijack?"
223
+ HIJACK = "rack.hijack"
224
+ HIJACK_IO = "rack.hijack_io"
234
225
 
235
- HIJACK_P = "rack.hijack?".freeze
236
- HIJACK = "rack.hijack".freeze
237
- HIJACK_IO = "rack.hijack_io".freeze
226
+ EARLY_HINTS = "rack.early_hints"
238
227
 
239
- EARLY_HINTS = "rack.early_hints".freeze
228
+ # Illegal character in the key or value of response header
229
+ DQUOTE = "\""
230
+ HTTP_HEADER_DELIMITER = Regexp.escape("(),/:;<=>?@[]{}\\").freeze
231
+ ILLEGAL_HEADER_KEY_REGEX = /[\x00-\x20#{DQUOTE}#{HTTP_HEADER_DELIMITER}]/.freeze
232
+ # header values can contain HTAB?
233
+ ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze
240
234
 
241
- # Mininum interval to checks worker health
242
- WORKER_CHECK_INTERVAL = 5
235
+ # Banned keys of response header
236
+ BANNED_HEADER_KEY = /\A(rack\.|status\z)/.freeze
243
237
 
238
+ PROXY_PROTOCOL_V1_REGEX = /^PROXY (?:TCP4|TCP6|UNKNOWN) ([^\r]+)\r\n/.freeze
244
239
  end
245
240
  end