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.
- data/.travis.yml +5 -0
- data/CHANGELOG +5 -0
- data/Gemfile +4 -2
- data/Gemfile.lock +47 -8
- data/README.md +2 -0
- data/VERSION +1 -1
- data/java/src/jubilee/JubileeService.java +1 -2
- data/java/src/org/jruby/jubilee/Const.java +135 -131
- data/java/src/org/jruby/jubilee/RackApplication.java +12 -8
- data/java/src/org/jruby/jubilee/RackResponse.java +0 -2
- data/java/src/org/jruby/jubilee/Server.java +15 -7
- data/java/src/org/jruby/jubilee/impl/DefaultRackEnvironment.java +71 -71
- data/java/src/org/jruby/jubilee/impl/RubyIORackInput.java +171 -135
- data/jubilee.gemspec +100 -0
- data/lib/jubilee/configuration.rb +25 -14
- data/lib/jubilee/jubilee.jar +0 -0
- data/lib/jubilee/server.rb +1 -2
- data/test/jubilee/{test_persistent.rb → test_response.rb} +28 -2
- data/test/jubilee/test_server.rb +1 -1
- data/test/jubilee/test_upload.rb +298 -0
- data/test/test_helper.rb +32 -0
- metadata +12 -9
@@ -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
|
-
|
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
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
21
|
+
private RubyHash env;
|
22
|
+
private MultiMap headers;
|
23
|
+
private Ruby runtime;
|
25
24
|
|
26
|
-
|
25
|
+
public DefaultRackEnvironment(final Ruby runtime, final HttpServerRequest request, RackInput input, boolean isSSL) {
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
89
|
-
|
90
|
-
|
88
|
+
public RubyHash getEnv() {
|
89
|
+
return env;
|
90
|
+
}
|
91
91
|
|
92
|
-
|
93
|
-
|
94
|
-
|
92
|
+
private RubyString orEmpty(String jString) {
|
93
|
+
return jString == null ? RubyString.newEmptyString(runtime) : RubyString.newString(runtime, jString);
|
94
|
+
}
|
95
95
|
|
96
|
-
|
97
|
-
|
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.
|
14
|
+
import org.vertx.java.core.http.HttpServerRequest;
|
13
15
|
|
14
|
-
import java.util.
|
15
|
-
import java.util.concurrent.
|
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
|
-
|
25
|
-
|
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
|
-
|
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
|
-
|
30
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
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
|
}
|