mega-max-tool 0.0.1

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 (157) hide show
  1. checksums.yaml +7 -0
  2. data/mega-max-tool.gemspec +12 -0
  3. data/unicorn-6.1.0/Application_Timeouts +77 -0
  4. data/unicorn-6.1.0/CONTRIBUTORS +39 -0
  5. data/unicorn-6.1.0/COPYING +674 -0
  6. data/unicorn-6.1.0/DESIGN +95 -0
  7. data/unicorn-6.1.0/Documentation/unicorn.1 +222 -0
  8. data/unicorn-6.1.0/Documentation/unicorn_rails.1 +207 -0
  9. data/unicorn-6.1.0/FAQ +70 -0
  10. data/unicorn-6.1.0/GIT-VERSION-FILE +1 -0
  11. data/unicorn-6.1.0/GIT-VERSION-GEN +39 -0
  12. data/unicorn-6.1.0/GNUmakefile +313 -0
  13. data/unicorn-6.1.0/HACKING +112 -0
  14. data/unicorn-6.1.0/ISSUES +97 -0
  15. data/unicorn-6.1.0/KNOWN_ISSUES +79 -0
  16. data/unicorn-6.1.0/LATEST +24 -0
  17. data/unicorn-6.1.0/LICENSE +67 -0
  18. data/unicorn-6.1.0/Links +58 -0
  19. data/unicorn-6.1.0/NEWS +2890 -0
  20. data/unicorn-6.1.0/PHILOSOPHY +139 -0
  21. data/unicorn-6.1.0/README +151 -0
  22. data/unicorn-6.1.0/Rakefile +16 -0
  23. data/unicorn-6.1.0/SIGNALS +123 -0
  24. data/unicorn-6.1.0/Sandbox +104 -0
  25. data/unicorn-6.1.0/TODO +3 -0
  26. data/unicorn-6.1.0/TUNING +119 -0
  27. data/unicorn-6.1.0/archive/slrnpull.conf +4 -0
  28. data/unicorn-6.1.0/bin/unicorn +128 -0
  29. data/unicorn-6.1.0/bin/unicorn_rails +209 -0
  30. data/unicorn-6.1.0/examples/big_app_gc.rb +2 -0
  31. data/unicorn-6.1.0/examples/echo.ru +27 -0
  32. data/unicorn-6.1.0/examples/init.sh +102 -0
  33. data/unicorn-6.1.0/examples/logger_mp_safe.rb +25 -0
  34. data/unicorn-6.1.0/examples/logrotate.conf +44 -0
  35. data/unicorn-6.1.0/examples/nginx.conf +156 -0
  36. data/unicorn-6.1.0/examples/unicorn.conf.minimal.rb +13 -0
  37. data/unicorn-6.1.0/examples/unicorn.conf.rb +110 -0
  38. data/unicorn-6.1.0/examples/unicorn.socket +11 -0
  39. data/unicorn-6.1.0/examples/unicorn@.service +40 -0
  40. data/unicorn-6.1.0/ext/unicorn_http/CFLAGS +13 -0
  41. data/unicorn-6.1.0/ext/unicorn_http/c_util.h +116 -0
  42. data/unicorn-6.1.0/ext/unicorn_http/common_field_optimization.h +128 -0
  43. data/unicorn-6.1.0/ext/unicorn_http/epollexclusive.h +124 -0
  44. data/unicorn-6.1.0/ext/unicorn_http/ext_help.h +38 -0
  45. data/unicorn-6.1.0/ext/unicorn_http/extconf.rb +37 -0
  46. data/unicorn-6.1.0/ext/unicorn_http/global_variables.h +97 -0
  47. data/unicorn-6.1.0/ext/unicorn_http/httpdate.c +79 -0
  48. data/unicorn-6.1.0/ext/unicorn_http/unicorn_http.c +4319 -0
  49. data/unicorn-6.1.0/ext/unicorn_http/unicorn_http.rl +1025 -0
  50. data/unicorn-6.1.0/ext/unicorn_http/unicorn_http_common.rl +76 -0
  51. data/unicorn-6.1.0/lib/unicorn/app/old_rails/static.rb +59 -0
  52. data/unicorn-6.1.0/lib/unicorn/app/old_rails.rb +35 -0
  53. data/unicorn-6.1.0/lib/unicorn/cgi_wrapper.rb +147 -0
  54. data/unicorn-6.1.0/lib/unicorn/configurator.rb +743 -0
  55. data/unicorn-6.1.0/lib/unicorn/const.rb +21 -0
  56. data/unicorn-6.1.0/lib/unicorn/http_request.rb +201 -0
  57. data/unicorn-6.1.0/lib/unicorn/http_response.rb +61 -0
  58. data/unicorn-6.1.0/lib/unicorn/http_server.rb +893 -0
  59. data/unicorn-6.1.0/lib/unicorn/launcher.rb +62 -0
  60. data/unicorn-6.1.0/lib/unicorn/oob_gc.rb +81 -0
  61. data/unicorn-6.1.0/lib/unicorn/preread_input.rb +33 -0
  62. data/unicorn-6.1.0/lib/unicorn/select_waiter.rb +6 -0
  63. data/unicorn-6.1.0/lib/unicorn/socket_helper.rb +211 -0
  64. data/unicorn-6.1.0/lib/unicorn/stream_input.rb +147 -0
  65. data/unicorn-6.1.0/lib/unicorn/tee_input.rb +131 -0
  66. data/unicorn-6.1.0/lib/unicorn/tmpio.rb +33 -0
  67. data/unicorn-6.1.0/lib/unicorn/util.rb +90 -0
  68. data/unicorn-6.1.0/lib/unicorn/version.rb +1 -0
  69. data/unicorn-6.1.0/lib/unicorn/worker.rb +165 -0
  70. data/unicorn-6.1.0/lib/unicorn.rb +138 -0
  71. data/unicorn-6.1.0/man/man1/unicorn.1 +222 -0
  72. data/unicorn-6.1.0/man/man1/unicorn_rails.1 +207 -0
  73. data/unicorn-6.1.0/setup.rb +1586 -0
  74. data/unicorn-6.1.0/t/GNUmakefile +5 -0
  75. data/unicorn-6.1.0/t/README +42 -0
  76. data/unicorn-6.1.0/t/bin/content-md5-put +36 -0
  77. data/unicorn-6.1.0/t/bin/sha1sum.rb +17 -0
  78. data/unicorn-6.1.0/t/bin/unused_listen +40 -0
  79. data/unicorn-6.1.0/t/broken-app.ru +12 -0
  80. data/unicorn-6.1.0/t/detach.ru +11 -0
  81. data/unicorn-6.1.0/t/env.ru +3 -0
  82. data/unicorn-6.1.0/t/fails-rack-lint.ru +5 -0
  83. data/unicorn-6.1.0/t/heartbeat-timeout.ru +12 -0
  84. data/unicorn-6.1.0/t/listener_names.ru +4 -0
  85. data/unicorn-6.1.0/t/my-tap-lib.sh +201 -0
  86. data/unicorn-6.1.0/t/oob_gc.ru +20 -0
  87. data/unicorn-6.1.0/t/oob_gc_path.ru +20 -0
  88. data/unicorn-6.1.0/t/pid.ru +3 -0
  89. data/unicorn-6.1.0/t/preread_input.ru +17 -0
  90. data/unicorn-6.1.0/t/rack-input-tests.ru +21 -0
  91. data/unicorn-6.1.0/t/t0000-http-basic.sh +50 -0
  92. data/unicorn-6.1.0/t/t0001-reload-bad-config.sh +53 -0
  93. data/unicorn-6.1.0/t/t0002-config-conflict.sh +49 -0
  94. data/unicorn-6.1.0/t/t0002-parser-error.sh +94 -0
  95. data/unicorn-6.1.0/t/t0003-working_directory.sh +51 -0
  96. data/unicorn-6.1.0/t/t0004-heartbeat-timeout.sh +69 -0
  97. data/unicorn-6.1.0/t/t0004-working_directory_broken.sh +24 -0
  98. data/unicorn-6.1.0/t/t0005-working_directory_app.rb.sh +40 -0
  99. data/unicorn-6.1.0/t/t0006-reopen-logs.sh +83 -0
  100. data/unicorn-6.1.0/t/t0006.ru +13 -0
  101. data/unicorn-6.1.0/t/t0007-working_directory_no_embed_cli.sh +44 -0
  102. data/unicorn-6.1.0/t/t0008-back_out_of_upgrade.sh +110 -0
  103. data/unicorn-6.1.0/t/t0009-broken-app.sh +56 -0
  104. data/unicorn-6.1.0/t/t0009-winch_ttin.sh +59 -0
  105. data/unicorn-6.1.0/t/t0010-reap-logging.sh +55 -0
  106. data/unicorn-6.1.0/t/t0011-active-unix-socket.sh +79 -0
  107. data/unicorn-6.1.0/t/t0012-reload-empty-config.sh +86 -0
  108. data/unicorn-6.1.0/t/t0013-rewindable-input-false.sh +24 -0
  109. data/unicorn-6.1.0/t/t0013.ru +12 -0
  110. data/unicorn-6.1.0/t/t0014-rewindable-input-true.sh +24 -0
  111. data/unicorn-6.1.0/t/t0014.ru +12 -0
  112. data/unicorn-6.1.0/t/t0015-configurator-internals.sh +25 -0
  113. data/unicorn-6.1.0/t/t0018-write-on-close.sh +23 -0
  114. data/unicorn-6.1.0/t/t0019-max_header_len.sh +49 -0
  115. data/unicorn-6.1.0/t/t0020-at_exit-handler.sh +49 -0
  116. data/unicorn-6.1.0/t/t0021-process_detach.sh +29 -0
  117. data/unicorn-6.1.0/t/t0022-listener_names-preload_app.sh +32 -0
  118. data/unicorn-6.1.0/t/t0100-rack-input-tests.sh +124 -0
  119. data/unicorn-6.1.0/t/t0116-client_body_buffer_size.sh +80 -0
  120. data/unicorn-6.1.0/t/t0116.ru +16 -0
  121. data/unicorn-6.1.0/t/t0300-no-default-middleware.sh +20 -0
  122. data/unicorn-6.1.0/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
  123. data/unicorn-6.1.0/t/t0301.ru +13 -0
  124. data/unicorn-6.1.0/t/t9000-preread-input.sh +48 -0
  125. data/unicorn-6.1.0/t/t9001-oob_gc.sh +47 -0
  126. data/unicorn-6.1.0/t/t9002-oob_gc-path.sh +75 -0
  127. data/unicorn-6.1.0/t/test-lib.sh +129 -0
  128. data/unicorn-6.1.0/t/write-on-close.ru +11 -0
  129. data/unicorn-6.1.0/test/aggregate.rb +15 -0
  130. data/unicorn-6.1.0/test/benchmark/README +60 -0
  131. data/unicorn-6.1.0/test/benchmark/dd.ru +18 -0
  132. data/unicorn-6.1.0/test/benchmark/ddstream.ru +50 -0
  133. data/unicorn-6.1.0/test/benchmark/readinput.ru +40 -0
  134. data/unicorn-6.1.0/test/benchmark/stack.ru +8 -0
  135. data/unicorn-6.1.0/test/benchmark/uconnect.perl +66 -0
  136. data/unicorn-6.1.0/test/exec/README +5 -0
  137. data/unicorn-6.1.0/test/exec/test_exec.rb +1101 -0
  138. data/unicorn-6.1.0/test/test_helper.rb +306 -0
  139. data/unicorn-6.1.0/test/unit/test_ccc.rb +91 -0
  140. data/unicorn-6.1.0/test/unit/test_configurator.rb +175 -0
  141. data/unicorn-6.1.0/test/unit/test_droplet.rb +28 -0
  142. data/unicorn-6.1.0/test/unit/test_http_parser.rb +884 -0
  143. data/unicorn-6.1.0/test/unit/test_http_parser_ng.rb +714 -0
  144. data/unicorn-6.1.0/test/unit/test_request.rb +182 -0
  145. data/unicorn-6.1.0/test/unit/test_response.rb +111 -0
  146. data/unicorn-6.1.0/test/unit/test_server.rb +342 -0
  147. data/unicorn-6.1.0/test/unit/test_signals.rb +188 -0
  148. data/unicorn-6.1.0/test/unit/test_socket_helper.rb +201 -0
  149. data/unicorn-6.1.0/test/unit/test_stream_input.rb +203 -0
  150. data/unicorn-6.1.0/test/unit/test_tee_input.rb +304 -0
  151. data/unicorn-6.1.0/test/unit/test_upload.rb +301 -0
  152. data/unicorn-6.1.0/test/unit/test_util.rb +131 -0
  153. data/unicorn-6.1.0/test/unit/test_waiter.rb +34 -0
  154. data/unicorn-6.1.0/unicorn.gemspec +49 -0
  155. data/unicorn-6.1.0/unicorn_1 +1 -0
  156. data/unicorn-6.1.0/unicorn_rails_1 +1 -0
  157. metadata +196 -0
