jubilee 1.1.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 (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
+ }