jubilee 0.4.0 → 0.4.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.
@@ -2,8 +2,6 @@ package org.jruby.jubilee;
2
2
 
3
3
  import org.vertx.java.core.http.HttpServerResponse;
4
4
 
5
- import java.util.Map;
6
-
7
5
  /**
8
6
  * Created with IntelliJ IDEA.
9
7
  * User: isaiah
@@ -1,12 +1,16 @@
1
1
  package org.jruby.jubilee;
2
2
 
3
- import org.vertx.java.core.*;
4
- import org.vertx.java.core.http.*;
5
-
6
3
  import org.jruby.*;
7
- import org.jruby.runtime.*;
8
- import org.jruby.runtime.builtin.*;
9
4
  import org.jruby.anno.JRubyMethod;
5
+ import org.jruby.runtime.Block;
6
+ import org.jruby.runtime.ObjectAllocator;
7
+ import org.jruby.runtime.ThreadContext;
8
+ import org.jruby.runtime.builtin.IRubyObject;
9
+ import org.vertx.java.core.Handler;
10
+ import org.vertx.java.core.Vertx;
11
+ import org.vertx.java.core.VertxFactory;
12
+ import org.vertx.java.core.http.HttpServer;
13
+ import org.vertx.java.core.http.HttpServerRequest;
10
14
  import org.vertx.java.core.json.JsonArray;
11
15
  import org.vertx.java.core.json.JsonObject;
12
16
 
@@ -19,6 +23,7 @@ public class Server extends RubyObject {
19
23
  private String keyStorePath;
20
24
  private String keyStorePassword;
21
25
  private String eventBusPrefix;
26
+ private int numberOfWorkers;
22
27
  private int port;
23
28
  private String host;
24
29
 
@@ -57,14 +62,17 @@ public class Server extends RubyObject {
57
62
  RubySymbol keystore_path_k = runtime.newSymbol("keystore_path");
58
63
  RubySymbol keystore_password_k = runtime.newSymbol("keystore_password");
59
64
  RubySymbol eventbus_prefix_k = runtime.newSymbol("eventbus_prefix");
60
- this.port = RubyInteger.num2int(options.op_aref(context, port_k));
65
+ RubySymbol number_of_workers_k = runtime.newSymbol("number_of_workers");
66
+ this.port = RubyInteger.fix2int(options.op_aref(context, port_k));
61
67
  if (options.has_key_p(host_k).isTrue()) {
62
68
  this.host = options.op_aref(context, host_k).toString();
63
69
  } else {
64
70
  this.host = "0.0.0.0";
65
71
  }
66
72
  this.ssl = options.op_aref(context, ssl_k).isTrue();
67
- this.app = new RackApplication(app, this.ssl);
73
+ if (options.has_key_p(number_of_workers_k).isTrue())
74
+ this.numberOfWorkers = RubyInteger.fix2int(options.op_aref(context, number_of_workers_k));
75
+ this.app = new RackApplication(app, this.ssl, this.numberOfWorkers);
68
76
  if (options.has_key_p(keystore_path_k).isTrue()) {
69
77
  this.keyStorePath = options.op_aref(context, keystore_path_k).toString();
70
78
  this.keyStorePassword = options.op_aref(context, keystore_password_k).toString();
@@ -1,11 +1,10 @@
1
1
  package org.jruby.jubilee.impl;
2
2
 
3
- import org.jruby.RubyArray;
4
- import org.jruby.RubyString;
5
- import org.jruby.jubilee.RackEnvironment;
6
- import org.jruby.jubilee.Const;
7
3
  import org.jruby.Ruby;
8
4
  import org.jruby.RubyHash;
5
+ import org.jruby.RubyString;
6
+ import org.jruby.jubilee.Const;
7
+ import org.jruby.jubilee.RackEnvironment;
9
8
  import org.jruby.jubilee.RackInput;
10
9
  import org.vertx.java.core.MultiMap;
11
10
  import org.vertx.java.core.http.HttpServerRequest;
@@ -19,81 +18,82 @@ import java.util.Map;
19
18
  * Time: 11:40 AM
20
19
  */
