jubilee 1.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/.travis.yml +5 -0
  4. data/CHANGELOG +32 -0
  5. data/Gemfile +35 -0
  6. data/Gemfile.lock +244 -0
  7. data/Guardfile +24 -0
  8. data/KNOWN_ISSUES +6 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +147 -0
  11. data/ROADMAP +5 -0
  12. data/Rakefile +98 -0
  13. data/bin/jubilee +6 -0
  14. data/bin/jubilee_d +13 -0
  15. data/examples/chatapp/Gemfile +5 -0
  16. data/examples/chatapp/Gemfile.lock +27 -0
  17. data/examples/chatapp/README.md +17 -0
  18. data/examples/chatapp/app.rb +57 -0
  19. data/examples/chatapp/config.ru +3 -0
  20. data/examples/chatapp/public/assets/javascripts/application.js +67 -0
  21. data/examples/chatapp/public/assets/javascripts/jquery.js +5 -0
  22. data/examples/chatapp/public/assets/javascripts/sockjs-0.3.4.min.js +27 -0
  23. data/examples/chatapp/public/assets/javascripts/vertxbus.js +216 -0
  24. data/examples/chatapp/public/assets/stylesheets/application.css +29 -0
  25. data/examples/client/sockjs-0.3.4.min.js +27 -0
  26. data/examples/client/vertxbus.js +216 -0
  27. data/examples/jubilee.conf.rb +12 -0
  28. data/examples/jubilee/keystore.jks +0 -0
  29. data/examples/jubilee/server-keystore.jks +0 -0
  30. data/jars/hazelcast-2.6.3.jar +0 -0
  31. data/jars/jackson-annotations-2.2.2.jar +0 -0
  32. data/jars/jackson-core-2.2.2.jar +0 -0
  33. data/jars/jackson-databind-2.2.2.jar +0 -0
  34. data/jars/netty-all-4.0.13.Final.jar +0 -0
  35. data/jars/vertx-core-2.1M3-SNAPSHOT.jar +0 -0
  36. data/jars/vertx-hazelcast-2.1M3-SNAPSHOT.jar +0 -0
  37. data/java/src/jubilee/JubileeService.java +20 -0
  38. data/java/src/org/jruby/jubilee/Const.java +32 -0
  39. data/java/src/org/jruby/jubilee/RackApplication.java +103 -0
  40. data/java/src/org/jruby/jubilee/RackEnvironment.java +150 -0
  41. data/java/src/org/jruby/jubilee/RackEnvironmentHash.java +449 -0
  42. data/java/src/org/jruby/jubilee/RackInput.java +62 -0
  43. data/java/src/org/jruby/jubilee/RackResponse.java +11 -0
  44. data/java/src/org/jruby/jubilee/RubyHttpServerResponse.java +88 -0
  45. data/java/src/org/jruby/jubilee/RubyServer.java +171 -0
  46. data/java/src/org/jruby/jubilee/deploy/Starter.java +26 -0
  47. data/java/src/org/jruby/jubilee/impl/RubyIORackInput.java +201 -0
  48. data/java/src/org/jruby/jubilee/impl/RubyNullIO.java +107 -0
  49. data/java/src/org/jruby/jubilee/utils/RubyHelper.java +37 -0
  50. data/java/src/org/jruby/jubilee/vertx/JubileeVertx.java +38 -0
  51. data/jubilee.gemspec +201 -0
  52. data/lib/jubilee.rb +17 -0
  53. data/lib/jubilee/application.rb +13 -0
  54. data/lib/jubilee/cli.rb +127 -0
  55. data/lib/jubilee/configuration.rb +177 -0
  56. data/lib/jubilee/const.rb +40 -0
  57. data/lib/jubilee/jubilee.jar +0 -0
  58. data/lib/jubilee/response.rb +69 -0
  59. data/lib/jubilee/server.rb +12 -0
  60. data/lib/jubilee/version.rb +10 -0
  61. data/lib/rack/chunked.rb +38 -0
  62. data/lib/rack/handler/jubilee.rb +44 -0
  63. data/lib/vertx.rb +26 -0
  64. data/lib/vertx/README.md +7 -0
  65. data/lib/vertx/buffer.rb +251 -0
  66. data/lib/vertx/event_bus.rb +206 -0
  67. data/lib/vertx/shared_data.rb +214 -0
  68. data/spec/apps/rack/basic/config.ru +50 -0
  69. data/spec/apps/rails4/basic/.gitignore +16 -0
  70. data/spec/apps/rails4/basic/Gemfile +41 -0
  71. data/spec/apps/rails4/basic/Gemfile.lock +127 -0
  72. data/spec/apps/rails4/basic/README.rdoc +28 -0
  73. data/spec/apps/rails4/basic/Rakefile +6 -0
  74. data/spec/apps/rails4/basic/app/assets/images/.keep +0 -0
  75. data/spec/apps/rails4/basic/app/assets/images/rails.png +0 -0
  76. data/spec/apps/rails4/basic/app/assets/javascripts/application.js +12 -0
  77. data/spec/apps/rails4/basic/app/assets/stylesheets/application.css +13 -0
  78. data/spec/apps/rails4/basic/app/controllers/application_controller.rb +5 -0
  79. data/spec/apps/rails4/basic/app/controllers/concerns/.keep +0 -0
  80. data/spec/apps/rails4/basic/app/controllers/reloader_controller.rb +11 -0
  81. data/spec/apps/rails4/basic/app/controllers/reloader_controller.rb.erb +11 -0
  82. data/spec/apps/rails4/basic/app/controllers/root_controller.rb +14 -0
  83. data/spec/apps/rails4/basic/app/helpers/application_helper.rb +2 -0
  84. data/spec/apps/rails4/basic/app/mailers/.keep +0 -0
  85. data/spec/apps/rails4/basic/app/models/.keep +0 -0
  86. data/spec/apps/rails4/basic/app/models/concerns/.keep +0 -0
  87. data/spec/apps/rails4/basic/app/views/layouts/application.html.erb +14 -0
  88. data/spec/apps/rails4/basic/app/views/reloader/index.html.erb +1 -0
  89. data/spec/apps/rails4/basic/app/views/root/index.html.erb +8 -0
  90. data/spec/apps/rails4/basic/app/views/root/streaming.html.erb +6 -0
  91. data/spec/apps/rails4/basic/bin/bundle +3 -0
  92. data/spec/apps/rails4/basic/bin/rails +4 -0
  93. data/spec/apps/rails4/basic/bin/rake +4 -0
  94. data/spec/apps/rails4/basic/config.ru +4 -0
  95. data/spec/apps/rails4/basic/config/application.rb +23 -0
  96. data/spec/apps/rails4/basic/config/boot.rb +4 -0
  97. data/spec/apps/rails4/basic/config/database.yml +20 -0
  98. data/spec/apps/rails4/basic/config/environment.rb +5 -0
  99. data/spec/apps/rails4/basic/config/environments/development.rb +29 -0
  100. data/spec/apps/rails4/basic/config/environments/production.rb +80 -0
  101. data/spec/apps/rails4/basic/config/environments/test.rb +36 -0
  102. data/spec/apps/rails4/basic/config/initializers/backtrace_silencers.rb +7 -0
  103. data/spec/apps/rails4/basic/config/initializers/filter_parameter_logging.rb +4 -0
  104. data/spec/apps/rails4/basic/config/initializers/inflections.rb +16 -0
  105. data/spec/apps/rails4/basic/config/initializers/mime_types.rb +5 -0
  106. data/spec/apps/rails4/basic/config/initializers/secret_token.rb +12 -0
  107. data/spec/apps/rails4/basic/config/initializers/session_store.rb +2 -0
  108. data/spec/apps/rails4/basic/config/initializers/wrap_parameters.rb +14 -0
  109. data/spec/apps/rails4/basic/config/locales/en.yml +23 -0
  110. data/spec/apps/rails4/basic/config/routes.rb +5 -0
  111. data/spec/apps/rails4/basic/db/seeds.rb +7 -0
  112. data/spec/apps/rails4/basic/lib/assets/.keep +0 -0
  113. data/spec/apps/rails4/basic/lib/tasks/.keep +0 -0
  114. data/spec/apps/rails4/basic/public/404.html +58 -0
  115. data/spec/apps/rails4/basic/public/422.html +58 -0
  116. data/spec/apps/rails4/basic/public/500.html +57 -0
  117. data/spec/apps/rails4/basic/public/favicon.ico +0 -0
  118. data/spec/apps/rails4/basic/public/robots.txt +5 -0
  119. data/spec/apps/rails4/basic/public/some_page.html +7 -0
  120. data/spec/apps/rails4/basic/test/controllers/.keep +0 -0
  121. data/spec/apps/rails4/basic/test/fixtures/.keep +0 -0
  122. data/spec/apps/rails4/basic/test/helpers/.keep +0 -0
  123. data/spec/apps/rails4/basic/test/integration/.keep +0 -0
  124. data/spec/apps/rails4/basic/test/mailers/.keep +0 -0
  125. data/spec/apps/rails4/basic/test/models/.keep +0 -0
  126. data/spec/apps/rails4/basic/test/test_helper.rb +15 -0
  127. data/spec/apps/rails4/basic/vendor/assets/javascripts/.keep +0 -0
  128. data/spec/apps/rails4/basic/vendor/assets/stylesheets/.keep +0 -0
  129. data/spec/apps/sinatra/basic/Gemfile +4 -0
  130. data/spec/apps/sinatra/basic/Gemfile.lock +20 -0
  131. data/spec/apps/sinatra/basic/basic.rb +27 -0
  132. data/spec/apps/sinatra/basic/config.ru +7 -0
  133. data/spec/apps/sinatra/basic/public/some_page.html +7 -0
  134. data/spec/apps/sinatra/basic/views/index.erb +4 -0
  135. data/spec/apps/sinatra/basic/views/posted.haml +2 -0
  136. data/spec/apps/sinatra/basic/views/poster.haml +4 -0
  137. data/spec/apps/sinatra/basic/views/request_mapping.haml +4 -0
  138. data/spec/integration/basic_rack_spec.rb +89 -0
  139. data/spec/integration/basic_rails4_spec.rb +64 -0
  140. data/spec/integration/basic_sinatra_spec.rb +80 -0
  141. data/spec/spec_helper.rb +13 -0
  142. data/test/.ruby-version +1 -0
  143. data/test/config/app.rb +5 -0
  144. data/test/jubilee/test_cli.rb +11 -0
  145. data/test/jubilee/test_configuration.rb +31 -0
  146. data/test/jubilee/test_rack_server.rb +137 -0
  147. data/test/jubilee/test_response.rb +272 -0
  148. data/test/jubilee/test_server.rb +72 -0
  149. data/test/jubilee/test_upload.rb +301 -0
  150. data/test/sinatra_app/app.rb +31 -0
  151. data/test/sinatra_app/config.ru +6 -0
  152. data/test/sinatra_app/public/test.html +10 -0
  153. data/test/sinatra_app/unicorn.conf.rb +29 -0
  154. data/test/test_helper.rb +93 -0
  155. metadata +242 -0
