unicorn 4.9.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +5 -5
  2. data/.gitattributes +5 -0
  3. data/.olddoc.yml +13 -6
  4. data/Application_Timeouts +7 -7
  5. data/DESIGN +2 -4
  6. data/Documentation/.gitignore +1 -3
  7. data/Documentation/unicorn.1 +222 -0
  8. data/Documentation/unicorn_rails.1 +207 -0
  9. data/FAQ +17 -8
  10. data/GIT-VERSION-GEN +1 -1
  11. data/GNUmakefile +121 -56
  12. data/HACKING +1 -2
  13. data/ISSUES +40 -41
  14. data/KNOWN_ISSUES +11 -11
  15. data/LICENSE +2 -2
  16. data/Links +24 -25
  17. data/PHILOSOPHY +0 -6
  18. data/README +46 -39
  19. data/SIGNALS +2 -2
  20. data/Sandbox +10 -9
  21. data/TODO +0 -2
  22. data/TUNING +30 -9
  23. data/archive/slrnpull.conf +1 -1
  24. data/bin/unicorn +4 -2
  25. data/bin/unicorn_rails +3 -3
  26. data/examples/big_app_gc.rb +1 -1
  27. data/examples/init.sh +36 -8
  28. data/examples/logrotate.conf +17 -2
  29. data/examples/nginx.conf +14 -14
  30. data/examples/unicorn.conf.minimal.rb +2 -2
  31. data/examples/unicorn.conf.rb +3 -6
  32. data/examples/unicorn.socket +11 -0
  33. data/examples/unicorn@.service +40 -0
  34. data/ext/unicorn_http/common_field_optimization.h +23 -5
  35. data/ext/unicorn_http/ext_help.h +0 -20
  36. data/ext/unicorn_http/extconf.rb +37 -1
  37. data/ext/unicorn_http/global_variables.h +1 -1
  38. data/ext/unicorn_http/httpdate.c +2 -2
  39. data/ext/unicorn_http/unicorn_http.rl +167 -170
  40. data/ext/unicorn_http/unicorn_http_common.rl +1 -1
  41. data/lib/unicorn.rb +66 -46
  42. data/lib/unicorn/configurator.rb +110 -44
  43. data/lib/unicorn/const.rb +2 -25
  44. data/lib/unicorn/http_request.rb +110 -31
  45. data/lib/unicorn/http_response.rb +17 -31
  46. data/lib/unicorn/http_server.rb +238 -157
  47. data/lib/unicorn/launcher.rb +1 -1
  48. data/lib/unicorn/oob_gc.rb +6 -6
  49. data/lib/unicorn/socket_helper.rb +58 -78
  50. data/lib/unicorn/stream_input.rb +8 -7
  51. data/lib/unicorn/tee_input.rb +8 -10
  52. data/lib/unicorn/tmpio.rb +8 -7
  53. data/lib/unicorn/util.rb +5 -4
  54. data/lib/unicorn/worker.rb +36 -23
  55. data/t/GNUmakefile +3 -72
  56. data/t/README +4 -4
  57. data/t/t0011-active-unix-socket.sh +1 -1
  58. data/t/t0012-reload-empty-config.sh +2 -1
  59. data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
  60. data/t/t0301.ru +13 -0
  61. data/t/test-lib.sh +2 -2
  62. data/test/benchmark/README +14 -4
  63. data/test/benchmark/ddstream.ru +50 -0
  64. data/test/benchmark/readinput.ru +40 -0
  65. data/test/benchmark/uconnect.perl +66 -0
  66. data/test/exec/test_exec.rb +73 -19
  67. data/test/test_helper.rb +40 -31
  68. data/test/unit/test_ccc.rb +91 -0
  69. data/test/unit/test_droplet.rb +1 -1
  70. data/test/unit/test_http_parser.rb +46 -16
  71. data/test/unit/test_http_parser_ng.rb +97 -114
  72. data/test/unit/test_request.rb +10 -10
  73. data/test/unit/test_response.rb +28 -16
  74. data/test/unit/test_server.rb +86 -12
  75. data/test/unit/test_signals.rb +8 -8
  76. data/test/unit/test_socket_helper.rb +14 -10
  77. data/test/unit/test_upload.rb +9 -14
  78. data/test/unit/test_util.rb +27 -2
  79. data/unicorn.gemspec +27 -19
  80. metadata +24 -45
  81. data/Documentation/GNUmakefile +0 -30
  82. data/Documentation/unicorn.1.txt +0 -185
  83. data/Documentation/unicorn_rails.1.txt +0 -175
  84. data/examples/git.ru +0 -13
  85. data/lib/unicorn/app/exec_cgi.rb +0 -154
  86. data/lib/unicorn/app/inetd.rb +0 -109
  87. data/lib/unicorn/ssl_client.rb +0 -11
  88. data/lib/unicorn/ssl_configurator.rb +0 -104
  89. data/lib/unicorn/ssl_server.rb +0 -42
  90. data/t/hijack.ru +0 -42
  91. data/t/t0016-trust-x-forwarded-false.sh +0 -30
  92. data/t/t0017-trust-x-forwarded-true.sh +0 -30
  93. data/t/t0200-rack-hijack.sh +0 -27
  94. data/test/unit/test_http_parser_xftrust.rb +0 -38
  95. data/test/unit/test_sni_hostnames.rb +0 -47