21
20
  public class DefaultRackEnvironment implements RackEnvironment {
22
- private RubyHash env;
23
- private MultiMap headers;
24
- private Ruby runtime;
21
+ private RubyHash env;
22
+ private MultiMap headers;
23
+ private Ruby runtime;
25
24
 
26
- public DefaultRackEnvironment(final Ruby runtime, final HttpServerRequest request, RackInput input, boolean isSSL) {
25
+ public DefaultRackEnvironment(final Ruby runtime, final HttpServerRequest request, RackInput input, boolean isSSL) {
27
26
 
28
- this.runtime = runtime;
29
- // DEFAULT
30
- env = RubyHash.newHash(runtime);
31
- env.put(Const.RACK_VERSION, Const.RackVersion(runtime));
32
- env.put(Const.RACK_ERRORS, new RubyIORackErrors(runtime));
33
- env.put(Const.RACK_MULTITHREAD, true);
34
- env.put(Const.RACK_MULTIPROCESS, false);
35
- env.put(Const.RACK_RUNONCE, true);
36
- if (isSSL)
37
- env.put(Const.URL_SCHEME, Const.HTTPS);
38
- else
39
- env.put(Const.URL_SCHEME, Const.HTTP);
40
- env.put(Const.SCRIPT_NAME, "");
27
+ this.runtime = runtime;
28
+ // DEFAULT
29
+ env = RubyHash.newHash(runtime);
30
+ env.put(Const.RACK_VERSION, Const.RackVersion(runtime));
31
+ env.put(Const.RACK_ERRORS, new RubyIORackErrors(runtime));
32
+ env.put(Const.RACK_MULTITHREAD, true);
33
+ env.put(Const.RACK_MULTIPROCESS, false);
34
+ env.put(Const.RACK_RUNONCE, true);
35
+ if (isSSL)
36
+ env.put(Const.URL_SCHEME, Const.HTTPS);
37
+ else
38
+ env.put(Const.URL_SCHEME, Const.HTTP);
39
+ env.put(Const.SCRIPT_NAME, "");
41
40
 
42
- env.put(Const.SERVER_PROTOCOL, Const.HTTP_11);
43
- env.put(Const.SERVER_SOFTWARE, Const.JUBILEE_VERSION);
44
- env.put(Const.GATEWAY_INTERFACE, Const.CGI_VER);
41
+ env.put(Const.SERVER_PROTOCOL, Const.HTTP_11);
42
+ env.put(Const.SERVER_SOFTWARE, Const.JUBILEE_VERSION);
43
+ env.put(Const.GATEWAY_INTERFACE, Const.CGI_VER);
45
44
 
46
- // Parse request headers
47
- headers = request.headers();
48
- String host;
49
- if ((host = headers.get(Const.Vertx.HOST)) != null) {
50
- int colon = host.indexOf(":");
51
- if (colon > 0) {
52
- env.put(Const.SERVER_NAME, host.substring(0, colon));
53
- env.put(Const.SERVER_PORT, host.substring(colon + 1));
54
- } else {
55
- env.put(Const.SERVER_NAME, host);
56
- env.put(Const.SERVER_PORT, Const.PORT_80);
57
- }
45
+ // Parse request headers
46
+ headers = request.headers();
47
+ String host;
48
+ if ((host = headers.get(Const.Vertx.HOST)) != null) {
49
+ int colon = host.indexOf(":");
50
+ if (colon > 0) {
51
+ env.put(Const.SERVER_NAME, host.substring(0, colon));
52
+ env.put(Const.SERVER_PORT, host.substring(colon + 1));
53
+ } else {
54
+ env.put(Const.SERVER_NAME, host);
55
+ env.put(Const.SERVER_PORT, Const.PORT_80);
56
+ }
58
57
 
59
- } else {
60
- env.put(Const.SERVER_NAME, Const.LOCALHOST);
61
- env.put(Const.SERVER_PORT, Const.PORT_80);
62
- }
58
+ } else {
59
+ env.put(Const.SERVER_NAME, Const.LOCALHOST);
60
+ env.put(Const.SERVER_PORT, Const.PORT_80);
61
+ }
62
+
63
+ env.put(Const.RACK_INPUT, input);
64
+ env.put(Const.REQUEST_METHOD, request.method());
65
+ env.put(Const.REQUEST_PATH, request.path());
66
+ env.put(Const.REQUEST_URI, request.uri());
67
+ env.put(Const.QUERY_STRING, orEmpty(request.query()));
68
+ env.put(Const.REMOTE_ADDR, request.remoteAddress().getHostString());
69
+ env.put(Const.HTTP_HOST, host);
70
+ env.put(Const.HTTP_COOKIE, orEmpty(headers.get(Const.Vertx.COOKIE)));
71
+ env.put(Const.HTTP_USER_AGENT, headers.get(Const.Vertx.USER_AGENT));
72
+ env.put(Const.HTTP_ACCEPT, headers.get(Const.Vertx.ACCEPT));
73
+ env.put(Const.HTTP_ACCEPT_LANGUAGE, orEmpty(headers.get(Const.Vertx.ACCEPT_LANGUAGE)));
74
+ env.put(Const.HTTP_ACCEPT_ENCODING, orEmpty(headers.get(Const.Vertx.ACCEPT_ENCODING)));
75
+ env.put(Const.HTTP_CONNECTION, orEmpty(headers.get(Const.Vertx.CONNECTION)));
76
+ env.put(Const.HTTP_CONTENT_TYPE, orEmpty(headers.get(Const.Vertx.CONTENT_TYPE)));
63
77
 
64
- env.put(Const.RACK_INPUT, input);
65
- env.put(Const.REQUEST_METHOD, request.method());
66
- env.put(Const.REQUEST_PATH, request.path());
67
- env.put(Const.REQUEST_URI, request.uri());
68
- env.put(Const.QUERY_STRING, orEmpty(request.query()));
69
- env.put(Const.REMOTE_ADDR, request.remoteAddress().getHostString());
70
- env.put(Const.HTTP_HOST, host);
71
- env.put(Const.HTTP_COOKIE, orEmpty(headers.get(Const.Vertx.COOKIE)));
72
- env.put(Const.HTTP_USER_AGENT, headers.get(Const.Vertx.USER_AGENT));
73
- env.put(Const.HTTP_ACCEPT, headers.get(Const.Vertx.ACCEPT));
74
- env.put(Const.HTTP_ACCEPT_LANGUAGE, orEmpty(headers.get(Const.Vertx.ACCEPT_LANGUAGE)));
75
- env.put(Const.HTTP_ACCEPT_ENCODING, orEmpty(headers.get(Const.Vertx.ACCEPT_ENCODING)));
76
- env.put(Const.HTTP_CONNECTION, orEmpty(headers.get(Const.Vertx.CONNECTION)));
77
- env.put(Const.HTTP_CONTENT_TYPE, orEmpty(headers.get(Const.Vertx.CONTENT_TYPE)));
78
- String contentLength;
79
- if ((contentLength = headers.get(Const.Vertx.CONTENT_LENGTH)) != null)
80
- env.put(Const.HTTP_CONTENT_LENGTH, contentLength);
81
- env.put(Const.PATH_INFO, request.path());
78
+ String contentLength;
79
+ if ((contentLength = headers.get(Const.Vertx.CONTENT_LENGTH)) != null)
80
+ env.put(Const.HTTP_CONTENT_LENGTH, contentLength);
81
+ env.put(Const.PATH_INFO, request.path());
82
82
 
83
- // Additional headers
84
- for (Map.Entry<String, String> var : Const.ADDITIONAL_HEADERS.entrySet())
85
- setRackHeader(var.getKey(), var.getValue());
86
- }
83
+ // Additional headers
84
+ for (Map.Entry<String, String> var : Const.ADDITIONAL_HEADERS.entrySet())
85
+ setRackHeader(var.getKey(), var.getValue());
86
+ }
87
87
 
88
- public RubyHash getEnv() {
89
- return env;
90
- }
88
+ public RubyHash getEnv() {
89
+ return env;
90
+ }
91
91
 
92
- private RubyString orEmpty(String jString) {
93
- return jString == null ? RubyString.newEmptyString(runtime) : RubyString.newString(runtime, jString);
94
- }
92
+ private RubyString orEmpty(String jString) {
93
+ return jString == null ? RubyString.newEmptyString(runtime) : RubyString.newString(runtime, jString);
94
+ }
95
95
 
96
- private void setRackHeader(String vertxHeader, String rackHeader) {
97
- if (headers.contains(vertxHeader)) env.put(rackHeader, headers.get(vertxHeader));
98
- }
96
+ private void setRackHeader(String vertxHeader, String rackHeader) {
97
+ if (headers.contains(vertxHeader)) env.put(rackHeader, headers.get(vertxHeader));
98
+ }
99
99
  }