@@ -0,0 +1,150 @@
1
+ package org.jruby.jubilee;
2
+
3
+ import io.netty.handler.codec.http.HttpHeaders;
4
+ import org.jruby.Ruby;
5
+ import org.jruby.RubyArray;
6
+ import org.jruby.RubyFixnum;
7
+ import org.jruby.RubyHash;
8
+ import org.jruby.RubyIO;
9
+ import org.jruby.RubyString;
10
+
11
+ import org.jruby.jubilee.utils.RubyHelper;
12
+ import org.vertx.java.core.MultiMap;
13
+ import org.vertx.java.core.http.HttpServerRequest;
14
+ import org.vertx.java.core.http.HttpVersion;
15
+
16
+ import java.io.IOException;
17
+ import java.net.InetSocketAddress;
18
+ import java.util.HashMap;
19
+ import java.util.Map;
20
+
21
+ public class RackEnvironment {
22
+
23
+ // When adding a key to the enum be sure to add its RubyString equivalent
24
+ // to populateRackKeyMap below
25
+ static enum RACK_KEY {
26
+ RACK_INPUT, RACK_ERRORS, REQUEST_METHOD, SCRIPT_NAME,
27
+ PATH_INFO, QUERY_STRING, SERVER_NAME, SERVER_PORT,
28
+ CONTENT_TYPE, REQUEST_URI, REMOTE_ADDR, URL_SCHEME,
29
+ VERSION, MULTITHREAD, MULTIPROCESS, RUN_ONCE, CONTENT_LENGTH,
30
+ HTTPS, HTTP_VERSION
31
+ }
32
+ static final int NUM_RACK_KEYS = RACK_KEY.values().length;
33
+
34
+ public RackEnvironment(final Ruby runtime) throws IOException {
35
+ this.runtime = runtime;
36
+ rackVersion = RubyArray.newArray(runtime, RubyFixnum.one(runtime), RubyFixnum.four(runtime));
37
+ errors = new RubyIO(runtime, runtime.getErr());
38
+ errors.setAutoclose(false);
39
+
40
+ populateRackKeyMap();
41
+ }
42
+
43
+ private void populateRackKeyMap() {
44
+ putRack("rack.input", RACK_KEY.RACK_INPUT);
45
+ putRack("rack.errors", RACK_KEY.RACK_ERRORS);
46
+ putRack("REQUEST_METHOD", RACK_KEY.REQUEST_METHOD);
47
+ putRack("SCRIPT_NAME", RACK_KEY.SCRIPT_NAME);
48
+ putRack("PATH_INFO", RACK_KEY.PATH_INFO);
49
+ putRack("QUERY_STRING", RACK_KEY.QUERY_STRING);
50
+ putRack("SERVER_NAME", RACK_KEY.SERVER_NAME);
51
+ putRack("SERVER_PORT", RACK_KEY.SERVER_PORT);
52
+ putRack("HTTP_VERSION", RACK_KEY.HTTP_VERSION);
53
+ putRack("CONTENT_TYPE", RACK_KEY.CONTENT_TYPE);
54
+ putRack("REQUEST_URI", RACK_KEY.REQUEST_URI);
55
+ putRack("REMOTE_ADDR", RACK_KEY.REMOTE_ADDR);
56
+ putRack("rack.url_scheme", RACK_KEY.URL_SCHEME);
57
+ putRack("rack.version", RACK_KEY.VERSION);
58
+ putRack("rack.multithread", RACK_KEY.MULTITHREAD);
59
+ putRack("rack.multiprocess", RACK_KEY.MULTIPROCESS);
60
+ putRack("rack.run_once", RACK_KEY.RUN_ONCE);
61
+ putRack("CONTENT_LENGTH", RACK_KEY.CONTENT_LENGTH);
62
+ putRack("HTTPS", RACK_KEY.HTTPS);
63
+ }
64
+
65
+ private void putRack(String key, RACK_KEY value) {
66
+ rackKeyMap.put(RubyHelper.toUsAsciiRubyString(runtime, key), value);
67
+ }
68
+
69
+ public RubyHash getEnv(final HttpServerRequest request,
70
+ final RackInput input,
71
+ final boolean isSSL) throws IOException {
72
+ MultiMap headers = request.headers();
73
+ final RackEnvironmentHash env = new RackEnvironmentHash(runtime, headers, rackKeyMap);
74
+ env.lazyPut(RACK_KEY.RACK_INPUT, input, false);
75
+ env.lazyPut(RACK_KEY.RACK_ERRORS, errors, false);
76
+
77
+ String pathInfo = request.path();
78
+
79
+ String scriptName = "";
80
+ String[] hostInfo = getHostInfo(request.headers().get(Const.HOST));
81
+
82
+ env.lazyPut(RACK_KEY.REQUEST_METHOD, request.method(), true);
83
+ env.lazyPut(RACK_KEY.SCRIPT_NAME, scriptName, false);
84
+ env.lazyPut(RACK_KEY.PATH_INFO, pathInfo, false);
85
+ env.lazyPut(RACK_KEY.QUERY_STRING, orEmpty(request.query()), false);
86
+ env.lazyPut(RACK_KEY.SERVER_NAME, hostInfo[0], false);
87
+ env.lazyPut(RACK_KEY.SERVER_PORT, hostInfo[1], true);
88
+ env.lazyPut(RACK_KEY.HTTP_VERSION,
89
+ request.version() == HttpVersion.HTTP_1_1 ? Const.HTTP_11 : Const.HTTP_10, true);
90
+ env.lazyPut(RACK_KEY.CONTENT_TYPE, headers.get(HttpHeaders.Names.CONTENT_TYPE), true);
91
+ env.lazyPut(RACK_KEY.REQUEST_URI, request.uri(), false);
92
+ env.lazyPut(RACK_KEY.REMOTE_ADDR, getRemoteAddr(request), true);
93
+ env.lazyPut(RACK_KEY.URL_SCHEME, isSSL? Const.HTTPS : Const.HTTP, true);
94
+ env.lazyPut(RACK_KEY.VERSION, rackVersion, false);
95
+ env.lazyPut(RACK_KEY.MULTITHREAD, runtime.getTrue(), false);
96
+ env.lazyPut(RACK_KEY.MULTIPROCESS, runtime.getFalse(), false);
97
+ env.lazyPut(RACK_KEY.RUN_ONCE, runtime.getFalse(), false);
98
+
99
+ final int contentLength = getContentLength(headers);
100
+ if (contentLength >= 0) {
101
+ env.lazyPut(RACK_KEY.CONTENT_LENGTH, contentLength + "", true);
102
+ }
103
+
104
+ if (isSSL) {
105
+ env.lazyPut(RACK_KEY.HTTPS, "on", true);
106
+ }
107
+
108
+ return env;
109
+ }
110
+
111
+ public String[] getHostInfo(String host) {
112
+ String[] hostInfo;
113
+ if (host != null) {
114
+ int colon = host.indexOf(":");
115
+ if (colon > 0)
116
+ hostInfo = new String[]{host.substring(0, colon), host.substring(colon + 1)};
117
+ else
118
+ hostInfo = new String[]{host, Const.PORT_80};
119
+
120
+ } else {
121
+ hostInfo = new String[]{Const.LOCALHOST, Const.PORT_80};
122
+ }
123
+ return hostInfo;
124
+ }
125
+
126
+ private static String getRemoteAddr(final HttpServerRequest request) {
127
+ InetSocketAddress sourceAddress = request.remoteAddress();
128
+ if(sourceAddress == null) {
129
+ return "";
130
+ }
131
+ return sourceAddress.getHostString();
132
+ }
133
+
134
+ private static int getContentLength(final MultiMap headers) {
135
+ final String contentLengthStr = headers.get(HttpHeaders.Names.CONTENT_LENGTH);
136
+ if (contentLengthStr == null || contentLengthStr.isEmpty()) {
137
+ return -1;
138
+ }
139
+ return Integer.parseInt(contentLengthStr);
140
+ }
141
+
142
+ private String orEmpty(String val) {
143
+ return val == null ? "" : val;
144
+ }
145
+
146
+ private final Ruby runtime;
147
+ private final RubyArray rackVersion;
148
+ private final RubyIO errors;
149
+ private final Map<RubyString, RACK_KEY> rackKeyMap = new HashMap<>();
150
+ }
@@ -0,0 +1,449 @@
1
+ package org.jruby.jubilee;
2
+
3
+ import io.netty.handler.codec.http.HttpHeaders;
4
+ import org.jruby.Ruby;
5
+ import org.jruby.RubyArray;
6
+ import org.jruby.RubyBoolean;
7
+ import org.jruby.RubyFixnum;
8
+ import org.jruby.RubyHash;
9
+ import org.jruby.RubyString;
10
+ import org.jruby.runtime.Block;
11
+ import org.jruby.runtime.ThreadContext;
12
+ import org.jruby.runtime.builtin.IRubyObject;
13
+ import org.jruby.jubilee.utils.RubyHelper;
14
+ import org.vertx.java.core.MultiMap;
15
+
16
+ import java.util.HashMap;
17
+ import java.util.List;
18
+ import java.util.Map;
19
+
20
+ public class RackEnvironmentHash extends RubyHash {
21
+
22
+ public RackEnvironmentHash(final Ruby runtime, final MultiMap headers,
23
+ final Map<RubyString, RackEnvironment.RACK_KEY> rackKeyMap) {
24
+ super(runtime);
25
+ this.headers = headers;
26
+ this.rackKeyMap = rackKeyMap;
27
+ this.headerKeyMap = new HashMap<>();
28
+ }
29
+
30
+ public void lazyPut(RackEnvironment.RACK_KEY rackKey, final Object value, boolean usAscii) {
31
+ rackValues[rackKey.ordinal()] = value;
32
+ usAsciiValues[rackKey.ordinal()] = usAscii;
33
+ }
34
+
35
+ // synchronized probably isn't needed here since we create a new RackEnvironment
36
+ // per request, but we can't guarantee users aren't spawning a new thread and
37
+ // passing the env to that new thread
38
+ private synchronized void fillKey(final IRubyObject rubyKey) {
39
+ if (!filledEntireHash) {
40
+ if (rubyKey instanceof RubyString && !containsKey(rubyKey)) {
41
+ if (! filledHeaderKeyMap) populateHeaderKeyMap();
42
+ byte[] keyBytes = ((RubyString) rubyKey).getBytes();
43
+ if (keyBytes.length > 5 && keyBytes[0] == 'H'
44
+ && keyBytes[1] == 'T' && keyBytes[2] == 'T'
45
+ && keyBytes[3] == 'P' && keyBytes[4] == '_') {
46
+
47
+ fillHeaderKey((RubyString) rubyKey);
48
+ } else {
49
+ fillRackKey((RubyString) rubyKey);
50
+ }
51
+ }
52
+ }
53
+ }
54
+ private synchronized void fillEntireHash() {
55
+ if (!filledEntireHash) {
56
+ for (RubyString key : rackKeyMap.keySet()) {
57
+ fillRackKey(key);
58
+ }
59
+
60
+ for (String headerKey : headers.names()) {
61
+ RubyString rubyKey = RubyHelper.toUsAsciiRubyString(getRuntime(), rackHeaderNameToBytes(headerKey));
62
+ putHeaderKey(rubyKey, headerKey);
63
+ fillHeaderKey(rubyKey, headerKey);
64
+ }
65
+ filledEntireHash = true;
66
+ }
67
+ }
68
+ private synchronized void fillRackKey(final RubyString key) {
69
+ RackEnvironment.RACK_KEY rackKey = rackKeyMap.get(key);
70
+ if (rackKey != null) {
71
+ Object value = rackValues[rackKey.ordinal()];
72
+ if (value != null) {
73
+ if (value instanceof String) {
74
+ boolean usAscii = usAsciiValues[rackKey.ordinal()];
75
+ RubyString rubyValue = usAscii ? RubyHelper.toUsAsciiRubyString(getRuntime(), (String) value) :
76
+ RubyHelper.toUnicodeRubyString(getRuntime(), (String) value);
77
+ put(key, rubyValue);
78
+ } else {
79
+ put(key, value);
80
+ }
81
+ rackValues[rackKey.ordinal()] = null;
82
+ }
83
+ }
84
+ }
85
+
86
+ private synchronized void populateHeaderKeyMap() {
87
+ for (String key : headers.names()) {
88
+ byte[] rubyKeyBytes = rackHeaderNameToBytes(key);
89
+ RubyString rubyKey = RubyHelper.toUsAsciiRubyString(getRuntime(), rubyKeyBytes);
90
+ putHeaderKey(rubyKey, key);
91
+ }
92
+ this.filledHeaderKeyMap = true;
93
+ }
94
+
95
+ private void putHeaderKey(RubyString rubyKey, String key) {
96
+ this.headerKeyMap.put(rubyKey, key);
97
+ }
98
+ private synchronized void fillHeaderKey(final RubyString rubyKey) {
99
+ String headerKey = this.headerKeyMap.get(rubyKey);
100
+ if (headerKey != null) fillHeaderKey(rubyKey, headerKey);
101
+ }
102
+ private synchronized void fillHeaderKey(final RubyString rubyKey, String key) {
103
+ // RACK spec says not to create HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH headers
104
+ if (!key.equals(HttpHeaders.Names.CONTENT_TYPE) && !key.equals(HttpHeaders.Names.CONTENT_LENGTH)) {
105
+ List<String> headerValues = headers.getAll(key);
106
+ if (!headerValues.isEmpty()) {
107
+ String headerValue = headerValues.get(0);
108
+ int valueIndex = 1;
109
+ while (valueIndex < headerValues.size()) {
110
+ headerValue += "\n" + headerValues.get(valueIndex++);
111
+ }
112
+ put(rubyKey, RubyHelper.toUnicodeRubyString(getRuntime(), headerValue));
113
+ }
114
+ }
115
+ }
116
+
117
+ private static byte[] rackHeaderNameToBytes(final String headerName) {
118
+ // This is a more performant implemention of:
119
+ // "HTTP_" + headerName.toUpperCase().replace('-', '_');
120
+ byte[] envNameBytes = new byte[headerName.length() + 5];
121
+ envNameBytes[0] = 'H';
122
+ envNameBytes[1] = 'T';
123
+ envNameBytes[2] = 'T';
124
+ envNameBytes[3] = 'P';
125
+ envNameBytes[4] = '_';
126
+ for (int i = 5; i < envNameBytes.length; i++) {
127
+ envNameBytes[i] = (byte) rackHeaderize(headerName.charAt(i - 5));
128
+ }
129
+ return envNameBytes;
130
+ }
131
+
132
+ private static char rackHeaderize(char c) {
133
+ if (c == '-') {
134
+ c = '_';
135
+ }
136
+ return toUpperCase(c);
137
+ }
138
+
139
+ private static char toUpperCase(char c) {
140
+ if (c >= 'a' && c <= 'z') {
141
+ c -= 32;
142
+ }
143
+ return c;
144
+ }
145
+
146
+ private final Object[] rackValues = new Object[RackEnvironment.NUM_RACK_KEYS];
147
+ private final boolean[] usAsciiValues = new boolean[RackEnvironment.NUM_RACK_KEYS];
148
+ private final MultiMap headers;
149
+ private final Map<RubyString, RackEnvironment.RACK_KEY> rackKeyMap;
150
+ private final Map<RubyString, String> headerKeyMap;
151
+ private boolean filledEntireHash = false;
152
+ private boolean filledHeaderKeyMap = false;
153
+
154
+
155
+
156
+ //
157
+ // Overridden RubyHash methods that operate on individual keys
158
+ //
159
+ @Override
160
+ public IRubyObject op_aref(ThreadContext context, IRubyObject key) {
161
+ fillKey(key);
162
+ return super.op_aref(context, key);
163
+ }
164
+ @Override
165
+ public IRubyObject fetch(ThreadContext context, IRubyObject key, Block block) {
166
+ fillKey(key);
167
+ return super.fetch(context, key, block);
168
+ }
169
+ @Override
170
+ public IRubyObject fetch(ThreadContext context, IRubyObject key, IRubyObject _default, Block block) {
171
+ fillKey(key);
172
+ return super.fetch(context, key ,_default, block);
173
+ }
174
+ @Override
175
+ public RubyBoolean has_key_p(IRubyObject key) {
176
+ fillKey(key);
177
+ return super.has_key_p(key);
178
+ }
179
+ @Override
180
+ public IRubyObject op_aset(ThreadContext context, IRubyObject key, IRubyObject value) {
181
+ fillKey(key);
182
+ return super.op_aset(context, key, value);
183
+ }
184
+ @Override
185
+ public IRubyObject delete(ThreadContext context, IRubyObject key, Block block) {
186
+ fillKey(key);
187
+ return super.delete(context, key, block);
188
+ }
189
+
190
+ //
191
+ // Overridden RubyHash methods that don't operate on individual keys so we
192
+ // fill the entire hash
193
+ //
194
+ @Override
195
+ public IRubyObject inspect(ThreadContext context) {
196
+ fillEntireHash();
197
+ return super.inspect(context);
198
+ }
199
+ @Override
200
+ public IRubyObject inspect19(ThreadContext context) {
201
+ fillEntireHash();
202
+ return super.inspect19(context);
203
+ }
204
+ @Override
205
+ public RubyFixnum rb_size() {
206
+ fillEntireHash();
207
+ return super.rb_size();
208
+ }
209
+ @Override
210
+ public RubyBoolean empty_p() {
211
+ fillEntireHash();
212
+ return super.empty_p();
213
+ }
214
+ @Override
215
+ public RubyArray to_a() {
216
+ fillEntireHash();
217
+ return super.to_a();
218
+ }
219
+ @Override
220
+ public IRubyObject to_s(ThreadContext context) {
221
+ fillEntireHash();
222
+ return super.to_s(context);
223
+ }
224
+ @Override
225
+ public IRubyObject to_s19(ThreadContext context) {
226
+ fillEntireHash();
227
+ return super.to_s19(context);
228
+ }
229
+ @Override
230
+ public RubyHash rehash() {
231
+ fillEntireHash();
232
+ return super.rehash();
233
+ }
234
+ @Override
235
+ public IRubyObject op_equal(final ThreadContext context, IRubyObject other) {
236
+ fillEntireHash();
237
+ return super.op_equal(context, other);
238
+ }
239
+ @Override
240
+ public IRubyObject op_eql19(final ThreadContext context, IRubyObject other) {
241
+ fillEntireHash();
242
+ return super.op_eql19(context, other);
243
+ }
244
+ @Override
245
+ public RubyFixnum hash() {
246
+ fillEntireHash();
247
+ return super.hash();
248
+ }
249
+ @Override
250
+ public RubyFixnum hash19() {
251
+ fillEntireHash();
252
+ return super.hash19();
253
+ }
254
+ @Override
255
+ public IRubyObject fetch(ThreadContext context, IRubyObject[] args, Block block) {
256
+ fillEntireHash();
257
+ return super.fetch(context, args, block);
258
+ }
259
+ @Override
260
+ public RubyBoolean has_value_p(ThreadContext context, IRubyObject expected) {
261
+ fillEntireHash();
262
+ return super.has_value_p(context, expected);
263
+ }
264
+ @Override
265
+ public IRubyObject each(final ThreadContext context, final Block block) {
266
+ fillEntireHash();
267
+ return super.each(context, block);
268
+ }
269
+ @Override
270
+ public IRubyObject each19(final ThreadContext context, final Block block) {
271
+ fillEntireHash();
272
+ return super.each19(context, block);
273
+ }
274
+ @Override
275
+ public IRubyObject each_value(final ThreadContext context, final Block block) {
276
+ fillEntireHash();
277
+ return super.each_value(context, block);
278
+ }
279
+ @Override
280
+ public IRubyObject each_key(final ThreadContext context, final Block block) {
281
+ fillEntireHash();
282
+ return super.each_key(context, block);
283
+ }
284
+ @Override
285
+ public IRubyObject select_bang(final ThreadContext context, final Block block) {
286
+ fillEntireHash();
287
+ return super.select_bang(context, block);
288
+ }
289
+ @Override
290
+ public IRubyObject keep_if(final ThreadContext context, final Block block) {
291
+ fillEntireHash();
292
+ return super.keep_if(context, block);
293
+ }
294
+ @Override
295
+ public IRubyObject sort(ThreadContext context, Block block) {
296
+ fillEntireHash();
297
+ return super.sort(context, block);
298
+ }
299
+ @Override
300
+ public IRubyObject index(ThreadContext context, IRubyObject expected) {
301
+ fillEntireHash();
302
+ return super.index(context, expected);
303
+ }
304
+ @Override
305
+ public IRubyObject index19(ThreadContext context, IRubyObject expected) {
306
+ fillEntireHash();
307
+ return super.index19(context, expected);
308
+ }
309
+ @Override
310
+ public IRubyObject key(ThreadContext context, IRubyObject expected) {
311
+ fillEntireHash();
312
+ return super.key(context, expected);
313
+ }
314
+ @Override
315
+ public RubyArray indices(ThreadContext context, IRubyObject[] indices) {
316
+ fillEntireHash();
317
+ return super.indices(context, indices);
318
+ }
319
+ @Override
320
+ public RubyArray keys() {
321
+ fillEntireHash();
322
+ return super.keys();
323
+ }
324
+ @Override
325
+ public RubyArray rb_values() {
326
+ fillEntireHash();
327
+ return super.rb_values();
328
+ }
329
+ @Override
330
+ public IRubyObject shift(ThreadContext context) {
331
+ fillEntireHash();
332
+ return super.shift(context);
333
+ }
334
+ @Override
335
+ public IRubyObject select(final ThreadContext context, final Block block) {
336
+ fillEntireHash();
337
+ return super.select(context, block);
338
+ }
339
+ @Override
340
+ public IRubyObject select19(final ThreadContext context, final Block block) {
341
+ fillEntireHash();
342
+ return super.select19(context, block);
343
+ }
344
+ @Override
345
+ public IRubyObject delete_if(final ThreadContext context, final Block block) {
346
+ fillEntireHash();
347
+ return super.delete_if(context, block);
348
+ }
349
+ @Override
350
+ public IRubyObject reject(final ThreadContext context, final Block block) {
351
+ fillEntireHash();
352
+ return super.reject(context, block);
353
+ }
354
+ @Override
355
+ public IRubyObject reject_bang(final ThreadContext context, final Block block) {
356
+ fillEntireHash();
357
+ return super.reject_bang(context, block);
358
+ }
359
+ @Override
360
+ public RubyHash rb_clear() {
361
+ fillEntireHash();
362
+ return super.rb_clear();
363
+ }
364
+ @Override
365
+ public RubyHash invert(final ThreadContext context) {
366
+ fillEntireHash();
367
+ return super.invert(context);
368
+ }
369
+ @Override
370
+ public RubyHash merge_bang(final ThreadContext context, final IRubyObject other, final Block block) {
371
+ fillEntireHash();
372
+ return super.merge_bang(context, other, block);
373
+ }
374
+ @Override
375
+ public RubyHash merge_bang19(final ThreadContext context, final IRubyObject other, final Block block) {
376
+ fillEntireHash();
377
+ return super.merge_bang19(context, other, block);
378
+ }
379
+ @Override
380
+ public RubyHash merge(ThreadContext context, IRubyObject other, Block block) {
381
+ fillEntireHash();
382
+ return super.merge(context, other, block);
383
+ }
384
+ @Override
385
+ public RubyHash initialize_copy(ThreadContext context, IRubyObject other) {
386
+ fillEntireHash();
387
+ return super.initialize_copy(context, other);
388
+ }
389
+ @Override
390
+ public RubyHash initialize_copy19(ThreadContext context, IRubyObject other) {
391
+ fillEntireHash();
392
+ return super.initialize_copy19(context, other);
393
+ }
394
+ @Override
395
+ public RubyHash replace(final ThreadContext context, IRubyObject other) {
396
+ fillEntireHash();
397
+ return super.replace(context, other);
398
+ }
399
+ @Override
400
+ public RubyHash replace19(final ThreadContext context, IRubyObject other) {
401
+ fillEntireHash();
402
+ return super.replace19(context, other);
403
+ }
404
+ @Override
405
+ public RubyArray values_at(ThreadContext context, IRubyObject[] args) {
406
+ fillEntireHash();
407
+ return super.values_at(context, args);
408
+ }
409
+ @Override
410
+ public IRubyObject assoc(final ThreadContext context, final IRubyObject obj) {
411
+ fillEntireHash();
412
+ return super.assoc(context, obj);
413
+ }
414
+ @Override
415
+ public IRubyObject rassoc(final ThreadContext context, final IRubyObject obj) {
416
+ fillEntireHash();
417
+ return super.rassoc(context, obj);
418
+ }
419
+ @Override
420
+ public IRubyObject flatten(ThreadContext context) {
421
+ fillEntireHash();
422
+ return super.flatten(context);
423
+ }
424
+ @Override
425
+ public IRubyObject flatten(ThreadContext context, IRubyObject level) {
426
+ fillEntireHash();
427
+ return super.flatten(context, level);
428
+ }
429
+ @Override
430
+ public IRubyObject getCompareByIdentity(ThreadContext context) {
431
+ fillEntireHash();
432
+ return super.getCompareByIdentity(context);
433
+ }
434
+ @Override
435
+ public IRubyObject getCompareByIdentity_p(ThreadContext context) {
436
+ fillEntireHash();
437
+ return super.getCompareByIdentity_p(context);
438
+ }
439
+ @Override
440
+ public IRubyObject dup(ThreadContext context) {
441
+ fillEntireHash();
442
+ return super.dup(context);
443
+ }
444
+ @Override
445
+ public IRubyObject rbClone(ThreadContext context) {
446
+ fillEntireHash();
447
+ return super.rbClone(context);
448
+ }
449
+ }