@@ -0,0 +1,62 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ # :enddoc:
4
+ $stdout.sync = $stderr.sync = true
5
+ $stdin.binmode
6
+ $stdout.binmode
7
+ $stderr.binmode
8
+
9
+ require 'unicorn'
10
+
11
+ module Unicorn::Launcher
12
+
13
+ # We don't do a lot of standard daemonization stuff:
14
+ # * umask is whatever was set by the parent process at startup
15
+ # and can be set in config.ru and config_file, so making it
16
+ # 0000 and potentially exposing sensitive log data can be bad
17
+ # policy.
18
+ # * don't bother to chdir("/") here since unicorn is designed to
19
+ # run inside APP_ROOT. Unicorn will also re-chdir() to
20
+ # the directory it was started in when being re-executed
21
+ # to pickup code changes if the original deployment directory
22
+ # is a symlink or otherwise got replaced.
23
+ def self.daemonize!(options)
24
+ cfg = Unicorn::Configurator
25
+ $stdin.reopen("/dev/null")
26
+
27
+ # We only start a new process group if we're not being reexecuted
28
+ # and inheriting file descriptors from our parent
29
+ unless ENV['UNICORN_FD']
30
+ # grandparent - reads pipe, exits when master is ready
31
+ # \_ parent - exits immediately ASAP
32
+ # \_ unicorn master - writes to pipe when ready
33
+
34
+ rd, wr = Unicorn.pipe
35
+ grandparent = $$
36
+ if fork
37
+ wr.close # grandparent does not write
38
+ else
39
+ rd.close # unicorn master does not read
40
+ Process.setsid
41
+ exit if fork # parent dies now
42
+ end
43
+
44
+ if grandparent == $$
45
+ # this will block until HttpServer#join runs (or it dies)
46
+ master_pid = (rd.readpartial(16) rescue nil).to_i
47
+ unless master_pid > 1
48
+ warn "master failed to start, check stderr log for details"
49
+ exit!(1)
50
+ end
51
+ exit 0
52
+ else # unicorn master process
53
+ options[:ready_pipe] = wr
54
+ end
55
+ end
56
+ # $stderr/$stderr can/will be redirected separately in the Unicorn config
57
+ cfg::DEFAULTS[:stderr_path] ||= "/dev/null"
58
+ cfg::DEFAULTS[:stdout_path] ||= "/dev/null"
59
+ cfg::RACKUP[:daemonized] = true
60
+ end
61
+
62
+ end
@@ -0,0 +1,81 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ # Strongly consider https://github.com/tmm1/gctools if using Ruby 2.1+
4
+ # It is built on new APIs in Ruby 2.1, so it is more intelligent than
5
+ # this historical implementation.
6
+ #
7
+ # Users on Ruby 2.0 (not 2.1+) may also want to check out
8
+ # lib/middleware/unicorn_oobgc.rb from the Discourse project
9
+ # (https://github.com/discourse/discourse)
10
+ #
11
+ # The following information is only for historical versions of Ruby.
12
+ #
13
+ # Runs GC after requests, after closing the client socket and
14
+ # before attempting to accept more connections.
15
+ #
16
+ # This shouldn't hurt overall performance as long as the server cluster
17
+ # is at <50% CPU capacity, and improves the performance of most memory
18
+ # intensive requests. This serves to improve _client-visible_
19
+ # performance (possibly at the cost of overall performance).
20
+ #
21
+ # Increasing the number of +worker_processes+ may be necessary to
22
+ # improve average client response times because some of your workers
23
+ # will be busy doing GC and unable to service clients. Think of
24
+ # using more workers with this module as a poor man's concurrent GC.
25
+ #
26
+ # We'll call GC after each request is been written out to the socket, so
27
+ # the client never sees the extra GC hit it.
28
+ #
29
+ # This middleware is _only_ effective for applications that use a lot
30
+ # of memory, and will hurt simpler apps/endpoints that can process
31
+ # multiple requests before incurring GC.
32
+ #
33
+ # This middleware is only designed to work with unicorn, as it harms
34
+ # performance with keepalive-enabled servers.
35
+ #
36
+ # Example (in config.ru):
37
+ #
38
+ # require 'unicorn/oob_gc'
39
+ #
40
+ # # GC ever two requests that hit /expensive/foo or /more_expensive/foo
41
+ # # in your app. By default, this will GC once every 5 requests
42
+ # # for all endpoints in your app
43
+ # use Unicorn::OobGC, 2, %r{\A/(?:expensive/foo|more_expensive/foo)}
44
+ #
45
+ # Feedback from users of early implementations of this module:
46
+ # * https://yhbt.net/unicorn-public/0BFC98E9-072B-47EE-9A70-05478C20141B@lukemelia.com/
47
+ # * https://yhbt.net/unicorn-public/AANLkTilUbgdyDv9W1bi-s_W6kq9sOhWfmuYkKLoKGOLj@mail.gmail.com/
48
+
49
+ module Unicorn::OobGC
50
+
51
+ # this pretends to be Rack middleware because it used to be
52
+ # But we need to hook into unicorn internals so we need to close
53
+ # the socket before clearing the request env.
54
+ #
55
+ # +interval+ is the number of requests matching the +path+ regular
56
+ # expression before invoking GC.
57
+ def self.new(app, interval = 5, path = %r{\A/})
58
+ @@nr = interval
59
+ self.const_set :OOBGC_PATH, path
60
+ self.const_set :OOBGC_INTERVAL, interval
61
+ ObjectSpace.each_object(Unicorn::HttpServer) do |s|
62
+ s.extend(self)
63
+ end
64
+ app # pretend to be Rack middleware since it was in the past
65
+ end
66
+
67
+ #:stopdoc:
68
+ def process_client(client)
69
+ super(client) # Unicorn::HttpServer#process_client
70
+ env = instance_variable_get(:@request).env
71
+ if OOBGC_PATH =~ env['PATH_INFO'] && ((@@nr -= 1) <= 0)
72
+ @@nr = OOBGC_INTERVAL
73
+ env.clear
74
+ disabled = GC.enable
75
+ GC.start
76
+ GC.disable if disabled
77
+ end
78
+ end
79
+
80
+ # :startdoc:
81
+ end
@@ -0,0 +1,33 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ module Unicorn
4
+ # This middleware is used to ensure input is buffered to memory
5
+ # or disk (depending on size) before the application is dispatched
6
+ # by entirely consuming it (from TeeInput) beforehand.
7
+ #
8
+ # Usage (in config.ru):
9
+ #
10
+ # require 'unicorn/preread_input'
11
+ # if defined?(Unicorn)
12
+ # use Unicorn::PrereadInput
13
+ # end
14
+ # run YourApp.new
15
+ class PrereadInput
16
+
17
+ # :stopdoc:
18
+ def initialize(app)
19
+ @app = app
20
+ end
21
+
22
+ def call(env)
23
+ buf = ""
24
+ input = env["rack.input"]
25
+ if input.respond_to?(:rewind)
26
+ true while input.read(16384, buf)
27
+ input.rewind
28
+ end
29
+ @app.call(env)
30
+ end
31
+ # :startdoc:
32
+ end
33
+ end
@@ -0,0 +1,6 @@
1
+ # fallback for non-Linux and Linux <4.5 systems w/o EPOLLEXCLUSIVE
2
+ class Unicorn::SelectWaiter # :nodoc:
3
+ def get_readers(ready, readers, timeout) # :nodoc:
4
+ ret = IO.select(readers, nil, nil, timeout) and ready.replace(ret[0])
5
+ end
6
+ end
@@ -0,0 +1,211 @@
1
+ # -*- encoding: binary -*-
2
+ # :enddoc:
3
+ require 'socket'
4
+
5
+ module Unicorn
6
+
7
+ # Instead of using a generic Kgio::Socket for everything,
8
+ # tag TCP sockets so we can use TCP_INFO under Linux without
9
+ # incurring extra syscalls for Unix domain sockets.
10
+ # TODO: remove these when we remove kgio
11
+ TCPClient = Class.new(Kgio::Socket) # :nodoc:
12
+ class TCPSrv < Kgio::TCPServer # :nodoc:
13
+ def kgio_tryaccept # :nodoc:
14
+ super(TCPClient)
15
+ end
16
+ end
17
+
18
+ module SocketHelper
19
+
20
+ # internal interface
21
+ DEFAULTS = {
22
+ # The semantics for TCP_DEFER_ACCEPT changed in Linux 2.6.32+
23
+ # with commit d1b99ba41d6c5aa1ed2fc634323449dd656899e9
24
+ # This change shouldn't affect unicorn users behind nginx (a
25
+ # value of 1 remains an optimization).
26
+ :tcp_defer_accept => 1,
27
+
28
+ # FreeBSD, we need to override this to 'dataready' if we
29
+ # eventually support non-HTTP/1.x
30
+ :accept_filter => 'httpready',
31
+
32
+ # same default value as Mongrel
33
+ :backlog => 1024,
34
+
35
+ # favor latency over bandwidth savings
36
+ :tcp_nopush => nil,
37
+ :tcp_nodelay => true,
38
+ }
39
+
40
+ # configure platform-specific options (only tested on Linux 2.6 so far)
41
+ def accf_arg(af_name)
42
+ [ af_name, nil ].pack('a16a240')
43
+ end if RUBY_PLATFORM =~ /freebsd/ && Socket.const_defined?(:SO_ACCEPTFILTER)
44
+
45
+ def set_tcp_sockopt(sock, opt)
46
+ # just in case, even LANs can break sometimes. Linux sysadmins
47
+ # can lower net.ipv4.tcp_keepalive_* sysctl knobs to very low values.
48
+ Socket.const_defined?(:SO_KEEPALIVE) and
49
+ sock.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, 1)
50
+
51
+ if Socket.const_defined?(:TCP_NODELAY)
52
+ val = opt[:tcp_nodelay]
53
+ val = DEFAULTS[:tcp_nodelay] if val.nil?
54
+ sock.setsockopt(:IPPROTO_TCP, :TCP_NODELAY, val ? 1 : 0)
55
+ end
56
+
57
+ val = opt[:tcp_nopush]
58
+ unless val.nil?
59
+ if Socket.const_defined?(:TCP_CORK) # Linux
60
+ sock.setsockopt(:IPPROTO_TCP, :TCP_CORK, val)
61
+ elsif Socket.const_defined?(:TCP_NOPUSH) # FreeBSD
62
+ sock.setsockopt(:IPPROTO_TCP, :TCP_NOPUSH, val)
63
+ end
64
+ end
65
+
66
+ # No good reason to ever have deferred accepts off in single-threaded
67
+ # servers (except maybe benchmarking)
68
+ if Socket.const_defined?(:TCP_DEFER_ACCEPT)
69
+ # this differs from nginx, since nginx doesn't allow us to
70
+ # configure the the timeout...
71
+ seconds = opt[:tcp_defer_accept]
72
+ seconds = DEFAULTS[:tcp_defer_accept] if [true,nil].include?(seconds)
73
+ seconds = 0 unless seconds # nil/false means disable this
74
+ sock.setsockopt(:IPPROTO_TCP, :TCP_DEFER_ACCEPT, seconds)
75
+ elsif respond_to?(:accf_arg)
76
+ name = opt[:accept_filter]
77
+ name = DEFAULTS[:accept_filter] if name.nil?
78
+ sock.listen(opt[:backlog])
79
+ got = (sock.getsockopt(:SOL_SOCKET, :SO_ACCEPTFILTER) rescue nil).to_s
80
+ arg = accf_arg(name)
81
+ begin
82
+ sock.setsockopt(:SOL_SOCKET, :SO_ACCEPTFILTER, arg)
83
+ rescue => e
84
+ logger.error("#{sock_name(sock)} " \
85
+ "failed to set accept_filter=#{name} (#{e.inspect})")
86
+ logger.error("perhaps accf_http(9) needs to be loaded".freeze)
87
+ end if arg != got
88
+ end
89
+ end
90
+
91
+ def set_server_sockopt(sock, opt)
92
+ opt = DEFAULTS.merge(opt || {})
93
+
94
+ TCPSocket === sock and set_tcp_sockopt(sock, opt)
95
+
96
+ rcvbuf, sndbuf = opt.values_at(:rcvbuf, :sndbuf)
97
+ if rcvbuf || sndbuf
98
+ log_buffer_sizes(sock, "before: ")
99
+ sock.setsockopt(:SOL_SOCKET, :SO_RCVBUF, rcvbuf) if rcvbuf
100
+ sock.setsockopt(:SOL_SOCKET, :SO_SNDBUF, sndbuf) if sndbuf
101
+ log_buffer_sizes(sock, " after: ")
102
+ end
103
+ sock.listen(opt[:backlog])
104
+ rescue => e
105
+ Unicorn.log_error(logger, "#{sock_name(sock)} #{opt.inspect}", e)
106
+ end
107
+
108
+ def log_buffer_sizes(sock, pfx = '')
109
+ rcvbuf = sock.getsockopt(:SOL_SOCKET, :SO_RCVBUF).int
110
+ sndbuf = sock.getsockopt(:SOL_SOCKET, :SO_SNDBUF).int
111
+ logger.info "#{pfx}#{sock_name(sock)} rcvbuf=#{rcvbuf} sndbuf=#{sndbuf}"
112
+ end
113
+
114
+ # creates a new server, socket. address may be a HOST:PORT or
115
+ # an absolute path to a UNIX socket. address can even be a Socket
116
+ # object in which case it is immediately returned
117
+ def bind_listen(address = '0.0.0.0:8080', opt = {})
118
+ return address unless String === address
119
+
120
+ sock = if address.start_with?('/')
121
+ if File.exist?(address)
122
+ if File.socket?(address)
123
+ begin
124
+ UNIXSocket.new(address).close
125
+ # fall through, try to bind(2) and fail with EADDRINUSE
126
+ # (or succeed from a small race condition we can't sanely avoid).
127
+ rescue Errno::ECONNREFUSED
128
+ logger.info "unlinking existing socket=#{address}"
129
+ File.unlink(address)
130
+ end
131
+ else
132
+ raise ArgumentError,
133
+ "socket=#{address} specified but it is not a socket!"
134
+ end
135
+ end
136
+ old_umask = File.umask(opt[:umask] || 0)
137
+ begin
138
+ Kgio::UNIXServer.new(address)
139
+ ensure
140
+ File.umask(old_umask)
141
+ end
142
+ elsif /\A\[([a-fA-F0-9:]+)\]:(\d+)\z/ =~ address
143
+ new_tcp_server($1, $2.to_i, opt.merge(:ipv6=>true))
144
+ elsif /\A(\d+\.\d+\.\d+\.\d+):(\d+)\z/ =~ address
145
+ new_tcp_server($1, $2.to_i, opt)
146
+ else
147
+ raise ArgumentError, "Don't know how to bind: #{address}"
148
+ end
149
+ set_server_sockopt(sock, opt)
150
+ sock
151
+ end
152
+
153
+ def new_tcp_server(addr, port, opt)
154
+ # n.b. we set FD_CLOEXEC in the workers
155
+ sock = Socket.new(opt[:ipv6] ? :AF_INET6 : :AF_INET, :SOCK_STREAM)
156
+ if opt.key?(:ipv6only)
157
+ Socket.const_defined?(:IPV6_V6ONLY) or
158
+ abort "Socket::IPV6_V6ONLY not defined, upgrade Ruby and/or your OS"
159
+ sock.setsockopt(:IPPROTO_IPV6, :IPV6_V6ONLY, opt[:ipv6only] ? 1 : 0)
160
+ end
161
+ sock.setsockopt(:SOL_SOCKET, :SO_REUSEADDR, 1)
162
+ if Socket.const_defined?(:SO_REUSEPORT) && opt[:reuseport]
163
+ sock.setsockopt(:SOL_SOCKET, :SO_REUSEPORT, 1)
164
+ end
165
+ sock.bind(Socket.pack_sockaddr_in(port, addr))
166
+ sock.autoclose = false
167
+ TCPSrv.for_fd(sock.fileno)
168
+ end
169
+
170
+ # returns rfc2732-style (e.g. "[::1]:666") addresses for IPv6
171
+ def tcp_name(sock)
172
+ port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
173
+ addr.include?(':') ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
174
+ end
175
+ module_function :tcp_name
176
+
177
+ # Returns the configuration name of a socket as a string. sock may
178
+ # be a string value, in which case it is returned as-is
179
+ # Warning: TCP sockets may not always return the name given to it.
180
+ def sock_name(sock)
181
+ case sock
182
+ when String then sock
183
+ when UNIXServer
184
+ Socket.unpack_sockaddr_un(sock.getsockname)
185
+ when TCPServer
186
+ tcp_name(sock)
187
+ when Socket
188
+ begin
189
+ tcp_name(sock)
190
+ rescue ArgumentError
191
+ Socket.unpack_sockaddr_un(sock.getsockname)
192
+ end
193
+ else
194
+ raise ArgumentError, "Unhandled class #{sock.class}: #{sock.inspect}"
195
+ end
196
+ end
197
+
198
+ module_function :sock_name
199
+
200
+ # casts a given Socket to be a TCPServer or UNIXServer
201
+ def server_cast(sock)
202
+ begin
203
+ Socket.unpack_sockaddr_in(sock.getsockname)
204
+ TCPSrv.for_fd(sock.fileno)
205
+ rescue ArgumentError
206
+ Kgio::UNIXServer.for_fd(sock.fileno)
207
+ end
208
+ end
209
+
210
+ end # module SocketHelper
211
+ end # module Unicorn
@@ -0,0 +1,147 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ # When processing uploads, unicorn may expose a StreamInput object under
4
+ # "rack.input" of the Rack environment when
5
+ # Unicorn::Configurator#rewindable_input is set to +false+
6
+ class Unicorn::StreamInput
7
+ # The I/O chunk size (in +bytes+) for I/O operations where
8
+ # the size cannot be user-specified when a method is called.
9
+ # The default is 16 kilobytes.
10
+ @@io_chunk_size = Unicorn::Const::CHUNK_SIZE # :nodoc:
11
+
12
+ # Initializes a new StreamInput object. You normally do not have to call
13
+ # this unless you are writing an HTTP server.
14
+ def initialize(socket, request) # :nodoc:
15
+ @chunked = request.content_length.nil?
16
+ @socket = socket
17
+ @parser = request
18
+ @buf = request.buf
19
+ @rbuf = ''
20
+ @bytes_read = 0
21
+ filter_body(@rbuf, @buf) unless @buf.empty?
22
+ end
23
+
24
+ # :call-seq:
25
+ # ios.read([length [, buffer ]]) => string, buffer, or nil
26
+ #
27
+ # Reads at most length bytes from the I/O stream, or to the end of
28
+ # file if length is omitted or is nil. length must be a non-negative
29
+ # integer or nil. If the optional buffer argument is present, it
30
+ # must reference a String, which will receive the data.
31
+ #
32
+ # At end of file, it returns nil or '' depend on length.
33
+ # ios.read() and ios.read(nil) returns ''.
34
+ # ios.read(length [, buffer]) returns nil.
35
+ #
36
+ # If the Content-Length of the HTTP request is known (as is the common
37
+ # case for POST requests), then ios.read(length [, buffer]) will block
38
+ # until the specified length is read (or it is the last chunk).
39
+ # Otherwise, for uncommon "Transfer-Encoding: chunked" requests,
40
+ # ios.read(length [, buffer]) will return immediately if there is
41
+ # any data and only block when nothing is available (providing
42
+ # IO#readpartial semantics).
43
+ def read(length = nil, rv = '')
44
+ if length
45
+ if length <= @rbuf.size
46
+ length < 0 and raise ArgumentError, "negative length #{length} given"
47
+ rv.replace(@rbuf.slice!(0, length))
48
+ else
49
+ to_read = length - @rbuf.size
50
+ rv.replace(@rbuf.slice!(0, @rbuf.size))
51
+ until to_read == 0 || eof? || (rv.size > 0 && @chunked)
52
+ @socket.kgio_read(to_read, @buf) or eof!
53
+ filter_body(@rbuf, @buf)
54
+ rv << @rbuf
55
+ to_read -= @rbuf.size
56
+ end
57
+ @rbuf.clear
58
+ end
59
+ rv = nil if rv.empty? && length != 0
60
+ else
61
+ read_all(rv)
62
+ end
63
+ rv
64
+ end
65
+
66
+ # :call-seq:
67
+ # ios.gets => string or nil
68
+ #
69
+ # Reads the next ``line'' from the I/O stream; lines are separated
70
+ # by the global record separator ($/, typically "\n"). A global
71
+ # record separator of nil reads the entire unread contents of ios.
72
+ # Returns nil if called at the end of file.
73
+ # This takes zero arguments for strict Rack::Lint compatibility,
74
+ # unlike IO#gets.
75
+ def gets
76
+ sep = $/
77
+ if sep.nil?
78
+ read_all(rv = '')
79
+ return rv.empty? ? nil : rv
80
+ end
81
+ re = /\A(.*?#{Regexp.escape(sep)})/
82
+
83
+ begin
84
+ @rbuf.sub!(re, '') and return $1
85
+ return @rbuf.empty? ? nil : @rbuf.slice!(0, @rbuf.size) if eof?
86
+ @socket.kgio_read(@@io_chunk_size, @buf) or eof!
87
+ filter_body(once = '', @buf)
88
+ @rbuf << once
89
+ end while true
90
+ end
91
+
92
+ # :call-seq:
93
+ # ios.each { |line| block } => ios
94
+ #
95
+ # Executes the block for every ``line'' in *ios*, where lines are
96
+ # separated by the global record separator ($/, typically "\n").
97
+ def each
98
+ while line = gets
99
+ yield line
100
+ end
101
+
102
+ self # Rack does not specify what the return value is here
103
+ end
104
+
105
+ private
106
+
107
+ def eof?
108
+ if @parser.body_eof?
109
+ while @chunked && ! @parser.parse
110
+ once = @socket.kgio_read(@@io_chunk_size) or eof!
111
+ @buf << once
112
+ end
113
+ @socket = nil
114
+ true
115
+ else
116
+ false
117
+ end
118
+ end
119
+
120
+ def filter_body(dst, src)
121
+ rv = @parser.filter_body(dst, src)
122
+ @bytes_read += dst.size
123
+ rv
124
+ end
125
+
126
+ def read_all(dst)
127
+ dst.replace(@rbuf)
128
+ @socket or return
129
+ until eof?
130
+ @socket.kgio_read(@@io_chunk_size, @buf) or eof!
131
+ filter_body(@rbuf, @buf)
132
+ dst << @rbuf
133
+ end
134
+ ensure
135
+ @rbuf.clear
136
+ end
137
+
138
+ def eof!
139
+ # in case client only did a premature shutdown(SHUT_WR)
140
+ # we do support clients that shutdown(SHUT_WR) after the
141
+ # _entire_ request has been sent, and those will not have
142
+ # raised EOFError on us.
143
+ @socket.shutdown if @socket
144
+ ensure
145
+ raise Unicorn::ClientShutdown, "bytes_read=#{@bytes_read}", []
146
+ end
147
+ end
@@ -0,0 +1,131 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ # Acts like tee(1) on an input input to provide a input-like stream
4
+ # while providing rewindable semantics through a File/StringIO backing
5
+ # store. On the first pass, the input is only read on demand so your
6
+ # Rack application can use input notification (upload progress and
7
+ # like). This should fully conform to the Rack::Lint::InputWrapper
8
+ # specification on the public API. This class is intended to be a
9
+ # strict interpretation of Rack::Lint::InputWrapper functionality and
10
+ # will not support any deviations from it.
11
+ #
12
+ # When processing uploads, unicorn exposes a TeeInput object under
13
+ # "rack.input" of the Rack environment by default.
14
+ class Unicorn::TeeInput < Unicorn::StreamInput
15
+ # The maximum size (in +bytes+) to buffer in memory before
16
+ # resorting to a temporary file. Default is 112 kilobytes.
17
+ @@client_body_buffer_size = Unicorn::Const::MAX_BODY # :nodoc:
18
+
19
+ # sets the maximum size of request bodies to buffer in memory,
20
+ # amounts larger than this are buffered to the filesystem
21
+ def self.client_body_buffer_size=(bytes) # :nodoc:
22
+ @@client_body_buffer_size = bytes
23
+ end
24
+
25
+ # returns the maximum size of request bodies to buffer in memory,
26
+ # amounts larger than this are buffered to the filesystem
27
+ def self.client_body_buffer_size # :nodoc:
28
+ @@client_body_buffer_size
29
+ end
30
+
31
+ # for Rack::TempfileReaper in rack 1.6+
32
+ def new_tmpio # :nodoc:
33
+ tmpio = Unicorn::TmpIO.new
34
+ (@parser.env['rack.tempfiles'] ||= []) << tmpio
35
+ tmpio
36
+ end
37
+
38
+ # Initializes a new TeeInput object. You normally do not have to call
39
+ # this unless you are writing an HTTP server.
40
+ def initialize(socket, request) # :nodoc:
41
+ @len = request.content_length
42
+ super
43
+ @tmp = @len && @len <= @@client_body_buffer_size ?
44
+ StringIO.new("") : new_tmpio
45
+ end
46
+
47
+ # :call-seq:
48
+ # ios.size => Integer
49
+ #
50
+ # Returns the size of the input. For requests with a Content-Length
51
+ # header value, this will not read data off the socket and just return
52
+ # the value of the Content-Length header as an Integer.
53
+ #
54
+ # For Transfer-Encoding:chunked requests, this requires consuming
55
+ # all of the input stream before returning since there's no other
56
+ # way to determine the size of the request body beforehand.
57
+ #
58
+ # This method is no longer part of the Rack specification as of
59
+ # Rack 1.2, so its use is not recommended. This method only exists
60
+ # for compatibility with Rack applications designed for Rack 1.1 and
61
+ # earlier. Most applications should only need to call +read+ with a
62
+ # specified +length+ in a loop until it returns +nil+.
63
+ def size
64
+ @len and return @len
65
+ pos = @tmp.pos
66
+ consume!
67
+ @tmp.pos = pos
68
+ @len = @tmp.size
69
+ end
70
+
71
+ # :call-seq:
72
+ # ios.read([length [, buffer ]]) => string, buffer, or nil
73
+ #
74
+ # Reads at most length bytes from the I/O stream, or to the end of
75
+ # file if length is omitted or is nil. length must be a non-negative
76
+ # integer or nil. If the optional buffer argument is present, it
77
+ # must reference a String, which will receive the data.
78
+ #
79
+ # At end of file, it returns nil or "" depend on length.
80
+ # ios.read() and ios.read(nil) returns "".
81
+ # ios.read(length [, buffer]) returns nil.
82
+ #
83
+ # If the Content-Length of the HTTP request is known (as is the common
84
+ # case for POST requests), then ios.read(length [, buffer]) will block
85
+ # until the specified length is read (or it is the last chunk).
86
+ # Otherwise, for uncommon "Transfer-Encoding: chunked" requests,
87
+ # ios.read(length [, buffer]) will return immediately if there is
88
+ # any data and only block when nothing is available (providing
89
+ # IO#readpartial semantics).
90
+ def read(*args)
91
+ @socket ? tee(super) : @tmp.read(*args)
92
+ end
93
+
94
+ # :call-seq:
95
+ # ios.gets => string or nil
96
+ #
97
+ # Reads the next ``line'' from the I/O stream; lines are separated
98
+ # by the global record separator ($/, typically "\n"). A global
99
+ # record separator of nil reads the entire unread contents of ios.
100
+ # Returns nil if called at the end of file.
101
+ # This takes zero arguments for strict Rack::Lint compatibility,
102
+ # unlike IO#gets.
103
+ def gets
104
+ @socket ? tee(super) : @tmp.gets
105
+ end
106
+
107
+ # :call-seq:
108
+ # ios.rewind => 0
109
+ #
110
+ # Positions the *ios* pointer to the beginning of input, returns
111
+ # the offset (zero) of the +ios+ pointer. Subsequent reads will
112
+ # start from the beginning of the previously-buffered input.
113
+ def rewind
114
+ return 0 if 0 == @tmp.size
115
+ consume! if @socket
116
+ @tmp.rewind # Rack does not specify what the return value is here
117
+ end
118
+
119
+ private
120
+
121
+ # consumes the stream of the socket
122
+ def consume!
123
+ junk = ""
124
+ nil while read(@@io_chunk_size, junk)
125
+ end
126
+
127
+ def tee(buffer)
128
+ @tmp.write(buffer) if buffer
129
+ buffer
130
+ end
131
+ end