@@ -1,4 +1,4 @@
1
1
  # group_name max expire headers_only
2
2
  gmane.comp.lang.ruby.unicorn.general 1000000000 1000000000 0
3
3
 
4
- # usage: slrnpull -d $PWD -h news.gmane.org --no-post
4
+ # usage: slrnpull -d $PWD -h news.gmane.io --no-post
data/bin/unicorn CHANGED
@@ -6,6 +6,7 @@
6
6
  ENV["RACK_ENV"] ||= "development"
7
7
  rackup_opts = Unicorn::Configurator::RACKUP
8
8
  options = rackup_opts[:options]
9
+ set_no_default_middleware = true
9
10
 
10
11
  op = OptionParser.new("", 24, ' ') do |opts|
11
12
  cmd = File.basename($0)
@@ -29,7 +30,7 @@
29
30
 
30
31
  opts.on("-I", "--include PATH",
31
32
  "specify $LOAD_PATH (may be used more than once)") do |path|
32
- $LOAD_PATH.unshift(*path.split(/:/))
33
+ $LOAD_PATH.unshift(*path.split(':'))
33
34
  end
34
35
 
35
36
  opts.on("-r", "--require LIBRARY",
@@ -60,7 +61,7 @@
60
61
 
61
62
  opts.on("-N", "--no-default-middleware",
62
63
  "do not load middleware implied by RACK_ENV") do |e|
63
- rackup_opts[:no_default_middleware] = true
64
+ rackup_opts[:no_default_middleware] = true if set_no_default_middleware
64
65
  end
65
66
 
66
67
  opts.on("-D", "--daemonize", "run daemonized in the background") do |d|
@@ -110,6 +111,7 @@
110
111
  opts.parse! ARGV
111
112
  end
112
113
 
114
+ set_no_default_middleware = false
113
115
  app = Unicorn.builder(ARGV[0] || 'config.ru', op)
114
116
  op = nil
115
117
 
data/bin/unicorn_rails CHANGED
@@ -30,7 +30,7 @@
30
30
 
31
31
  opts.on("-I", "--include PATH",
32
32
  "specify $LOAD_PATH (may be used more than once)") do |path|
33
- $LOAD_PATH.unshift(*path.split(/:/))
33
+ $LOAD_PATH.unshift(*path.split(':'))
34
34
  end
35
35
 
36
36
  opts.on("-r", "--require LIBRARY",
@@ -132,11 +132,11 @@ def rails_builder(ru, op, daemonize)
132
132
 
133
133
  # this lambda won't run until after forking if preload_app is false
134
134
  # this runs after config file reloading
135
- lambda do ||
135
+ lambda do |x, server|
136
136
  # Rails 3 includes a config.ru, use it if we find it after
137
137
  # working_directory is bound.
138
138
  ::File.exist?('config.ru') and
139
- return Unicorn.builder('config.ru', op).call
139
+ return Unicorn.builder('config.ru', op).call(x, server)
140
140
 
141
141
  # Load Rails and (possibly) the private version of Rack it bundles.
142
142
  begin
@@ -1,2 +1,2 @@
1
- # see {Unicorn::OobGC}[http://unicorn.bogomips.org/Unicorn/OobGC.html]
1
+ # see {Unicorn::OobGC}[https://yhbt.net/unicorn/Unicorn/OobGC.html]
2
2
  # Unicorn::OobGC was broken in Unicorn v3.3.1 - v3.6.1 and fixed in v3.6.2
data/examples/init.sh CHANGED
@@ -1,7 +1,16 @@
1
1
  #!/bin/sh
2
2
  set -e
3
+ ### BEGIN INIT INFO
4
+ # Provides: unicorn
5
+ # Required-Start: $local_fs $network
6
+ # Required-Stop: $local_fs $network
7
+ # Default-Start: 2 3 4 5
8
+ # Default-Stop: 0 1 6
9
+ # Short-Description: Start/stop unicorn Rack app server
10
+ ### END INIT INFO
11
+
3
12
  # Example init script, this can be used with nginx, too,
4
- # since nginx and unicorn accept the same signals
13
+ # since nginx and unicorn accept the same signals.
5
14
 
6
15
  # Feel free to change any of the following variables for your app:
7
16
  TIMEOUT=${TIMEOUT-60}
@@ -9,21 +18,22 @@ APP_ROOT=/home/x/my_app/current
9
18
  PID=$APP_ROOT/tmp/pids/unicorn.pid
10
19
  CMD="/usr/bin/unicorn -D -c $APP_ROOT/config/unicorn.rb"
11
20
  INIT_CONF=$APP_ROOT/config/init.conf
21
+ UPGRADE_DELAY=${UPGRADE_DELAY-2}
12
22
  action="$1"
13
23
  set -u
14
24
 
15
25
  test -f "$INIT_CONF" && . $INIT_CONF
16
26
 
17
- old_pid="$PID.oldbin"
27
+ OLD="$PID.oldbin"
18
28
 
19
29
  cd $APP_ROOT || exit 1
20
30
 
21
31
  sig () {
22
- test -s "$PID" && kill -$1 `cat $PID`
32
+ test -s "$PID" && kill -$1 $(cat $PID)
23
33
  }
24
34
 
25
35
  oldsig () {
26
- test -s $old_pid && kill -$1 `cat $old_pid`
36
+ test -s "$OLD" && kill -$1 $(cat $OLD)
27
37
  }
28
38
 
29
39
  case $action in
@@ -45,18 +55,36 @@ restart|reload)
45
55
  $CMD
46
56
  ;;
47
57
  upgrade)
