jun-puma 1.0.0-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 (87) hide show
  1. checksums.yaml +7 -0
  2. data/History.md +2897 -0
  3. data/LICENSE +29 -0
  4. data/README.md +475 -0
  5. data/bin/puma +10 -0
  6. data/bin/puma-wild +25 -0
  7. data/bin/pumactl +12 -0
  8. data/docs/architecture.md +74 -0
  9. data/docs/compile_options.md +55 -0
  10. data/docs/deployment.md +102 -0
  11. data/docs/fork_worker.md +35 -0
  12. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  13. data/docs/images/puma-connection-flow.png +0 -0
  14. data/docs/images/puma-general-arch.png +0 -0
  15. data/docs/jungle/README.md +9 -0
  16. data/docs/jungle/rc.d/README.md +74 -0
  17. data/docs/jungle/rc.d/puma +61 -0
  18. data/docs/jungle/rc.d/puma.conf +10 -0
  19. data/docs/kubernetes.md +78 -0
  20. data/docs/nginx.md +80 -0
  21. data/docs/plugins.md +38 -0
  22. data/docs/rails_dev_mode.md +28 -0
  23. data/docs/restart.md +65 -0
  24. data/docs/signals.md +98 -0
  25. data/docs/stats.md +142 -0
  26. data/docs/systemd.md +253 -0
  27. data/docs/testing_benchmarks_local_files.md +150 -0
  28. data/docs/testing_test_rackup_ci_files.md +36 -0
  29. data/ext/puma_http11/PumaHttp11Service.java +17 -0
  30. data/ext/puma_http11/ext_help.h +15 -0
  31. data/ext/puma_http11/extconf.rb +80 -0
  32. data/ext/puma_http11/http11_parser.c +1057 -0
  33. data/ext/puma_http11/http11_parser.h +65 -0
  34. data/ext/puma_http11/http11_parser.java.rl +145 -0
  35. data/ext/puma_http11/http11_parser.rl +149 -0
  36. data/ext/puma_http11/http11_parser_common.rl +54 -0
  37. data/ext/puma_http11/mini_ssl.c +842 -0
  38. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  39. data/ext/puma_http11/org/jruby/puma/Http11.java +228 -0
  40. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +455 -0
  41. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +509 -0
  42. data/ext/puma_http11/puma_http11.c +495 -0
  43. data/lib/puma/app/status.rb +96 -0
  44. data/lib/puma/binder.rb +502 -0
  45. data/lib/puma/cli.rb +247 -0
  46. data/lib/puma/client.rb +682 -0
  47. data/lib/puma/cluster/worker.rb +180 -0
  48. data/lib/puma/cluster/worker_handle.rb +96 -0
  49. data/lib/puma/cluster.rb +616 -0
  50. data/lib/puma/commonlogger.rb +115 -0
  51. data/lib/puma/configuration.rb +390 -0
  52. data/lib/puma/const.rb +307 -0
  53. data/lib/puma/control_cli.rb +316 -0
  54. data/lib/puma/detect.rb +45 -0
  55. data/lib/puma/dsl.rb +1425 -0
  56. data/lib/puma/error_logger.rb +113 -0
  57. data/lib/puma/events.rb +57 -0
  58. data/lib/puma/io_buffer.rb +46 -0
  59. data/lib/puma/jruby_restart.rb +11 -0
  60. data/lib/puma/json_serialization.rb +96 -0
  61. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  62. data/lib/puma/launcher.rb +488 -0
  63. data/lib/puma/log_writer.rb +147 -0
  64. data/lib/puma/minissl/context_builder.rb +96 -0
  65. data/lib/puma/minissl.rb +459 -0
  66. data/lib/puma/null_io.rb +84 -0
  67. data/lib/puma/plugin/systemd.rb +90 -0
  68. data/lib/puma/plugin/tmp_restart.rb +36 -0
  69. data/lib/puma/plugin.rb +111 -0
  70. data/lib/puma/puma_http11.jar +0 -0
  71. data/lib/puma/rack/builder.rb +297 -0
  72. data/lib/puma/rack/urlmap.rb +93 -0
  73. data/lib/puma/rack_default.rb +24 -0
  74. data/lib/puma/reactor.rb +125 -0
  75. data/lib/puma/request.rb +688 -0
  76. data/lib/puma/runner.rb +213 -0
  77. data/lib/puma/sd_notify.rb +149 -0
  78. data/lib/puma/server.rb +680 -0
  79. data/lib/puma/single.rb +69 -0
  80. data/lib/puma/state_file.rb +68 -0
  81. data/lib/puma/thread_pool.rb +434 -0
  82. data/lib/puma/util.rb +141 -0
  83. data/lib/puma.rb +78 -0
  84. data/lib/rack/handler/puma.rb +144 -0
  85. data/tools/Dockerfile +16 -0
  86. data/tools/trickletest.rb +44 -0
  87. metadata +153 -0
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'const'
4
+
5
+ module Puma
6
+ # The implementation of a detailed error logging.
7
+ # @version 5.0.0
8
+ #
9
+ class ErrorLogger
10
+ include Const
11
+
12
+ attr_reader :ioerr
13
+
14
+ REQUEST_FORMAT = %{"%s %s%s" - (%s)}
15
+
16
+ LOG_QUEUE = Queue.new
17
+
18
+ def initialize(ioerr, env: ENV)
19
+ @ioerr = ioerr
20
+
21
+ @debug = env.key?('PUMA_DEBUG')
22
+ end
23
+
24
+ def self.stdio(env: ENV)
25
+ new($stderr, env: env)
26
+ end
27
+
28
+ # Print occurred error details.
29
+ # +options+ hash with additional options:
30
+ # - +error+ is an exception object
31
+ # - +req+ the http request
32
+ # - +text+ (default nil) custom string to print in title
33
+ # and before all remaining info.
34
+ #
35
+ def info(options={})
36
+ internal_write title(options)
37
+ end
38
+
39
+ # Print occurred error details only if
40
+ # environment variable PUMA_DEBUG is defined.
41
+ # +options+ hash with additional options:
42
+ # - +error+ is an exception object
43
+ # - +req+ the http request
44
+ # - +text+ (default nil) custom string to print in title
45
+ # and before all remaining info.
46
+ #
47
+ def debug(options={})
48
+ return unless @debug
49
+
50
+ error = options[:error]
51
+ req = options[:req]
52
+
53
+ string_block = []
54
+ string_block << title(options)
55
+ string_block << request_dump(req) if request_parsed?(req)
56
+ string_block << error.backtrace if error
57
+
58
+ internal_write string_block.join("\n")
59
+ end
60
+
61
+ def title(options={})
62
+ text = options[:text]
63
+ req = options[:req]
64
+ error = options[:error]
65
+
66
+ string_block = ["#{Time.now}"]
67
+ string_block << " #{text}" if text
68
+ string_block << " (#{request_title(req)})" if request_parsed?(req)
69
+ string_block << ": #{error.inspect}" if error
70
+ string_block.join('')
71
+ end
72
+
73
+ def request_dump(req)
74
+ "Headers: #{request_headers(req)}\n" \
75
+ "Body: #{req.body}"
76
+ end
77
+
78
+ def request_title(req)
79
+ env = req.env
80
+
81
+ REQUEST_FORMAT % [
82
+ env[REQUEST_METHOD],
83
+ env[REQUEST_PATH] || env[PATH_INFO],
84
+ env[QUERY_STRING] || "",
85
+ env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-"
86
+ ]
87
+ end
88
+
89
+ def request_headers(req)
90
+ headers = req.env.select { |key, _| key.start_with?('HTTP_') }
91
+ headers.map { |key, value| [key[5..-1], value] }.to_h.inspect
92
+ end
93
+
94
+ def request_parsed?(req)
95
+ req && req.env[REQUEST_METHOD]
96
+ end
97
+
98
+ def internal_write(str)
99
+ LOG_QUEUE << str
100
+ while (w_str = LOG_QUEUE.pop(true)) do
101
+ begin
102
+ @ioerr.is_a?(IO) and @ioerr.wait_writable(1)
103
+ @ioerr.write "#{w_str}\n"
104
+ @ioerr.flush unless @ioerr.sync
105
+ rescue Errno::EPIPE, Errno::EBADF, IOError, Errno::EINVAL
106
+ # 'Invalid argument' (Errno::EINVAL) may be raised by flush
107
+ end
108
+ end
109
+ rescue ThreadError
110
+ end
111
+ private :internal_write
112
+ end
113
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Puma
4
+
5
+ # This is an event sink used by `Puma::Server` to handle
6
+ # lifecycle events such as :on_booted, :on_restart, and :on_stopped.
7
+ # Using `Puma::DSL` it is possible to register callback hooks
8
+ # for each event type.
9
+ class Events
10
+
11
+ def initialize
12
+ @hooks = Hash.new { |h,k| h[k] = [] }
13
+ end
14
+
15
+ # Fire callbacks for the named hook
16
+ def fire(hook, *args)
17
+ @hooks[hook].each { |t| t.call(*args) }
18
+ end
19
+
20
+ # Register a callback for a given hook
21
+ def register(hook, obj=nil, &blk)
22
+ if obj and blk
23
+ raise "Specify either an object or a block, not both"
24
+ end
25
+
26
+ h = obj || blk
27
+
28
+ @hooks[hook] << h
29
+
30
+ h
31
+ end
32
+
33
+ def on_booted(&block)
34
+ register(:on_booted, &block)
35
+ end
36
+
37
+ def on_restart(&block)
38
+ register(:on_restart, &block)
39
+ end
40
+
41
+ def on_stopped(&block)
42
+ register(:on_stopped, &block)
43
+ end
44
+
45
+ def fire_on_booted!
46
+ fire(:on_booted)
47
+ end
48
+
49
+ def fire_on_restart!
50
+ fire(:on_restart)
51
+ end
52
+
53
+ def fire_on_stopped!
54
+ fire(:on_stopped)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stringio'
4
+
5
+ module Puma
6
+ class IOBuffer < StringIO
7
+ def initialize
8
+ super.binmode
9
+ end
10
+
11
+ def empty?
12
+ length.zero?
13
+ end
14
+
15
+ def reset
16
+ truncate 0
17
+ rewind
18
+ end
19
+
20
+ def to_s
21
+ rewind
22
+ read
23
+ end
24
+
25
+ # Read & Reset - returns contents and resets
26
+ # @return [String] StringIO contents
27
+ def read_and_reset
28
+ rewind
29
+ str = read
30
+ truncate 0
31
+ rewind
32
+ str
33
+ end
34
+
35
+ alias_method :clear, :reset
36
+
37
+ # before Ruby 2.5, `write` would only take one argument
38
+ if RUBY_VERSION >= '2.5' && RUBY_ENGINE != 'truffleruby'
39
+ alias_method :append, :write
40
+ else
41
+ def append(*strs)
42
+ strs.each { |str| write str }
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ffi'
4
+
5
+ module Puma
6
+ module JRubyRestart
7
+ extend FFI::Library
8
+ ffi_lib 'c'
9
+ attach_function :chdir, [:string], :int
10
+ end
11
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+ require 'stringio'
3
+
4
+ module Puma
5
+
6
+ # Puma deliberately avoids the use of the json gem and instead performs JSON
7
+ # serialization without any external dependencies. In a puma cluster, loading
8
+ # any gem into the puma master process means that operators cannot use a
9
+ # phased restart to upgrade their application if the new version of that
10
+ # application uses a different version of that gem. The json gem in
11
+ # particular is additionally problematic because it leverages native
12
+ # extensions. If the puma master process relies on a gem with native
13
+ # extensions and operators remove gems from disk related to old releases,
14
+ # subsequent phased restarts can fail.
15
+ #
16
+ # The implementation of JSON serialization in this module is not designed to
17
+ # be particularly full-featured or fast. It just has to handle the few places
18
+ # where Puma relies on JSON serialization internally.
19
+
20
+ module JSONSerialization
21
+ QUOTE = /"/
22
+ BACKSLASH = /\\/
23
+ CONTROL_CHAR_TO_ESCAPE = /[\x00-\x1F]/ # As required by ECMA-404
24
+ CHAR_TO_ESCAPE = Regexp.union QUOTE, BACKSLASH, CONTROL_CHAR_TO_ESCAPE
25
+
26
+ class SerializationError < StandardError; end
27
+
28
+ class << self
29
+ def generate(value)
30
+ StringIO.open do |io|
31
+ serialize_value io, value
32
+ io.string
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def serialize_value(output, value)
39
+ case value
40
+ when Hash
41
+ output << '{'
42
+ value.each_with_index do |(k, v), index|
43
+ output << ',' if index != 0
44
+ serialize_object_key output, k
45
+ output << ':'
46
+ serialize_value output, v
47
+ end
48
+ output << '}'
49
+ when Array
50
+ output << '['
51
+ value.each_with_index do |member, index|
52
+ output << ',' if index != 0
53
+ serialize_value output, member
54
+ end
55
+ output << ']'
56
+ when Integer, Float
57
+ output << value.to_s
58
+ when String
59
+ serialize_string output, value
60
+ when true
61
+ output << 'true'
62
+ when false
63
+ output << 'false'
64
+ when nil
65
+ output << 'null'
66
+ else
67
+ raise SerializationError, "Unexpected value of type #{value.class}"
68
+ end
69
+ end
70
+
71
+ def serialize_string(output, value)
72
+ output << '"'
73
+ output << value.gsub(CHAR_TO_ESCAPE) do |character|
74
+ case character
75
+ when BACKSLASH
76
+ '\\\\'
77
+ when QUOTE
78
+ '\\"'
79
+ when CONTROL_CHAR_TO_ESCAPE
80
+ '\u%.4X' % character.ord
81
+ end
82
+ end
83
+ output << '"'
84
+ end
85
+
86
+ def serialize_object_key(output, value)
87
+ case value
88
+ when Symbol, String
89
+ serialize_string output, value.to_s
90
+ else
91
+ raise SerializationError, "Could not serialize object of type #{value.class} as object key"
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Puma
4
+ class Launcher
5
+
6
+ # This class is used to pickup Gemfile changes during
7
+ # application restarts.
8
+ class BundlePruner
9
+
10
+ def initialize(original_argv, extra_runtime_dependencies, log_writer)
11
+ @original_argv = Array(original_argv)
12
+ @extra_runtime_dependencies = Array(extra_runtime_dependencies)
13
+ @log_writer = log_writer
14
+ end
15
+
16
+ def prune
17
+ return if ENV['PUMA_BUNDLER_PRUNED']
18
+ return unless defined?(Bundler)
19
+
20
+ require_rubygems_min_version!
21
+
22
+ unless puma_wild_path
23
+ log "! Unable to prune Bundler environment, continuing"
24
+ return
25
+ end
26
+
27
+ dirs = paths_to_require_after_prune
28
+
29
+ log '* Pruning Bundler environment'
30
+ home = ENV['GEM_HOME']
31
+ bundle_gemfile = Bundler.original_env['BUNDLE_GEMFILE']
32
+ bundle_app_config = Bundler.original_env['BUNDLE_APP_CONFIG']
33
+
34
+ with_unbundled_env do
35
+ ENV['GEM_HOME'] = home
36
+ ENV['BUNDLE_GEMFILE'] = bundle_gemfile
37
+ ENV['PUMA_BUNDLER_PRUNED'] = '1'
38
+ ENV["BUNDLE_APP_CONFIG"] = bundle_app_config
39
+ args = [Gem.ruby, puma_wild_path, '-I', dirs.join(':')] + @original_argv
40
+ # Ruby 2.0+ defaults to true which breaks socket activation
41
+ args += [{:close_others => false}]
42
+ Kernel.exec(*args)
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def require_rubygems_min_version!
49
+ min_version = Gem::Version.new('2.2')
50
+
51
+ return if min_version <= Gem::Version.new(Gem::VERSION)
52
+
53
+ raise "prune_bundler is not supported on your version of RubyGems. " \
54
+ "You must have RubyGems #{min_version}+ to use this feature."
55
+ end
56
+
57
+ def puma_wild_path
58
+ puma_lib_dir = puma_require_paths.detect { |x| File.exist? File.join(x, '../bin/puma-wild') }
59
+ File.expand_path(File.join(puma_lib_dir, '../bin/puma-wild'))
60
+ end
61
+
62
+ def with_unbundled_env
63
+ bundler_ver = Gem::Version.new(Bundler::VERSION)
64
+ if bundler_ver < Gem::Version.new('2.1.0')
65
+ Bundler.with_clean_env { yield }
66
+ else
67
+ Bundler.with_unbundled_env { yield }
68
+ end
69
+ end
70
+
71
+ def paths_to_require_after_prune
72
+ puma_require_paths + extra_runtime_deps_paths
73
+ end
74
+
75
+ def extra_runtime_deps_paths
76
+ t = @extra_runtime_dependencies.map do |dep_name|
77
+ if (spec = spec_for_gem(dep_name))
78
+ require_paths_for_gem(spec)
79
+ else
80
+ log "* Could not load extra dependency: #{dep_name}"
81
+ nil
82
+ end
83
+ end
84
+ t.flatten!; t.compact!; t
85
+ end
86
+
87
+ def puma_require_paths
88
+ require_paths_for_gem(spec_for_gem('puma'))
89
+ end
90
+
91
+ def spec_for_gem(gem_name)
92
+ Bundler.rubygems.loaded_specs(gem_name)
93
+ end
94
+
95
+ def require_paths_for_gem(gem_spec)
96
+ gem_spec.full_require_paths
97
+ end
98
+
99
+ def log(str)
100
+ @log_writer.log(str)
101
+ end
102
+ end
103
+ end
104
+ end