wendell-puma 2.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +55 -0
  3. data/DEPLOYMENT.md +92 -0
  4. data/Gemfile +17 -0
  5. data/History.txt +588 -0
  6. data/LICENSE +26 -0
  7. data/Manifest.txt +68 -0
  8. data/README.md +251 -0
  9. data/Rakefile +158 -0
  10. data/bin/puma +10 -0
  11. data/bin/puma-wild +31 -0
  12. data/bin/pumactl +12 -0
  13. data/docs/config.md +0 -0
  14. data/docs/nginx.md +80 -0
  15. data/docs/signals.md +43 -0
  16. data/ext/puma_http11/PumaHttp11Service.java +17 -0
  17. data/ext/puma_http11/ext_help.h +15 -0
  18. data/ext/puma_http11/extconf.rb +9 -0
  19. data/ext/puma_http11/http11_parser.c +1225 -0
  20. data/ext/puma_http11/http11_parser.h +64 -0
  21. data/ext/puma_http11/http11_parser.java.rl +161 -0
  22. data/ext/puma_http11/http11_parser.rl +146 -0
  23. data/ext/puma_http11/http11_parser_common.rl +54 -0
  24. data/ext/puma_http11/io_buffer.c +155 -0
  25. data/ext/puma_http11/mini_ssl.c +198 -0
  26. data/ext/puma_http11/org/jruby/puma/Http11.java +225 -0
  27. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +488 -0
  28. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +391 -0
  29. data/ext/puma_http11/puma_http11.c +491 -0
  30. data/lib/puma.rb +14 -0
  31. data/lib/puma/accept_nonblock.rb +23 -0
  32. data/lib/puma/app/status.rb +59 -0
  33. data/lib/puma/binder.rb +298 -0
  34. data/lib/puma/capistrano.rb +86 -0
  35. data/lib/puma/cli.rb +606 -0
  36. data/lib/puma/client.rb +289 -0
  37. data/lib/puma/cluster.rb +404 -0
  38. data/lib/puma/compat.rb +18 -0
  39. data/lib/puma/configuration.rb +377 -0
  40. data/lib/puma/const.rb +165 -0
  41. data/lib/puma/control_cli.rb +251 -0
  42. data/lib/puma/daemon_ext.rb +25 -0
  43. data/lib/puma/delegation.rb +11 -0
  44. data/lib/puma/detect.rb +4 -0
  45. data/lib/puma/events.rb +130 -0
  46. data/lib/puma/io_buffer.rb +7 -0
  47. data/lib/puma/java_io_buffer.rb +45 -0
  48. data/lib/puma/jruby_restart.rb +83 -0
  49. data/lib/puma/minissl.rb +187 -0
  50. data/lib/puma/null_io.rb +34 -0
  51. data/lib/puma/rack_default.rb +7 -0
  52. data/lib/puma/rack_patch.rb +45 -0
  53. data/lib/puma/reactor.rb +183 -0
  54. data/lib/puma/runner.rb +146 -0
  55. data/lib/puma/server.rb +801 -0
  56. data/lib/puma/single.rb +102 -0
  57. data/lib/puma/tcp_logger.rb +32 -0
  58. data/lib/puma/thread_pool.rb +185 -0
  59. data/lib/puma/util.rb +9 -0
  60. data/lib/rack/handler/puma.rb +66 -0
  61. data/test/test_app_status.rb +92 -0
  62. data/test/test_cli.rb +173 -0
  63. data/test/test_config.rb +26 -0
  64. data/test/test_http10.rb +27 -0
  65. data/test/test_http11.rb +144 -0
  66. data/test/test_integration.rb +165 -0
  67. data/test/test_iobuffer.rb +38 -0
  68. data/test/test_minissl.rb +29 -0
  69. data/test/test_null_io.rb +31 -0
  70. data/test/test_persistent.rb +238 -0
  71. data/test/test_puma_server.rb +288 -0
  72. data/test/test_puma_server_ssl.rb +137 -0
  73. data/test/test_rack_handler.rb +10 -0
  74. data/test/test_rack_server.rb +141 -0
  75. data/test/test_tcp_rack.rb +42 -0
  76. data/test/test_thread_pool.rb +156 -0
  77. data/test/test_unix_socket.rb +39 -0
  78. data/test/test_ws.rb +89 -0
  79. data/tools/jungle/README.md +9 -0
  80. data/tools/jungle/init.d/README.md +54 -0
  81. data/tools/jungle/init.d/puma +332 -0
  82. data/tools/jungle/init.d/run-puma +3 -0
  83. data/tools/jungle/upstart/README.md +61 -0
  84. data/tools/jungle/upstart/puma-manager.conf +31 -0
  85. data/tools/jungle/upstart/puma.conf +63 -0
  86. data/tools/trickletest.rb +45 -0
  87. data/wendell-puma.gemspec +55 -0
  88. metadata +225 -0
