jun-puma 1.0.1-java → 1.0.2-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/lib/puma/puma_http11.jar +0 -0
  3. metadata +3 -81
  4. data/bin/puma-wild +0 -25
  5. data/docs/architecture.md +0 -74
  6. data/docs/compile_options.md +0 -55
  7. data/docs/deployment.md +0 -102
  8. data/docs/fork_worker.md +0 -31
  9. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  10. data/docs/images/puma-connection-flow.png +0 -0
  11. data/docs/images/puma-general-arch.png +0 -0
  12. data/docs/jungle/README.md +0 -9
  13. data/docs/jungle/rc.d/README.md +0 -74
  14. data/docs/jungle/rc.d/puma +0 -61
  15. data/docs/jungle/rc.d/puma.conf +0 -10
  16. data/docs/kubernetes.md +0 -78
  17. data/docs/nginx.md +0 -80
  18. data/docs/plugins.md +0 -38
  19. data/docs/rails_dev_mode.md +0 -28
  20. data/docs/restart.md +0 -64
  21. data/docs/signals.md +0 -98
  22. data/docs/stats.md +0 -142
  23. data/docs/systemd.md +0 -244
  24. data/docs/testing_benchmarks_local_files.md +0 -150
  25. data/docs/testing_test_rackup_ci_files.md +0 -36
  26. data/ext/puma_http11/PumaHttp11Service.java +0 -17
  27. data/ext/puma_http11/ext_help.h +0 -15
  28. data/ext/puma_http11/http11_parser.c +0 -1057
  29. data/ext/puma_http11/http11_parser.h +0 -65
  30. data/ext/puma_http11/http11_parser.java.rl +0 -145
  31. data/ext/puma_http11/http11_parser.rl +0 -149
  32. data/ext/puma_http11/http11_parser_common.rl +0 -54
  33. data/ext/puma_http11/mini_ssl.c +0 -832
  34. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -15
  35. data/ext/puma_http11/org/jruby/puma/Http11.java +0 -226
  36. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +0 -455
  37. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +0 -508
  38. data/ext/puma_http11/puma_http11.c +0 -492
  39. data/lib/puma/app/status.rb +0 -96
  40. data/lib/puma/binder.rb +0 -501
  41. data/lib/puma/cli.rb +0 -243
  42. data/lib/puma/client.rb +0 -632
  43. data/lib/puma/cluster/worker.rb +0 -182
  44. data/lib/puma/cluster/worker_handle.rb +0 -97
  45. data/lib/puma/cluster.rb +0 -562
  46. data/lib/puma/commonlogger.rb +0 -115
  47. data/lib/puma/configuration.rb +0 -391
  48. data/lib/puma/const.rb +0 -289
  49. data/lib/puma/control_cli.rb +0 -316
  50. data/lib/puma/detect.rb +0 -45
  51. data/lib/puma/dsl.rb +0 -1204
  52. data/lib/puma/error_logger.rb +0 -113
  53. data/lib/puma/events.rb +0 -57
  54. data/lib/puma/io_buffer.rb +0 -46
  55. data/lib/puma/jruby_restart.rb +0 -27
  56. data/lib/puma/json_serialization.rb +0 -96
  57. data/lib/puma/launcher/bundle_pruner.rb +0 -104
  58. data/lib/puma/launcher.rb +0 -484
  59. data/lib/puma/log_writer.rb +0 -147
  60. data/lib/puma/minissl/context_builder.rb +0 -95
  61. data/lib/puma/minissl.rb +0 -458
  62. data/lib/puma/null_io.rb +0 -61
  63. data/lib/puma/plugin/systemd.rb +0 -90
  64. data/lib/puma/plugin/tmp_restart.rb +0 -36
  65. data/lib/puma/plugin.rb +0 -111
  66. data/lib/puma/rack/builder.rb +0 -297
  67. data/lib/puma/rack/urlmap.rb +0 -93
  68. data/lib/puma/rack_default.rb +0 -24
  69. data/lib/puma/reactor.rb +0 -125
  70. data/lib/puma/request.rb +0 -671
  71. data/lib/puma/runner.rb +0 -213
  72. data/lib/puma/sd_notify.rb +0 -149
  73. data/lib/puma/server.rb +0 -664
  74. data/lib/puma/single.rb +0 -69
  75. data/lib/puma/state_file.rb +0 -68
  76. data/lib/puma/thread_pool.rb +0 -434
  77. data/lib/puma/util.rb +0 -141
  78. data/lib/puma.rb +0 -78
  79. data/lib/rack/handler/puma.rb +0 -141
  80. data/tools/Dockerfile +0 -16
  81. data/tools/trickletest.rb +0 -44