48
- if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
58
+ if oldsig 0
59
+ then
60
+ echo >&2 "Old upgraded process still running with $OLD"
61
+ exit 1
62
+ fi
63
+
64
+ cur_pid=
65
+ if test -s "$PID"
66
+ then
67
+ cur_pid=$(cat $PID)
68
+ fi
69
+
70
+ if test -n "$cur_pid" &&
71
+ kill -USR2 "$cur_pid" &&
72
+ sleep $UPGRADE_DELAY &&
73
+ new_pid=$(cat $PID) &&
74
+ test x"$new_pid" != x"$cur_pid" &&
75
+ kill -0 "$new_pid" &&
76
+ kill -QUIT "$cur_pid"
49
77
  then
50
78
  n=$TIMEOUT
51
- while test -s $old_pid && test $n -ge 0
79
+ while kill -0 "$cur_pid" 2>/dev/null && test $n -ge 0
52
80
  do
53
81
  printf '.' && sleep 1 && n=$(( $n - 1 ))
54
82
  done
55
83
  echo
56
84
 
57
- if test $n -lt 0 && test -s $old_pid
85
+ if test $n -lt 0 && kill -0 "$cur_pid" 2>/dev/null
58
86
  then
59
- echo >&2 "$old_pid still exists after $TIMEOUT seconds"
87
+ echo >&2 "$cur_pid still running after $TIMEOUT seconds"
60
88
  exit 1
61
89
  fi
62
90
  exit 0
@@ -2,7 +2,10 @@
2
2
  # /etc/logrotate.d/unicorn_app on my Debian systems