@@ -0,0 +1,18 @@
1
+ # Provides code to work properly on 1.8 and 1.9
2
+
3
+ class String
4
+ unless method_defined? :bytesize
5
+ alias_method :bytesize, :size
6
+ end
7
+
8
+ unless method_defined? :byteslice
9
+ if RUBY_VERSION < '1.9'
10
+ alias_method :byteslice, :[]
11
+ else
12
+ def byteslice(*arg)
13
+ enc = self.encoding
14
+ self.dup.force_encoding(Encoding::ASCII_8BIT).slice(*arg).force_encoding(enc)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,377 @@
1
+ module Puma
2
+
3
+ # The CLI exports it's Configuration object here to allow
4
+ # apps to pick it up. An app needs to use it conditionally though
5
+ # since it is not set if the app is launched via another
6
+ # mechanism than the CLI class.
7
+
8
+ class << self
9
+ attr_accessor :cli_config
10
+ end
11
+
12
+ class Configuration
13
+ DefaultRackup = "config.ru"
14
+
15
+ DefaultTCPHost = "0.0.0.0"
16
+ DefaultTCPPort = 9292
17
+ DefaultWorkerTimeout = 60
18
+
19
+ def initialize(options)
20
+ @options = options
21
+ @options[:mode] ||= :http
22
+ @options[:binds] ||= []
23
+ @options[:on_restart] ||= []
24
+ @options[:before_worker_boot] ||= []
25
+ @options[:after_worker_boot] ||= []
26
+ @options[:worker_timeout] ||= DefaultWorkerTimeout
27
+ end
28
+
29
+ attr_reader :options
30
+
31
+ def initialize_copy(other)
32
+ @options = @options.dup
33
+ end
34
+
35
+ def load
36
+ if path = @options[:config_file]
37
+ DSL.new(@options)._load_from path
38
+ end
39
+
40
+ # Rakeup default option support
41
+ if host = @options[:Host]
42
+ port = @options[:Port] || DefaultTCPPort
43
+
44
+ @options[:binds] << "tcp://#{host}:#{port}"
45
+ end
46
+
47
+ if @options[:binds].empty?
48
+ @options[:binds] << "tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"
49
+ end
50
+
51
+ if @options[:control_url] == "auto"
52
+ path = Configuration.temp_path
53
+ @options[:control_url] = "unix://#{path}"
54
+ @options[:control_url_temp] = path
55
+ end
56
+
57
+ unless @options[:control_auth_token]
58
+ setup_random_token
59
+ end
60
+ end
61
+
62
+ # Injects the Configuration object into the env
63
+ class ConfigMiddleware
64
+ def initialize(config, app)
65
+ @config = config
66
+ @app = app
67
+ end
68
+
69
+ def call(env)
70
+ env[Const::PUMA_CONFIG] = @config
71
+ @app.call(env)
72
+ end
73
+ end
74
+
75
+ # Indicate if there is a properly configured app
76
+ #
77
+ def app_configured?
78
+ @options[:app] || File.exist?(rackup)
79
+ end
80
+
81
+ def rackup
82
+ @options[:rackup] || DefaultRackup
83
+ end
84
+
85
+ # Load the specified rackup file, pull an options from
86
+ # the rackup file, and set @app.
87
+ #
88
+ def app
89
+ app = @options[:app]
90
+
91
+ unless app
92
+ unless File.exist?(rackup)
93
+ raise "Missing rackup file '#{rackup}'"
94
+ end
95
+
96
+ app, options = Rack::Builder.parse_file rackup
97
+ @options.merge! options
98
+
99
+ options.each do |key,val|
100
+ if key.to_s[0,4] == "bind"
101
+ @options[:binds] << val
102
+ end
103
+ end
104
+ end
105
+
106
+ if @options[:mode] == :tcp
107
+ require 'puma/tcp_logger'
108
+
109
+ logger = @options[:logger] || STDOUT
110
+ return TCPLogger.new(logger, app, @options[:quiet])
111
+ end
112
+
113
+ if !@options[:quiet] and @options[:environment] == "development"
114
+ logger = @options[:logger] || STDOUT
115
+ app = Rack::CommonLogger.new(app, logger)
116
+ end
117
+
118
+ return ConfigMiddleware.new(self, app)
119
+ end
120
+
121
+ def setup_random_token
122
+ begin
123
+ require 'openssl'
124
+ rescue LoadError
125
+ end
126
+
127
+ count = 16
128
+
129
+ bytes = nil
130
+
131
+ if defined? OpenSSL::Random
132
+ bytes = OpenSSL::Random.random_bytes(count)
133
+ elsif File.exist?("/dev/urandom")
134
+ File.open("/dev/urandom") do |f|
135
+ bytes = f.read(count)
136
+ end
137
+ end
138
+
139
+ if bytes
140
+ token = ""
141
+ bytes.each_byte { |b| token << b.to_s(16) }
142
+ else
143
+ token = (0..count).to_a.map { rand(255).to_s(16) }.join
144
+ end
145
+
146
+ @options[:control_auth_token] = token
147
+ end
148
+
149
+ def self.temp_path
150
+ require 'tmpdir'
151
+
152
+ t = (Time.now.to_f * 1000).to_i
153
+ "#{Dir.tmpdir}/puma-status-#{t}-#{$$}"
154
+ end
155
+
156
+ # The methods that are available for use inside the config file.
157
+ #
158
+ class DSL
159
+ def initialize(options)
160
+ @options = options
161
+ end
162
+
163
+ def _load_from(path)
164
+ instance_eval File.read(path), path, 1
165
+ end
166
+
167
+ # Use +obj+ or +block+ as the Rack app. This allows a config file to
168
+ # be the app itself.
169
+ #
170
+ def app(obj=nil, &block)
171
+ obj ||= block
172
+
173
+ raise "Provide either a #call'able or a block" unless obj
174
+
175
+ @options[:app] = obj
176
+ end
177
+
178
+ # Start the Puma control rack app on +url+. This app can be communicated
179
+ # with to control the main server.
180
+ #
181
+ def activate_control_app(url="auto", opts=nil)
182
+ @options[:control_url] = url
183
+
184
+ if opts
185
+ if tok = opts[:auth_token]
186
+ @options[:control_auth_token] = tok
187
+ end
188
+
189
+ if opts[:no_token]
190
+ @options[:control_auth_token] = :none
191
+ end
192
+ end
193
+ end
194
+
195
+ # Bind the server to +url+. tcp:// and unix:// are the only accepted
196
+ # protocols.
197
+ #
198
+ def bind(url)
199
+ @options[:binds] << url
200
+ end
201
+
202
+ # Define the TCP port to bind to. Use +bind+ for more advanced options.
203
+ #
204
+ def port(port)
205
+ @options[:binds] << "tcp://#{Configuration::DefaultTCPHost}:#{port}"
206
+ end
207
+
208
+ # Daemonize the server into the background. Highly suggest that
209
+ # this be combined with +pidfile+ and +stdout_redirect+.
210
+ def daemonize(which=true)
211
+ @options[:daemon] = which
212
+ end
213
+
214
+ # When shutting down, drain the accept socket of pending
215
+ # connections and proces them. This loops over the accept
216
+ # socket until there are no more read events and then stops
217
+ # looking and waits for the requests to finish.
218
+ def drain_on_shutdown(which=true)
219
+ @options[:drain_on_shutdown] = which
220
+ end
221
+
222
+ # Set the environment in which the Rack's app will run.
223
+ def environment(environment)
224
+ @options[:environment] = environment
225
+ end
226
+
227
+ # Code to run before doing a restart. This code should
228
+ # close logfiles, database connections, etc.
229
+ #
230
+ # This can be called multiple times to add code each time.
231
+ #
232
+ def on_restart(&block)
233
+ @options[:on_restart] << block
234
+ end
235
+
236
+ # Command to use to restart puma. This should be just how to
237
+ # load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
238
+ # to puma, as those are the same as the original process.
239
+ #
240
+ def restart_command(cmd)
241
+ @options[:restart_cmd] = cmd
242
+ end
243
+
244
+ # Store the pid of the server in the file at +path+.
245
+ def pidfile(path)
246
+ @options[:pidfile] = path
247
+ end
248
+
249
+ # Disable request logging.
250
+ #
251
+ def quiet
252
+ @options[:quiet] = true
253
+ end
254
+
255
+ # Load +path+ as a rackup file.
256
+ #
257
+ def rackup(path)
258
+ @options[:rackup] = path.to_s
259
+ end
260
+
261
+ # Redirect STDOUT and STDERR to files specified.
262
+ def stdout_redirect(stdout=nil, stderr=nil, append=false)
263
+ @options[:redirect_stdout] = stdout
264
+ @options[:redirect_stderr] = stderr
265
+ @options[:redirect_append] = append
266
+ end
267
+
268
+ # Configure +min+ to be the minimum number of threads to use to answer
269
+ # requests and +max+ the maximum.
270
+ #
271
+ def threads(min, max)
272
+ min = Integer(min)
273
+ max = Integer(max)
274
+ if min > max
275
+ raise "The minimum (#{min}) number of threads must be less than the max (#{max})"
276
+ end
277
+
278
+ @options[:min_threads] = min
279
+ @options[:max_threads] = max
280
+ end
281
+
282
+ def ssl_bind(host, port, opts)
283
+ o = [
284
+ "cert=#{opts[:cert]}",
285
+ "key=#{opts[:key]}"
286
+ ]
287
+
288
+ @options[:binds] << "ssl://#{host}:#{port}?#{o.join('&')}"
289
+ end
290
+
291
+ # Use +path+ as the file to store the server info state. This is
292
+ # used by pumactl to query and control the server.
293
+ #
294
+ def state_path(path)
295
+ @options[:state] = path.to_s
296
+ end
297
+
298
+ # *Cluster mode only* How many worker processes to run.
299
+ #
300
+ def workers(count)
301
+ @options[:workers] = count.to_i
302
+ end
303
+
304
+ # *Cluster mode only* Code to run when a worker boots to setup
305
+ # the process before booting the app.
306
+ #
307
+ # This can be called multiple times to add hooks.
308
+ #
309
+ def on_worker_boot(&block)
310
+ @options[:before_worker_boot] << block
311
+ end
312
+
313
+ # *Cluster mode only* Code to run when a worker boots to setup
314
+ # the process after booting the app.
315
+ #
316
+ # This can be called multiple times to add hooks.
317
+ #
318
+ def after_worker_boot(&block)
319
+ @options[:after_worker_boot] << block
320
+ end
321
+
322
+ # The directory to operate out of.
323
+ def directory(dir)
324
+ @options[:directory] = dir.to_s
325
+ @options[:worker_directory] = dir.to_s
326
+ end
327
+
328
+ # Run the app as a raw TCP app instead of an HTTP rack app
329
+ def tcp_mode
330
+ @options[:mode] = :tcp
331
+ end
332
+
333
+ # *Cluster mode only* Preload the application before starting
334
+ # the workers and setting up the listen ports. This conflicts
335
+ # with using the phased restart feature, you can't use both.
336
+ #
337
+ def preload_app!(answer=true)
338
+ @options[:preload_app] = answer
339
+ end
340
+
341
+ # Use +obj+ or +block+ as the low lever error handler. This allows a config file to
342
+ # change the default error on the server.
343
+ #
344
+ def lowlevel_error_handler(obj=nil, &block)
345
+ obj ||= block
346
+ raise "Provide either a #call'able or a block" unless obj
347
+ @options[:lowlevel_error_handler] = obj
348
+ end
349
+
350
+ # This option is used to allow your app and it's gems to be
351
+ # properly reloaded when not using preload.
352
+ #
353
+ # When set, if puma detects that it's been invoked in the
354
+ # context of Bundler, it will cleanup the environment and
355
+ # re-run itself outside the Bundler environment, but directly
356
+ # using the files that Bundler has setup.
357
+ #
358
+ # This means that puma is now decoupled from your Bundler
359
+ # context and when each worker loads, it will be loading a
360
+ # new Bundler context and thus can float around as the release
361
+ # dictates.
362
+ def prune_bundler(answer=true)
363
+ @options[:prune_bundler] = answer
364
+ end
365
+
366
+ # Additional text to display in process listing
367
+ def tag(string)
368
+ @options[:tag] = string
369
+ end
370
+
371
+ # *Cluster mode only* Set the timeout for workers
372
+ def worker_timeout(timeout)
373
+ @options[:worker_timeout] = timeout
374
+ end
375
+ end
376
+ end
377
+ end
@@ -0,0 +1,165 @@
1
+ require 'rack'
2
+
3
+ module Puma
4
+ class UnsupportedOption < RuntimeError
5
+ end
6
+
7
+
8
+ # Every standard HTTP code mapped to the appropriate message. These are
9
+ # used so frequently that they are placed directly in Puma for easy
10
+ # access rather than Puma::Const itself.
11
+ HTTP_STATUS_CODES = Rack::Utils::HTTP_STATUS_CODES
12
+
13
+ # For some HTTP status codes the client only expects headers.
14
+ STATUS_WITH_NO_ENTITY_BODY = Hash[Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.map { |s|
15
+ [s, true]
16
+ }]
17
+
18
+ # Frequently used constants when constructing requests or responses. Many times
19
+ # the constant just refers to a string with the same contents. Using these constants
20
+ # gave about a 3% to 10% performance improvement over using the strings directly.
21
+ #
22
+ # The constants are frozen because Hash#[]= when called with a String key dups
23
+ # the String UNLESS the String is frozen. This saves us therefore 2 object
24
+ # allocations when creating the env hash later.
25
+ #
26
+ # While Puma does try to emulate the CGI/1.2 protocol, it does not use the REMOTE_IDENT,
27
+ # REMOTE_USER, or REMOTE_HOST parameters since those are either a security problem or
28
+ # too taxing on performance.
29
+ module Const
30
+
31
+ PUMA_VERSION = VERSION = "2.9.2".freeze
32
+ CODE_NAME = "Team High Five".freeze
33
+
34
+ FAST_TRACK_KA_TIMEOUT = 0.2
35
+
36
+ # The default number of seconds for another request within a persistent
37
+ # session.
38
+ PERSISTENT_TIMEOUT = 20
39
+
40
+ # The default number of seconds to wait until we get the first data
41
+ # for the request
42
+ FIRST_DATA_TIMEOUT = 30
43
+
44
+ # How long to wait when getting some write blocking on the socket when
45
+ # sending data back
46
+ WRITE_TIMEOUT = 10
47
+
48
+ DATE = "Date".freeze
49
+
50
+ SCRIPT_NAME = "SCRIPT_NAME".freeze
51
+
52
+ # The original URI requested by the client.
53
+ REQUEST_URI= 'REQUEST_URI'.freeze
54
+ REQUEST_PATH = 'REQUEST_PATH'.freeze
55
+
56
+ PATH_INFO = 'PATH_INFO'.freeze
57
+
58
+ PUMA_TMP_BASE = "puma".freeze
59
+
60
+ # Indicate that we couldn't parse the request
61
+ ERROR_400_RESPONSE = "HTTP/1.1 400 Bad Request\r\n\r\n".freeze
62
+
63
+ # The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
64
+ ERROR_404_RESPONSE = "HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\nNOT FOUND".freeze
65
+
66
+ # The standard empty 408 response for requests that timed out.
67
+ ERROR_408_RESPONSE = "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\n".freeze
68
+
69
+ CONTENT_LENGTH = "CONTENT_LENGTH".freeze
70
+
71
+ # Indicate that there was an internal error, obviously.
72
+ ERROR_500_RESPONSE = "HTTP/1.1 500 Internal Server Error\r\n\r\n".freeze
73
+
74
+ # A common header for indicating the server is too busy. Not used yet.
75
+ ERROR_503_RESPONSE = "HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY".freeze
76
+
77
+ # The basic max request size we'll try to read.
78
+ CHUNK_SIZE = 16 * 1024
79
+
80
+ # This is the maximum header that is allowed before a client is booted. The parser detects
81
+ # this, but we'd also like to do this as well.
82
+ MAX_HEADER = 1024 * (80 + 32)
83
+
84
+ # Maximum request body size before it is moved out of memory and into a tempfile for reading.
85
+ MAX_BODY = MAX_HEADER
86
+
87
+ # A frozen format for this is about 15% faster
88
+ STATUS_FORMAT = "HTTP/1.1 %d %s\r\nConnection: close\r\n".freeze
89
+
90
+ CONTENT_TYPE = "Content-Type".freeze
91
+
92
+ LAST_MODIFIED = "Last-Modified".freeze
93
+ ETAG = "ETag".freeze
94
+ SLASH = "/".freeze
95
+ REQUEST_METHOD = "REQUEST_METHOD".freeze
96
+ GET = "GET".freeze
97
+ HEAD = "HEAD".freeze
98
+ # ETag is based on the apache standard of hex mtime-size-inode (inode is 0 on win32)
99
+ ETAG_FORMAT = "\"%x-%x-%x\"".freeze
100
+ LINE_END = "\r\n".freeze
101
+ REMOTE_ADDR = "REMOTE_ADDR".freeze
102
+ HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze
103
+ HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE".freeze
104
+ HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH".freeze
105
+ REDIRECT = "HTTP/1.1 302 Found\r\nLocation: %s\r\nConnection: close\r\n\r\n".freeze
106
+ HOST = "HOST".freeze
107
+
108
+ SERVER_NAME = "SERVER_NAME".freeze
109
+ SERVER_PORT = "SERVER_PORT".freeze
110
+ HTTP_HOST = "HTTP_HOST".freeze
111
+ PORT_80 = "80".freeze
112
+ PORT_443 = "443".freeze
113
+ LOCALHOST = "localhost".freeze
114
+
115
+ SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
116
+ HTTP_11 = "HTTP/1.1".freeze
117
+ HTTP_10 = "HTTP/1.0".freeze
118
+
119
+ SERVER_SOFTWARE = "SERVER_SOFTWARE".freeze
120
+ GATEWAY_INTERFACE = "GATEWAY_INTERFACE".freeze
121
+ CGI_VER = "CGI/1.2".freeze
122
+
123
+ STOP_COMMAND = "?".freeze
124
+ HALT_COMMAND = "!".freeze
125
+ RESTART_COMMAND = "R".freeze
126
+
127
+ RACK_INPUT = "rack.input".freeze
128
+ RACK_URL_SCHEME = "rack.url_scheme".freeze
129
+ RACK_AFTER_REPLY = "rack.after_reply".freeze
130
+ PUMA_SOCKET = "puma.socket".freeze
131
+ PUMA_CONFIG = "puma.config".freeze
132
+
133
+ HTTP = "http".freeze
134
+ HTTPS = "https".freeze
135
+
136
+ HTTPS_KEY = "HTTPS".freeze
137
+
138
+ HTTP_VERSION = "HTTP_VERSION".freeze
139
+ HTTP_CONNECTION = "HTTP_CONNECTION".freeze
140
+
141
+ HTTP_11_200 = "HTTP/1.1 200 OK\r\n".freeze
142
+ HTTP_10_200 = "HTTP/1.0 200 OK\r\n".freeze
143
+
144
+ CLOSE = "close".freeze
145
+ KEEP_ALIVE = "Keep-Alive".freeze
146
+
147
+ CONTENT_LENGTH2 = "Content-Length".freeze
148
+ CONTENT_LENGTH_S = "Content-Length: ".freeze
149
+ TRANSFER_ENCODING = "Transfer-Encoding".freeze
150
+
151
+ CONNECTION_CLOSE = "Connection: close\r\n".freeze
152
+ CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n".freeze
153
+
154
+ TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n".freeze
155
+ CLOSE_CHUNKED = "0\r\n\r\n".freeze
156
+
157
+ COLON = ": ".freeze
158
+
159
+ NEWLINE = "\n".freeze
160
+
161
+ HIJACK_P = "rack.hijack?".freeze
162
+ HIJACK = "rack.hijack".freeze
163
+ HIJACK_IO = "rack.hijack_io".freeze
164
+ end
165
+ end