@@ -1,6 +1,8 @@
1
1
  package org.jruby.jubilee.impl;
2
2
 
3
3
  import io.netty.buffer.ByteBuf;
4
+ import org.jcodings.specific.ASCIIEncoding;
5
+ import org.jcodings.Encoding;
4
6
  import org.jruby.*;
5
7
  import org.jruby.anno.JRubyMethod;
6
8
  import org.jruby.jubilee.Const;
@@ -9,10 +11,10 @@ import org.jruby.runtime.Block;
9
11
  import org.jruby.runtime.ObjectAllocator;
10
12
  import org.jruby.runtime.ThreadContext;
11
13
  import org.jruby.runtime.builtin.IRubyObject;
12
- import org.vertx.java.core.buffer.Buffer;
14
+ import org.vertx.java.core.http.HttpServerRequest;
13
15
 
14
- import java.util.concurrent.CountDownLatch;
15
- import java.util.concurrent.TimeUnit;
16
+ import java.util.Arrays;
17
+ import java.util.concurrent.atomic.AtomicBoolean;
16
18
 
17
19
  /**
18
20
  * Created with IntelliJ IDEA.
@@ -21,144 +23,178 @@ import java.util.concurrent.TimeUnit;
21
23
  * Time: 10:12 PM
22
24
  */