3
3
  #
4
4
  # See the logrotate(8) manpage for more information:
5
- # http://linux.die.net/man/8/logrotate
5
+ # https://linux.die.net/man/8/logrotate
6
+ #
7
+ # public logrotate-related discussion in our archives:
8
+ # https://yhbt.net/unicorn-public/?q=logrotate
6
9
 
7
10
  # Modify the following glob to match the logfiles your app writes to:
8
11
  /var/log/unicorn_app/*.log {
@@ -22,7 +25,19 @@
22
25
  # config. Unicorn supports the USR1 signal and we send it
23
26
  # as our "lastaction" action:
24
27
  lastaction
25
- # assuming your pid file is in /var/run/unicorn_app/pid
28
+ # For systemd users, assuming you use two services
29
+ # (as recommended) to allow zero-downtime upgrades.
30
+ # Only one service needs to be started, but signaling
31
+ # both here is harmless as long as they're both enabled
32
+ systemctl kill -s SIGUSR1 unicorn@1.service
33
+ systemctl kill -s SIGUSR1 unicorn@2.service
34
+
35
+ # Examples for other process management systems appreciated
36
+ # Mail us at unicorn-public@yhbt.net
37
+ # (see above for archives)
38
+
39
+ # If you use a pid file and assuming your pid file
40
+ # is in /var/run/unicorn_app/pid
26
41
  pid=/var/run/unicorn_app/pid
27
42
  test -s $pid && kill -USR1 "$(cat $pid)"
28
43
  endscript
data/examples/nginx.conf CHANGED
@@ -1,5 +1,5 @@
1
1
  # This is example contains the bare mininum to get nginx going with
2
- # Unicorn or Rainbows! servers. Generally these configuration settings
2
+ # unicorn servers. Generally these configuration settings
3
3
  # are applicable to other HTTP application servers (and not just Ruby
4
4
  # ones), so if you have one working well for proxying another app
5
5
  # server, feel free to continue using it.
@@ -44,8 +44,8 @@ http {
44
44
  # click tracking!
45
45
  access_log /path/to/nginx.access.log combined;
46
46
 
47
- # you generally want to serve static files with nginx since neither
48
- # Unicorn nor Rainbows! is optimized for it at the moment
47
+ # you generally want to serve static files with nginx since
48
+ # unicorn is not and will never be optimized for it
49
49
  sendfile on;
50
50
 
51
51
  tcp_nopush on; # off may be better for *some* Comet/long-poll stuff
@@ -56,7 +56,8 @@ http {
56
56
  # to configure it all in one place here for static files and also
57
57
  # to disable gzip for clients who don't get gzip/deflate right.
58
58
  # There are other gzip settings that may be needed used to deal with
59
- # bad clients out there, see http://wiki.nginx.org/NginxHttpGzipModule
59
+ # bad clients out there, see
60
+ # https://nginx.org/en/docs/http/ngx_http_gzip_module.html
60
61
  gzip on;
61
62
  gzip_http_version 1.0;
62
63
  gzip_proxied any;
@@ -67,10 +68,10 @@ http {
67
68
  text/javascript application/x-javascript
68
69
  application/atom+xml;
69
70
 
70
- # this can be any application server, not just Unicorn/Rainbows!
71
+ # this can be any application server, not just unicorn
71
72
  upstream app_server {
72
73
  # fail_timeout=0 means we always retry an upstream even if it failed
73
- # to return a good HTTP response (in case the Unicorn master nukes a
74
+ # to return a good HTTP response (in case the unicorn master nukes a
74
75
  # single worker for timing out).
75
76
 
76
77
  # for UNIX domain socket setups:
@@ -112,12 +113,12 @@ http {
112
113
  # try_files directive appeared in in nginx 0.7.27 and has stabilized
113
114
  # over time. Older versions of nginx (e.g. 0.6.x) requires
114
115
  # "if (!-f $request_filename)" which was less efficient:
115
- # http://bogomips.org/unicorn.git/tree/examples/nginx.conf?id=v3.3.1#n127
116
+ # https://yhbt.net/unicorn.git/tree/examples/nginx.conf?id=v3.3.1#n127
116
117
  try_files $uri/index.html $uri.html $uri @app;
117
118
 
118
119
  location @app {
119
120
  # an HTTP header important enough to have its own Wikipedia entry:
120
- # http://en.wikipedia.org/wiki/X-Forwarded-For
121
+ # https://en.wikipedia.org/wiki/X-Forwarded-For
121
122
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
122
123
 
123
124
  # enable this if you forward HTTPS traffic to unicorn,
@@ -132,12 +133,11 @@ http {
132
133
  # redirects, we set the Host: header above already.
133
134
  proxy_redirect off;
134
135
 
135
- # set "proxy_buffering off" *only* for Rainbows! when doing
136
- # Comet/long-poll/streaming. It's also safe to set if you're using
137
- # only serving fast clients with Unicorn + nginx, but not slow
138
- # clients. You normally want nginx to buffer responses to slow
139
- # clients, even with Rails 3.1 streaming because otherwise a slow
140
- # client can become a bottleneck of Unicorn.
136
+ # It's also safe to set if you're using only serving fast clients
137
+ # with unicorn + nginx, but not slow clients. You normally want
138
+ # nginx to buffer responses to slow clients, even with Rails 3.1
139
+ # streaming because otherwise a slow client can become a bottleneck
140
+ # of unicorn.
141
141
  #
142
142
  # The Rack application may also set "X-Accel-Buffering (yes|no)"
143
143
  # in the response headers do disable/enable buffering on a
@@ -1,9 +1,9 @@
1
1
  # Minimal sample configuration file for Unicorn (not Rack) when used
2
2
  # with daemonization (unicorn -D) started in your working directory.
3
3
  #
4
- # See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
4
+ # See https://yhbt.net/unicorn/Unicorn/Configurator.html for complete
5
5
  # documentation.
6
- # See also http://unicorn.bogomips.org/examples/unicorn.conf.rb for
6
+ # See also https://yhbt.net/unicorn/examples/unicorn.conf.rb for
7
7
  # a more verbose configuration using more features.
8
8
 
9
9
  listen 2007 # by default Unicorn listens on port 8080
@@ -2,10 +2,10 @@
2
2
  #
3
3
  # This configuration file documents many features of Unicorn
4
4
  # that may not be needed for some applications. See
5
- # http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
5
+ # https://yhbt.net/unicorn/examples/unicorn.conf.minimal.rb
6
6
  # for a much simpler configuration file.
7
7
  #
8
- # See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
8
+ # See https://yhbt.net/unicorn/Unicorn/Configurator.html for complete
9
9
  # documentation.
10
10
 
11
11
  # Use at least one worker per core if you're on a dedicated server,
@@ -40,11 +40,8 @@
40
40
  stderr_path "/path/to/app/shared/log/unicorn.stderr.log"
41
41
  stdout_path "/path/to/app/shared/log/unicorn.stdout.log"
42
42
 
43
- # combine Ruby 2.0.0dev or REE with "preload_app true" for memory savings
44
- # http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
43
+ # combine Ruby 2.0.0+ with "preload_app true" for memory savings
45
44
  preload_app true
46
- GC.respond_to?(:copy_on_write_friendly=) and
47
- GC.copy_on_write_friendly = true
48
45
 
49
46
  # Enable this flag to have unicorn test client connections by writing the
50
47
  # beginning of the HTTP headers before calling the application. This
@@ -0,0 +1,11 @@
1
+ # ==> /etc/systemd/system/unicorn.socket <==
2
+ [Unit]
3
+ Description = unicorn sockets
4
+
5
+ [Socket]
6
+ ListenStream = 127.0.0.1:8080
7
+ ListenStream = /tmp/path/to/.unicorn.sock
8
+ Service = unicorn@1.service
9
+
10
+ [Install]
11
+ WantedBy = sockets.target
@@ -0,0 +1,40 @@
1
+ # ==> /etc/systemd/system/unicorn@.service <==
2
+ # Since SIGUSR2 upgrades do not work under systemd, this service file
3
+ # allows starting two simultaneous services during upgrade time
4
+ # (e.g. unicorn@1 unicorn@2) with the intention that they take
5
+ # turns running in-between upgrades. This should allow upgrading
6
+ # without downtime.
7
+
8
+ [Unit]
9
+ Description = unicorn Rack application server %i
10
+ Wants = unicorn.socket
11
+ After = unicorn.socket
12
+
13
+ [Service]
14
+ # bundler users must use the "--keep-file-descriptors" switch, here:
15
+ # ExecStart = bundle exec --keep-file-descriptors unicorn -c ...
16
+ ExecStart = /usr/bin/unicorn -c /path/to/unicorn.conf.rb /path/to/config.ru
17
+
18
+ # NonBlocking MUST be true if using socket activation with unicorn.
19
+ # Otherwise, there's a small window in-between when the non-blocking
20
+ # flag is set by us and our accept4 call where systemd can momentarily
21
+ # make the socket blocking, causing us to block on accept4:
22
+ NonBlocking = true
23
+ Sockets = unicorn.socket
24
+
25
+ KillSignal = SIGQUIT
26
+ User = nobody
27
+ Group = nogroup
28
+ ExecReload = /bin/kill -HUP $MAINPID
29
+
30
+ # This is based on the Unicorn::Configurator#timeout directive,
31
+ # adding a few seconds for scheduling differences:
32
+ TimeoutStopSec = 62
33
+
34
+ # Only kill the master process, it may be harmful to signal
35
+ # workers via default "control-group" setting since some
36
+ # Ruby extensions and applications misbehave on interrupts
37
+ KillMode = process
38
+
39
+ [Install]
40
+ WantedBy = multi-user.target
@@ -58,6 +58,23 @@ static struct common_field common_http_fields[] = {
58
58
 
59
59
  #define HTTP_PREFIX "HTTP_"
60
60
  #define HTTP_PREFIX_LEN (sizeof(HTTP_PREFIX) - 1)
61
+ static ID id_uminus;
62
+
63
+ /* this dedupes under Ruby 2.5+ (December 2017) */
64
+ static VALUE str_dd_freeze(VALUE str)
65
+ {
66
+ if (STR_UMINUS_DEDUPE)
67
+ return rb_funcall(str, id_uminus, 0);
68
+
69
+ /* freeze,since it speeds up older MRI slightly */
70
+ OBJ_FREEZE(str);
71
+ return str;
72
+ }
73
+
74
+ static VALUE str_new_dd_freeze(const char *ptr, long len)
75
+ {
76
+ return str_dd_freeze(rb_str_new(ptr, len));
77
+ }
61
78
 