data/lib/puma/client.rb DELETED
@@ -1,632 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class IO
4
- # We need to use this for a jruby work around on both 1.8 and 1.9.
5
- # So this either creates the constant (on 1.8), or harmlessly
6
- # reopens it (on 1.9).
7
- module WaitReadable
8
- end
9
- end
10
-
11
- require_relative 'detect'
12
- require_relative 'io_buffer'
13
- require 'tempfile'
14
-
15
- if Puma::IS_JRUBY
16
- # We have to work around some OpenSSL buffer/io-readiness bugs
17
- # so we pull it in regardless of if the user is binding
18
- # to an SSL socket
19
- require 'openssl'
20
- end
21
-
22
- module Puma
23
-
24
- class ConnectionError < RuntimeError; end
25
-
26
- class HttpParserError501 < IOError; end
27
-
28
- #———————————————————————— DO NOT USE — this class is for internal use only ———
29
-
30
-
31
- # An instance of this class represents a unique request from a client.
32
- # For example, this could be a web request from a browser or from CURL.
33
- #
34
- # An instance of `Puma::Client` can be used as if it were an IO object
35
- # by the reactor. The reactor is expected to call `#to_io`
36
- # on any non-IO objects it polls. For example, nio4r internally calls
37
- # `IO::try_convert` (which may call `#to_io`) when a new socket is
38
- # registered.
39
- #
40
- # Instances of this class are responsible for knowing if
41
- # the header and body are fully buffered via the `try_to_finish` method.
42
- # They can be used to "time out" a response via the `timeout_at` reader.
43
- #
44
- class Client # :nodoc:
45
-
46
- # this tests all values but the last, which must be chunked
47
- ALLOWED_TRANSFER_ENCODING = %w[compress deflate gzip].freeze
48
-
49
- # chunked body validation
50
- CHUNK_SIZE_INVALID = /[^\h]/.freeze
51
- CHUNK_VALID_ENDING = Const::LINE_END
52
- CHUNK_VALID_ENDING_SIZE = CHUNK_VALID_ENDING.bytesize
53
-
54
- # Content-Length header value validation
55
- CONTENT_LENGTH_VALUE_INVALID = /[^\d]/.freeze
56
-
57
- TE_ERR_MSG = 'Invalid Transfer-Encoding'
58
-
59
- # The object used for a request with no body. All requests with
60
- # no body share this one object since it has no state.
61
- EmptyBody = NullIO.new
62
-
63
- include Puma::Const
64
-
65
- def initialize(io, env=nil)
66
- @io = io
67
- @to_io = io.to_io
68
- @io_buffer = IOBuffer.new
69
- @proto_env = env
70
- @env = env&.dup
71
-
72
- @parser = HttpParser.new
73
- @parsed_bytes = 0
74
- @read_header = true
75
- @read_proxy = false
76
- @ready = false
77
-
78
- @body = nil
79
- @body_read_start = nil
80
- @buffer = nil
81
- @tempfile = nil
82
-
83
- @timeout_at = nil
84
-
85
- @requests_served = 0
86
- @hijacked = false
87
-
88
- @http_content_length_limit = nil
89
- @http_content_length_limit_exceeded = false
90
-
91
- @peerip = nil
92
- @peer_family = nil
93
- @listener = nil
94
- @remote_addr_header = nil
95
- @expect_proxy_proto = false
96
-
97
- @body_remain = 0
98
-
99
- @in_last_chunk = false
100
-
101
- # need unfrozen ASCII-8BIT, +'' is UTF-8
102
- @read_buffer = String.new # rubocop: disable Performance/UnfreezeString
103
- end
104
-
105
- attr_reader :env, :to_io, :body, :io, :timeout_at, :ready, :hijacked,
106
- :tempfile, :io_buffer, :http_content_length_limit_exceeded
107
-
108
- attr_writer :peerip, :http_content_length_limit
109
-
110
- attr_accessor :remote_addr_header, :listener
111
-
112
- # Remove in Puma 7?
113
- def closed?
114
- @to_io.closed?
115
- end
116
-
117
- # Test to see if io meets a bare minimum of functioning, @to_io needs to be
118
- # used for MiniSSL::Socket
119
- def io_ok?
120
- @to_io.is_a?(::BasicSocket) && !closed?
121
- end
122
-
123
- # @!attribute [r] inspect
124
- def inspect
125
- "#<Puma::Client:0x#{object_id.to_s(16)} @ready=#{@ready.inspect}>"
126
- end
127
-
128
- # For the hijack protocol (allows us to just put the Client object
129
- # into the env)
130
- def call
131
- @hijacked = true
132
- env[HIJACK_IO] ||= @io
133
- end
134
-
135
- # @!attribute [r] in_data_phase
136
- def in_data_phase
137
- !(@read_header || @read_proxy)
138
- end
139
-
140
- def set_timeout(val)
141
- @timeout_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + val
142
- end
143
-
144
- # Number of seconds until the timeout elapses.
145
- def timeout
146
- [@timeout_at - Process.clock_gettime(Process::CLOCK_MONOTONIC), 0].max
147
- end
148
-
149
- def reset(fast_check=true)
150
- @parser.reset
151
- @io_buffer.reset
152
- @read_header = true
153
- @read_proxy = !!@expect_proxy_proto
154
- @env = @proto_env.dup
155
- @body = nil
156
- @tempfile = nil
157
- @parsed_bytes = 0
158
- @ready = false
159
- @body_remain = 0
160
- @peerip = nil if @remote_addr_header
161
- @in_last_chunk = false
162
- @http_content_length_limit_exceeded = false
163
-
164
- if @buffer
165
- return false unless try_to_parse_proxy_protocol
166
-
167
- @parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
168
-
169
- if @parser.finished?
170
- return setup_body
171
- elsif @parsed_bytes >= MAX_HEADER
172
- raise HttpParserError,
173
- "HEADER is longer than allowed, aborting client early."
174
- end
175
-
176
- return false
177
- else
178
- begin
179
- if fast_check && @to_io.wait_readable(FAST_TRACK_KA_TIMEOUT)
180
- return try_to_finish
181
- end
182
- rescue IOError
183
- # swallow it
184
- end
185
-
186
- end
187
- end
188
-
189
- def close
190
- begin
191
- @io.close
192
- rescue IOError, Errno::EBADF
193
- Puma::Util.purge_interrupt_queue
194
- end
195
- end
196
-
197
- # If necessary, read the PROXY protocol from the buffer. Returns
198
- # false if more data is needed.
199
- def try_to_parse_proxy_protocol
200
- if @read_proxy
201
- if @expect_proxy_proto == :v1
202
- if @buffer.include? "\r\n"
203
- if md = PROXY_PROTOCOL_V1_REGEX.match(@buffer)
204
- if md[1]
205
- @peerip = md[1].split(" ")[0]
206
- end
207
- @buffer = md.post_match
208
- end
209
- # if the buffer has a \r\n but doesn't have a PROXY protocol
210
- # request, this is just HTTP from a non-PROXY client; move on
211
- @read_proxy = false
212
- return @buffer.size > 0
213
- else
214
- return false
215
- end
216
- end
217
- end
218
- true
219
- end
220
-
221
- def try_to_finish
222
- if env[CONTENT_LENGTH] && above_http_content_limit(env[CONTENT_LENGTH].to_i)
223
- @http_content_length_limit_exceeded = true
224
- end
225
-
226
- if @http_content_length_limit_exceeded
227
- @buffer = nil
228
- @body = EmptyBody
229
- set_ready
230
- return true
231
- end
232
-
233
- return read_body if in_data_phase
234
-
235
- begin
236
- data = @io.read_nonblock(CHUNK_SIZE)
237
- rescue IO::WaitReadable
238
- return false
239
- rescue EOFError
240
- # Swallow error, don't log
241
- rescue SystemCallError, IOError
242
- raise ConnectionError, "Connection error detected during read"
243
- end
244
-
245
- # No data means a closed socket
246
- unless data
247
- @buffer = nil
248
- set_ready
249
- raise EOFError
250
- end
251
-
252
- if @buffer
253
- @buffer << data
254
- else
255
- @buffer = data
256
- end
257
-
258
- return false unless try_to_parse_proxy_protocol
259
-
260
- @parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
261
-
262
- if @parser.finished? && above_http_content_limit(@parser.body.bytesize)
263
- @http_content_length_limit_exceeded = true
264
- end
265
-
266
- if @parser.finished?
267
- return setup_body
268
- elsif @parsed_bytes >= MAX_HEADER
269
- raise HttpParserError,
270
- "HEADER is longer than allowed, aborting client early."
271
- end
272
-
273
- false
274
- end
275
-
276
- def eagerly_finish
277
- return true if @ready
278
- return false unless @to_io.wait_readable(0)
279
- try_to_finish
280
- end
281
-
282
- def finish(timeout)
283
- return if @ready
284
- @to_io.wait_readable(timeout) || timeout! until try_to_finish
285
- end
286
-
287
- def timeout!
288
- write_error(408) if in_data_phase
289
- raise ConnectionError
290
- end
291
-
292
- def write_error(status_code)
293
- begin
294
- @io << ERROR_RESPONSE[status_code]
295
- rescue StandardError
296
- end
297
- end
298
-
299
- def peerip
300
- return @peerip if @peerip
301
-
302
- if @remote_addr_header
303
- hdr = (@env[@remote_addr_header] || @io.peeraddr.last).split(/[\s,]/).first
304
- @peerip = hdr
305
- return hdr
306
- end
307
-
308
- @peerip ||= @io.peeraddr.last
309
- end
310
-
311
- def peer_family
312
- return @peer_family if @peer_family
313
-
314
- @peer_family ||= begin
315
- @io.local_address.afamily
316
- rescue
317
- Socket::AF_INET
318
- end
319
- end
320
-
321
- # Returns true if the persistent connection can be closed immediately
322
- # without waiting for the configured idle/shutdown timeout.
323
- # @version 5.0.0
324
- #
325
- def can_close?
326
- # Allow connection to close if we're not in the middle of parsing a request.
327
- @parsed_bytes == 0
328
- end
329
-
330
- def expect_proxy_proto=(val)
331
- if val
332
- if @read_header
333
- @read_proxy = true
334
- end
335
- else
336
- @read_proxy = false
337
- end
338
- @expect_proxy_proto = val
339
- end
340
-
341
- private
342
-
343
- def setup_body
344
- @body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
345
-
346
- if @env[HTTP_EXPECT] == CONTINUE
347
- # TODO allow a hook here to check the headers before
348
- # going forward
349
- @io << HTTP_11_100
350
- @io.flush
351
- end
352
-
353
- @read_header = false
354
-
355
- body = @parser.body
356
-
357
- te = @env[TRANSFER_ENCODING2]
358
- if te
359
- te_lwr = te.downcase
360
- if te.include? ','
361
- te_ary = te_lwr.split ','
362
- te_count = te_ary.count CHUNKED
363
- te_valid = te_ary[0..-2].all? { |e| ALLOWED_TRANSFER_ENCODING.include? e }
364
- if te_ary.last == CHUNKED && te_count == 1 && te_valid
365
- @env.delete TRANSFER_ENCODING2
366
- return setup_chunked_body body
367
- elsif te_count >= 1
368
- raise HttpParserError , "#{TE_ERR_MSG}, multiple chunked: '#{te}'"
369
- elsif !te_valid
370
- raise HttpParserError501, "#{TE_ERR_MSG}, unknown value: '#{te}'"
371
- end
372
- elsif te_lwr == CHUNKED
373
- @env.delete TRANSFER_ENCODING2
374
- return setup_chunked_body body
375
- elsif ALLOWED_TRANSFER_ENCODING.include? te_lwr
376
- raise HttpParserError , "#{TE_ERR_MSG}, single value must be chunked: '#{te}'"
377
- else
378
- raise HttpParserError501 , "#{TE_ERR_MSG}, unknown value: '#{te}'"
379
- end
380
- end
381
-
382
- @chunked_body = false
383
-
384
- cl = @env[CONTENT_LENGTH]
385
-
386
- if cl
387
- # cannot contain characters that are not \d, or be empty
388
- if CONTENT_LENGTH_VALUE_INVALID.match?(cl) || cl.empty?
389
- raise HttpParserError, "Invalid Content-Length: #{cl.inspect}"
390
- end
391
- else
392
- @buffer = body.empty? ? nil : body
393
- @body = EmptyBody
394
- set_ready
395
- return true
396
- end
397
-
398
- remain = cl.to_i - body.bytesize
399
-
400
- if remain <= 0
401
- @body = StringIO.new(body)
402
- @buffer = nil
403
- set_ready
404
- return true
405
- end
406
-
407
- if remain > MAX_BODY
408
- @body = Tempfile.new(Const::PUMA_TMP_BASE)
409
- @body.unlink
410
- @body.binmode
411
- @tempfile = @body
412
- else
413
- # The body[0,0] trick is to get an empty string in the same
414
- # encoding as body.
415
- @body = StringIO.new body[0,0]
416
- end
417
-
418
- @body.write body
419
-
420
- @body_remain = remain
421
-
422
- false
423
- end
424
-
425
- def read_body
426
- if @chunked_body
427
- return read_chunked_body
428
- end
429
-
430
- # Read an odd sized chunk so we can read even sized ones
431
- # after this
432
- remain = @body_remain
433
-
434
- if remain > CHUNK_SIZE
435
- want = CHUNK_SIZE
436
- else
437
- want = remain
438
- end
439
-
440
- begin
441
- chunk = @io.read_nonblock(want, @read_buffer)
442
- rescue IO::WaitReadable
443
- return false
444
- rescue SystemCallError, IOError
445
- raise ConnectionError, "Connection error detected during read"
446
- end
447
-
448
- # No chunk means a closed socket
449
- unless chunk
450
- @body.close
451
- @buffer = nil
452
- set_ready
453
- raise EOFError
454
- end
455
-
456
- remain -= @body.write(chunk)
457
-
458
- if remain <= 0
459
- @body.rewind
460
- @buffer = nil
461
- set_ready
462
- return true
463
- end
464
-
465
- @body_remain = remain
466
-
467
- false
468
- end
469
-
470
- def read_chunked_body
471
- while true
472
- begin
473
- chunk = @io.read_nonblock(4096, @read_buffer)
474
- rescue IO::WaitReadable
475
- return false
476
- rescue SystemCallError, IOError
477
- raise ConnectionError, "Connection error detected during read"
478
- end
479
-
480
- # No chunk means a closed socket
481
- unless chunk
482
- @body.close
483
- @buffer = nil
484
- set_ready
485
- raise EOFError
486
- end
487
-
488
- if decode_chunk(chunk)
489
- @env[CONTENT_LENGTH] = @chunked_content_length.to_s
490
- return true
491
- end
492
- end
493
- end
494
-
495
- def setup_chunked_body(body)
496
- @chunked_body = true
497
- @partial_part_left = 0
498
- @prev_chunk = ""
499
-
500
- @body = Tempfile.new(Const::PUMA_TMP_BASE)
501
- @body.unlink
502
- @body.binmode
503
- @tempfile = @body
504
- @chunked_content_length = 0
505
-
506
- if decode_chunk(body)
507
- @env[CONTENT_LENGTH] = @chunked_content_length.to_s
508
- return true
509
- end
510
- end
511
-
512
- # @version 5.0.0
513
- def write_chunk(str)
514
- @chunked_content_length += @body.write(str)
515
- end
516
-
517
- def decode_chunk(chunk)
518
- if @partial_part_left > 0
519
- if @partial_part_left <= chunk.size
520
- if @partial_part_left > 2
521
- write_chunk(chunk[0..(@partial_part_left-3)]) # skip the \r\n
522
- end
523
- chunk = chunk[@partial_part_left..-1]
524
- @partial_part_left = 0
525
- else
526
- if @partial_part_left > 2
527
- if @partial_part_left == chunk.size + 1
528
- # Don't include the last \r
529
- write_chunk(chunk[0..(@partial_part_left-3)])
530
- else
531
- # don't include the last \r\n
532
- write_chunk(chunk)
533
- end
534
- end
535
- @partial_part_left -= chunk.size
536
- return false
537
- end
538
- end
539
-
540
- if @prev_chunk.empty?
541
- io = StringIO.new(chunk)
542
- else
543
- io = StringIO.new(@prev_chunk+chunk)
544
- @prev_chunk = ""
545
- end
546
-
547
- while !io.eof?
548
- line = io.gets
549
- if line.end_with?(CHUNK_VALID_ENDING)
550
- # Puma doesn't process chunk extensions, but should parse if they're
551
- # present, which is the reason for the semicolon regex
552
- chunk_hex = line.strip[/\A[^;]+/]
553
- if CHUNK_SIZE_INVALID.match? chunk_hex
554
- raise HttpParserError, "Invalid chunk size: '#{chunk_hex}'"
555
- end
556
- len = chunk_hex.to_i(16)
557
- if len == 0
558
- @in_last_chunk = true
559
- @body.rewind
560
- rest = io.read
561
- if rest.bytesize < CHUNK_VALID_ENDING_SIZE
562
- @buffer = nil
563
- @partial_part_left = CHUNK_VALID_ENDING_SIZE - rest.bytesize
564
- return false
565
- else
566
- # if the next character is a CRLF, set buffer to everything after that CRLF
567
- start_of_rest = if rest.start_with?(CHUNK_VALID_ENDING)
568
- CHUNK_VALID_ENDING_SIZE
569
- else # we have started a trailer section, which we do not support. skip it!
570
- rest.index(CHUNK_VALID_ENDING*2) + CHUNK_VALID_ENDING_SIZE*2
571
- end
572
-
573
- @buffer = rest[start_of_rest..-1]
574
- @buffer = nil if @buffer.empty?
575
- set_ready
576
- return true
577
- end
578
- end
579
-
580
- len += 2
581
-
582
- part = io.read(len)
583
-
584
- unless part
585
- @partial_part_left = len
586
- next
587
- end
588
-
589
- got = part.size
590
-
591
- case
592
- when got == len
593
- # proper chunked segment must end with "\r\n"
594
- if part.end_with? CHUNK_VALID_ENDING
595
- write_chunk(part[0..-3]) # to skip the ending \r\n
596
- else
597
- raise HttpParserError, "Chunk size mismatch"
598
- end
599
- when got <= len - 2
600
- write_chunk(part)
601
- @partial_part_left = len - part.size
602
- when got == len - 1 # edge where we get just \r but not \n
603
- write_chunk(part[0..-2])
604
- @partial_part_left = len - part.size
605
- end
606
- else
607
- @prev_chunk = line
608
- return false
609
- end
610
- end
611
-
612
- if @in_last_chunk
613
- set_ready
614
- true
615
- else
616
- false
617
- end
618
- end
619
-
620
- def set_ready
621
- if @body_read_start
622
- @env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - @body_read_start
623
- end
624
- @requests_served += 1
625
- @ready = true
626
- end
627
-
628
- def above_http_content_limit(value)
629
- @http_content_length_limit&.< value
630
- end
631
- end
632
- end