23
25
  public class RubyIORackInput extends RubyObject implements RackInput {
24
- private ByteBuf buf;
25
- private CountDownLatch bodyLatch;
26
+ private Encoding BINARY = ASCIIEncoding.INSTANCE;
27
+ private HttpServerRequest request;
28
+ private int len;
29
+ private boolean chunked;
30
+ private ByteBuf buf;
31
+ private AtomicBoolean eof;
26
32
 
27
- public static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
33
+ public static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
34
+ @Override
35
+ public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
36
+ return new RubyIORackInput(ruby, rubyClass);
37
+ }
38
+ };
39
+
40
+ public static RubyClass createRubyIORackInputClass(Ruby runtime) {
41
+ RubyModule jModule = runtime.defineModule("Jubilee");
42
+ RubyClass rackIOInputClass = jModule.defineClassUnder("RubyIORackInput", runtime.getObject(), ALLOCATOR);
43
+ rackIOInputClass.defineAnnotatedMethods(RubyIORackInput.class);
44
+ return rackIOInputClass;
45
+ }
46
+
47
+ public RubyIORackInput(Ruby runtime, RubyClass metaClass) {
48
+ super(runtime, metaClass);
49
+ }
50
+
51
+ public RubyIORackInput(Ruby runtime, HttpServerRequest request, ByteBuf buf, AtomicBoolean eof) {
52
+ this(runtime, createRubyIORackInputClass(runtime));
53
+ this.request = request;
54
+ String hdr = request.headers().get(Const.Vertx.CONTENT_LENGTH);
55
+ this.chunked = hdr == null;
56
+ this.len = this.chunked ? 0 : Integer.parseInt(hdr);
57
+ this.buf = buf;
58
+ this.eof = eof;
59
+ }
60
+
61
+ /**
62
+ * gets must be called without arguments and return a string, or nil on EOF.
63
+ * <p/>
64
+ * this method return one line a time.
65
+ *
66
+ * @param context it's a JRuby thing
67
+ * @return a string, or nil on EOF
68
+ */
28
69
  @Override