62
79
  /* this function is not performance-critical, called only at load time */
63
80
  static void init_common_fields(void)
@@ -65,19 +82,20 @@ static void init_common_fields(void)
65
82
  int i;
66
83
  struct common_field *cf = common_http_fields;
67
84
  char tmp[64];
85
+
86
+ id_uminus = rb_intern("-@");
68
87
  memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN);
69
88
 
70
89
  for(i = ARRAY_SIZE(common_http_fields); --i >= 0; cf++) {
71
90
  /* Rack doesn't like certain headers prefixed with "HTTP_" */
72
91
  if (!strcmp("CONTENT_LENGTH", cf->name) ||
73
92
  !strcmp("CONTENT_TYPE", cf->name)) {
74
- cf->value = rb_str_new(cf->name, cf->len);
93
+ cf->value = str_new_dd_freeze(cf->name, cf->len);
75
94
  } else {
76
95
  memcpy(tmp + HTTP_PREFIX_LEN, cf->name, cf->len + 1);
77
- cf->value = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len);
96
+ cf->value = str_new_dd_freeze(tmp, HTTP_PREFIX_LEN + cf->len);
78
97
  }
79
- cf->value = rb_obj_freeze(cf->value);
80
- rb_global_variable(&cf->value);
98
+ rb_gc_register_mark_object(cf->value);
81
99
  }
82
100
  }
83
101
 
@@ -105,7 +123,7 @@ static VALUE uncommon_field(const char *field, size_t flen)
105
123
  memcpy(RSTRING_PTR(f) + HTTP_PREFIX_LEN, field, flen);
106
124
  assert(*(RSTRING_PTR(f) + RSTRING_LEN(f)) == '\0' &&
107
125
  "string didn't end with \\0"); /* paranoia */
108
- return rb_obj_freeze(f);
126
+ return HASH_ASET_DEDUPE ? f : str_dd_freeze(f);
109
127
  }
110
128
 
111
129
  #endif /* common_field_optimization_h */
@@ -1,26 +1,6 @@
1
1
  #ifndef ext_help_h
2
2
  #define ext_help_h
3
3
 
4
- #ifndef RSTRING_PTR
5
- #define RSTRING_PTR(s) (RSTRING(s)->ptr)
6
- #endif /* !defined(RSTRING_PTR) */
7
- #ifndef RSTRING_LEN
8
- #define RSTRING_LEN(s) (RSTRING(s)->len)
9
- #endif /* !defined(RSTRING_LEN) */
10
-
11
- #ifndef HAVE_RB_STR_SET_LEN
12
- # ifdef RUBINIUS
13
- # error we should never get here with current Rubinius (1.x)
14
- # endif
15
- /* this is taken from Ruby 1.8.7, 1.8.6 may not have it */
16
- static void rb_18_str_set_len(VALUE str, long len)
17
- {
18
- RSTRING(str)->len = len;
19
- RSTRING(str)->ptr[len] = '\0';
20
- }
21
- # define rb_str_set_len(str,len) rb_18_str_set_len(str,len)
22
- #endif /* !defined(HAVE_RB_STR_SET_LEN) */
23
-
24
4
  /* not all Ruby implementations support frozen objects (Rubinius does not) */