29
- public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
30
- return new RubyIORackInput(ruby, rubyClass);
70
+ @JRubyMethod
71
+ public IRubyObject gets(ThreadContext context) {
72
+ RubyString line = RubyString.newEmptyString(getRuntime(), BINARY);
73
+ if (isEOF())
74
+ return getRuntime().getNil();
75
+ int lineEnd = -1;
76
+ while (lineEnd == -1 && !isEOF())
77
+ lineEnd = buf.indexOf(buf.readerIndex(), buf.writerIndex(), Const.EOL);
78
+
79
+ // No line break found, read all
80
+ if (lineEnd == -1)
81
+ return readAll(line);
82
+
83
+ int readLength = lineEnd - buf.readerIndex();
84
+ byte[] dst = new byte[readLength + 1];
85
+ buf.readBytes(dst);
86
+ return line.cat(dst);
31
87
  }
32
- };
33
-
34
- public static RubyClass createRubyIORackInputClass(Ruby runtime) {
35
- RubyModule jModule = runtime.defineModule("Jubilee");
36
- RubyClass rackIOInputClass = jModule.defineClassUnder("RubyIORackInput", runtime.getObject(), ALLOCATOR);
37
- rackIOInputClass.defineAnnotatedMethods(RubyIORackInput.class);
38
- return rackIOInputClass;
39
- }
40
-
41
- public RubyIORackInput(Ruby runtime, RubyClass metaClass) {
42
- super(runtime, metaClass);
43
- }
44
-
45
- public RubyIORackInput(Ruby runtime, Buffer buf, CountDownLatch bodyLatch) {
46
- this(runtime, createRubyIORackInputClass(runtime));
47
- this.buf = buf.getByteBuf();
48
- this.bodyLatch = bodyLatch;
49
- }
50
-
51
- /**
52
- * gets must be called without arguments and return a string, or nil on EOF.
53
- * <p/>
54
- * this method return one line a time.
55
- *
56
- * @param context it's a JRuby thing
57
- * @return a string, or nil on EOF
58
- */
59
- @Override
60
- @JRubyMethod
61
- public IRubyObject gets(ThreadContext context) {
62
- // TODO this is not the optimistic way. remove the latch and implement tee_input as unicorn
63
- try {
64
- bodyLatch.await(10, TimeUnit.SECONDS);
65
- } catch (InterruptedException ignore) {
66
- return getRuntime().getNil();
88
+
89
+ /**
90
+ * read behaves like IO#read. Its signature is read([length, [buffer]]). If given,
91
+ * length must be an non-negative Integer (>= 0) or nil, and buffer must be a
92
+ * String and may not be nil. If length is given and not nil, then this method
93
+ * reads at most length bytes from the input stream. If length is not given or
94
+ * nil, then this method reads all data until EOF. When EOF is reached, this
95
+ * method returns nil if length is given and not nil, or "" if) length is not
96
+ * given or is nil. If buffer is given, then the read data will be placed into
97
+ * buffer instead of a newly created String object.
98
+ *
99
+ * @param context it's a JRuby thing
100
+ * @param args [length, [buffer]]
101
+ * @return nil if length is given and not nil, or "" if length is not given or nil
102
+ */
103
+ @Override
104
+ @JRubyMethod(optional = 2)
105
+ public IRubyObject read(ThreadContext context, IRubyObject[] args) {
106
+ RubyString dst = RubyString.newEmptyString(getRuntime(), BINARY);
107
+ if (isEOF())
108
+ return getRuntime().getNil();
109
+ int length;
110
+ switch (args.length) {
111
+ case 0:
112
+ return readAll(dst);
113
+ case 1:
114
+ length = RubyInteger.num2int(args[0]);
115
+ break;
116
+ default:
117
+ length = RubyInteger.num2int(args[0]);
118
+ dst = (RubyString) args[1];
119
+ }
120
+ if (length < 0)
121
+ getRuntime().newArgumentError("Negative length " + length + " given");
122
+ byte[] buffer = new byte[length];
123
+ int toRead = length;
124
+ while (toRead > 0 && !isEOF()) {
125
+ int len = Math.min(toRead, readableBytes());
126
+ buf.readBytes(buffer, length - toRead, len);
127
+ toRead = toRead - len;
128
+ }
129
+ if (toRead > 0)
130
+ buffer = Arrays.copyOfRange(buffer, 0, length - toRead);
131
+ return dst.cat(buffer);
67
132
  }
68
- if (buf.readableBytes() == 0)
69
- return getRuntime().getNil();
70
- int lineEnd = buf.indexOf(buf.readerIndex(), buf.capacity(), Const.EOL);
71
- int readLength;
72
- if ((readLength = lineEnd - buf.readerIndex()) > 0) {
73
- byte[] dst = new byte[readLength + 1];
74
- buf.readBytes(dst, 0, readLength + 1);
75
- return RubyString.newString(getRuntime(), dst);
133
+
134
+ /**
135
+ * each must be called without arguments and only yield Strings.
136
+ *
137
+ * @param context it's a JRuby thing
138
+ * @param block that receives yield of Strings
139
+ * @return pretty much nil
140
+ */
141
+ @Override
142
+ @JRubyMethod
143
+ public IRubyObject each(ThreadContext context, Block block) {
144
+ IRubyObject str;
145
+ while (!(str = gets(context)).isNil()) {
146
+ block.yield(context, str);
147
+ }
148
+ return getRuntime().getNil();
149
+ }
150
+
151
+ /**
152
+ * rewind must be called without arguments. It rewinds the input stream back
153
+ * to the beginning. It must not raise Errno::ESPIPE: that is, it may not be
154
+ * a pipe or a socket. Therefore, handler developers must buffer the input
155
+ * data into some rewindable object if the underlying input stream is not rewindable.
156
+ *
157
+ * @param context it's a JRuby thing
158
+ * @return pretty much nil
159
+ */
160
+ @Override
161
+ @JRubyMethod
162
+ public IRubyObject rewind(ThreadContext context) {
163
+ buf.readerIndex(0);
164
+ return getRuntime().getNil();
76
165
  }
77
- return getRuntime().getNil();
78
- }
79
-
80
- /**
81
- * read behaves like IO#read. Its signature is read([length, [buffer]]). If given,
82
- * length must be an non-negative Integer (>= 0) or nil, and buffer must be a
83
- * String and may not be nil. If length is given and not nil, then this method
84
- * reads at most length bytes from the input stream. If length is not given or
85
- * nil, then this method reads all data until EOF. When EOF is reached, this
86
- * method returns nil if length is given and not nil, or "" if) length is not
87
- * given or is nil. If buffer is given, then the read data will be placed into
88
- * buffer instead of a newly created String object.
89
- *
90
- * @param context it's a JRuby thing
91
- * @param args [length, [buffer]]
92
- * @return nil if length is given and not nil, or "" if length is not given or nil
93
- */
94
- @Override
95
- @JRubyMethod(optional = 2)
96
- public IRubyObject read(ThreadContext context, IRubyObject[] args) {
97
- try {
98
- bodyLatch.await(10, TimeUnit.SECONDS);
99
- } catch (InterruptedException ignore) {
100
- return getRuntime().getNil();
166
+
167
+ /**
168
+ * Close the input. Exposed only to the Java side because the Rack spec says
169
+ * that application code must not call close, so we don't expose a close method to Ruby.
170
+ */
171
+ @JRubyMethod
172
+ public IRubyObject close(ThreadContext context) {
173
+ buf.clear();
174
+ return getRuntime().getNil();
101
175
  }
102
- if (buf.readableBytes() == 0)
103
- return getRuntime().getNil();
104
- int length;
105
- switch (args.length) {
106
- case 0:
107
- length = buf.readableBytes();
108
- break;
109
- case 1:
110
- int len = RubyInteger.num2int(args[0]);
111
- length = len > buf.readableBytes() ? buf.readableBytes() : len;
112
- break;
113
- default:
114
- len = RubyInteger.num2int(args[0]);
115
- length = len > buf.readableBytes() ? buf.readableBytes() : len;
176
+
177
+ private int readableBytes() {
178
+ if (! this.chunked) {
179
+ return Math.min(buf.readableBytes(), this.len - buf.readerIndex());
180
+ }
181
+ return buf.readableBytes();
116
182
  }
117
- byte[] dst = new byte[length];
118
- buf.readBytes(dst, 0, length);
119
- return RubyString.newString(getRuntime(), dst);
120
- }
121
-
122
- /**
123
- * each must be called without arguments and only yield Strings.
124
- *
125
- * @param context it's a JRuby thing
126
- * @param block that receives yield of Strings
127
- * @return pretty much nil
128
- */
129
- @Override
130
- @JRubyMethod
131
- public IRubyObject each(ThreadContext context, Block block) {
132
- IRubyObject str;
133
- while (!(str = gets(context)).isNil()) {
134
- block.yield(context, str);
183
+
184
+ private boolean isEOF() {
185
+ while (buf.readableBytes() == 0 && !eof.get())
186
+ ; // wait while there is nothing to read
187
+ return buf.readableBytes() == 0 && eof.get();
188
+ }
189
+
190
+ private IRubyObject readAll(RubyString dst) {
191
+ buf.readerIndex(0);
192
+ while(!eof.get())
193
+ ; // wait until all data received
194
+ int length = this.chunked ? buf.readableBytes() : Math.min(this.len, buf.readableBytes());
195
+ byte[] data = new byte[length];
196
+ dst.cat(data);
197
+ buf.readBytes(data);
198
+ return dst.isEmpty() ? getRuntime().getNil() : dst;
135
199
  }
136
- return getRuntime().getNil();
137
- }
138
-
139
- /**
140
- * rewind must be called without arguments. It rewinds the input stream back
141
- * to the beginning. It must not raise Errno::ESPIPE: that is, it may not be
142
- * a pipe or a socket. Therefore, handler developers must buffer the input
143
- * data into some rewindable object if the underlying input stream is not rewindable.
144
- *
145
- * @param context it's a JRuby thing
146
- * @return pretty much nil
147
- */
148
- @Override
149
- @JRubyMethod
150
- public IRubyObject rewind(ThreadContext context) {
151
- buf.readerIndex(0);
152
- return getRuntime().getNil();
153
- }
154
-
155
- /**
156
- * Close the input. Exposed only to the Java side because the Rack spec says
157
- * that application code must not call close, so we don't expose a close method to Ruby.
158
- */
159
- @JRubyMethod
160
- public IRubyObject close(ThreadContext context) {
161
- buf.clear();
162
- return getRuntime().getNil();
163
- }
164
200
  }