25
5
  #if defined(OBJ_FROZEN)
26
6
  # define assert_frozen(f) assert(OBJ_FROZEN(f) && "unfrozen object")
@@ -1,10 +1,46 @@
1
1
  # -*- encoding: binary -*-
2
2
  require 'mkmf'
3
3
 
4
+ unless RUBY_VERSION < '3.1'
5
+ warn "Unicorn was only tested against MRI up to 3.0.\n" \
6
+ "It might not properly work with #{RUBY_VERSION}"
7
+ end
8
+
4
9
  have_macro("SIZEOF_OFF_T", "ruby.h") or check_sizeof("off_t", "sys/types.h")
5
10
  have_macro("SIZEOF_SIZE_T", "ruby.h") or check_sizeof("size_t", "sys/types.h")
6
11
  have_macro("SIZEOF_LONG", "ruby.h") or check_sizeof("long", "sys/types.h")
7
- have_func("rb_str_set_len", "ruby.h")
12
+ have_func("rb_str_set_len", "ruby.h") or abort 'Ruby 1.9.3+ required'
13
+ have_func("rb_hash_clear", "ruby.h") # Ruby 2.0+
8
14
  have_func("gmtime_r", "time.h")
9
15
 
16
+ message('checking if String#-@ (str_uminus) dedupes... ')
17
+ begin
18
+ a = -(%w(t e s t).join)
19
+ b = -(%w(t e s t).join)
20
+ if a.equal?(b)
21
+ $CPPFLAGS += ' -DSTR_UMINUS_DEDUPE=1 '
22
+ message("yes\n")
23
+ else
24
+ $CPPFLAGS += ' -DSTR_UMINUS_DEDUPE=0 '
25
+ message("no, needs Ruby 2.5+\n")
26
+ end
27
+ rescue NoMethodError
28
+ $CPPFLAGS += ' -DSTR_UMINUS_DEDUPE=0 '
29
+ message("no, String#-@ not available\n")
30
+ end
31
+
32
+ message('checking if Hash#[]= (rb_hash_aset) dedupes... ')
33
+ h = {}
34
+ x = {}
35
+ r = rand.to_s
36
+ h[%W(#{r}).join('')] = :foo
37
+ x[%W(#{r}).join('')] = :foo
38
+ if x.keys[0].equal?(h.keys[0])
39
+ $CPPFLAGS += ' -DHASH_ASET_DEDUPE=1 '
40
+ message("yes\n")
41
+ else
42
+ $CPPFLAGS += ' -DHASH_ASET_DEDUPE=0 '
43
+ message("no, needs Ruby 2.6+\n")
44
+ end
45
+
10
46
  create_makefile("unicorn_http")