puma 2.8.2 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/DEPLOYMENT.md +2 -2
- data/History.txt +24 -0
- data/README.md +2 -2
- data/Rakefile +2 -2
- data/bin/pumactl +1 -1
- data/ext/puma_http11/mini_ssl.c +7 -4
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +284 -192
- data/lib/puma/binder.rb +23 -23
- data/lib/puma/cluster.rb +1 -1
- data/lib/puma/const.rb +2 -2
- data/lib/puma/minissl.rb +24 -20
- data/lib/puma/server.rb +4 -4
- data/puma.gemspec +1 -1
- data/test/test_minissl.rb +18 -14
- data/test/test_puma_server.rb +0 -35
- data/test/test_puma_server_ssl.rb +91 -0
- metadata +34 -42
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dd2e7a0ca1eba42615a406f35c0bbc304b91ee4c
|
4
|
+
data.tar.gz: fe274c58f7d7722caa7a7d444b080873c271034b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f021e24772d46c519e6edc358e25d3ab51bd65b6378918826bd647d7f08d1084c61f49e234c38c24113acdd075985a45f9bd83f7a1cb685526a36586af082ba3
|
7
|
+
data.tar.gz: 8dfc80519eaa94052b3f377546c701b7d1b84efeb40b6345d894caa40369a467a2bfc37955ece93ea84f4cb5a5013e14ff3952ccaf58f0260e222a09e1a6ac72
|
data/DEPLOYMENT.md
CHANGED
@@ -42,7 +42,7 @@ Here are some rules of thumb:
|
|
42
42
|
|
43
43
|
**How do you know if you're got enough (or too many workers)?**
|
44
44
|
|
45
|
-
A good question. Due to MRI's GIL, only one thread can be executing at a time.
|
45
|
+
A good question. Due to MRI's GIL, only one thread can be executing Ruby code at a time.
|
46
46
|
But since so many apps are waiting on IO from DBs, etc., they can utilize threads
|
47
47
|
to make better use of the process.
|
48
48
|
|
@@ -56,7 +56,7 @@ you've got capacity still but aren't starving threads.
|
|
56
56
|
|
57
57
|
## Daemonizing
|
58
58
|
|
59
|
-
I prefer to not daemonize my servers and use something like `runit` or `
|
59
|
+
I prefer to not daemonize my servers and use something like `runit` or `upstart` to
|
60
60
|
monitor them as child processes. This gives them fast response to crashes and
|
61
61
|
makes it easy to figure out what is going on. Additionally, unlike `unicorn`,
|
62
62
|
puma does not require daemonization to do zero-downtime restarts.
|
data/History.txt
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
=== 2.9.0 / 2014-07-12
|
2
|
+
|
3
|
+
* 1 minor feature:
|
4
|
+
* Add SSL support for JRuby
|
5
|
+
|
6
|
+
* 3 bug fixes:
|
7
|
+
* Typo BUNDLER_GEMFILE -> BUNDLE_GEMFILE
|
8
|
+
* Use fast_write because we can't trust syswrite
|
9
|
+
* pumactl - do not modify original ARGV
|
10
|
+
|
11
|
+
* 4 doc fixes:
|
12
|
+
* BSD-3-Clause over BSD to avoid confusion
|
13
|
+
* Deploy doc: clarification of the GIL
|
14
|
+
* Fix typo in DEPLOYMENT.md
|
15
|
+
* Update README.md
|
16
|
+
|
17
|
+
* 6 PRs merged:
|
18
|
+
* Merge pull request #520 from misfo/patch-2
|
19
|
+
* Merge pull request #530 from looker/jruby-ssl
|
20
|
+
* Merge pull request #537 from vlmonk/patch-1
|
21
|
+
* Merge pull request #540 from allaire/patch-1
|
22
|
+
* Merge pull request #544 from chulkilee/bsd-3-clause
|
23
|
+
* Merge pull request #551 from jcxplorer/patch-1
|
24
|
+
|
1
25
|
=== 2.8.2 / 2014-04-12
|
2
26
|
|
3
27
|
* 4 bug fixes:
|
data/README.md
CHANGED
@@ -117,7 +117,7 @@ If you're preloading your application and using ActiveRecord, it's recommend you
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
-
When you use preload_app, your new code goes all in the master process, and is then copied in the workers (meaning it’s only compatible with cluster mode). General rule is to use preload_app when your workers die often and need fast starts. If you don’t have many workers, you should
|
120
|
+
When you use preload_app, your new code goes all in the master process, and is then copied in the workers (meaning it’s only compatible with cluster mode). General rule is to use preload_app when your workers die often and need fast starts. If you don’t have many workers, you probably should not use preload_app.
|
121
121
|
|
122
122
|
Note that preload_app can’t be used with phased restart, since phased restart kills and restarts workers one-by-one, and preload_app is all about copying the code of master into the workers.
|
123
123
|
|
@@ -248,4 +248,4 @@ $ bundle exec rake
|
|
248
248
|
|
249
249
|
## License
|
250
250
|
|
251
|
-
Puma is copyright 2013 Evan Phoenix and contributors. It is licensed under the BSD license. See the include LICENSE file for details.
|
251
|
+
Puma is copyright 2013 Evan Phoenix and contributors. It is licensed under the BSD 3-Clause license. See the include LICENSE file for details.
|
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ HOE = Hoe.spec "puma" do
|
|
11
11
|
self.readme_file = "README.md"
|
12
12
|
self.urls = %w!http://puma.io https://github.com/puma/puma!
|
13
13
|
|
14
|
-
license "BSD"
|
14
|
+
license "BSD-3-Clause"
|
15
15
|
developer 'Evan Phoenix', 'evan@phx.io'
|
16
16
|
|
17
17
|
spec_extras[:extensions] = ["ext/puma_http11/extconf.rb"]
|
@@ -22,7 +22,7 @@ HOE = Hoe.spec "puma" do
|
|
22
22
|
|
23
23
|
dependency "rack", [">= 1.1", "< 2.0"]
|
24
24
|
|
25
|
-
extra_dev_deps << ["rake-compiler", "~> 0.8
|
25
|
+
extra_dev_deps << ["rake-compiler", "~> 0.8"]
|
26
26
|
end
|
27
27
|
|
28
28
|
task :prerelease => [:clobber, :check_manifest, :test]
|
data/bin/pumactl
CHANGED
data/ext/puma_http11/mini_ssl.c
CHANGED
@@ -36,15 +36,18 @@ ms_conn* engine_alloc(VALUE klass, VALUE* obj) {
|
|
36
36
|
return conn;
|
37
37
|
}
|
38
38
|
|
39
|
-
VALUE engine_init_server(VALUE self, VALUE
|
39
|
+
VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
|
40
40
|
VALUE obj;
|
41
41
|
SSL_CTX* ctx;
|
42
42
|
SSL* ssl;
|
43
43
|
|
44
44
|
ms_conn* conn = engine_alloc(self, &obj);
|
45
45
|
|
46
|
-
|
47
|
-
|
46
|
+
ID sym_key = rb_intern("key");
|
47
|
+
VALUE key = rb_funcall(mini_ssl_ctx, sym_key, 0);
|
48
|
+
|
49
|
+
ID sym_cert = rb_intern("cert");
|
50
|
+
VALUE cert = rb_funcall(mini_ssl_ctx, sym_cert, 0);
|
48
51
|
|
49
52
|
ctx = SSL_CTX_new(SSLv23_server_method());
|
50
53
|
conn->ctx = ctx;
|
@@ -184,7 +187,7 @@ void Init_mini_ssl(VALUE puma) {
|
|
184
187
|
|
185
188
|
eError = rb_define_class_under(mod, "SSLError", rb_eStandardError);
|
186
189
|
|
187
|
-
rb_define_singleton_method(eng, "server", engine_init_server,
|
190
|
+
rb_define_singleton_method(eng, "server", engine_init_server, 1);
|
188
191
|
rb_define_singleton_method(eng, "client", engine_init_client, 0);
|
189
192
|
|
190
193
|
rb_define_method(eng, "inject", engine_inject, 1);
|
@@ -2,29 +2,34 @@ package org.jruby.puma;
|
|
2
2
|
|
3
3
|
import org.jruby.Ruby;
|
4
4
|
import org.jruby.RubyClass;
|
5
|
-
import org.jruby.RubyHash;
|
6
5
|
import org.jruby.RubyModule;
|
7
|
-
import org.jruby.RubyNumeric;
|
8
6
|
import org.jruby.RubyObject;
|
9
7
|
import org.jruby.RubyString;
|
10
|
-
|
11
8
|
import org.jruby.anno.JRubyMethod;
|
12
|
-
|
13
9
|
import org.jruby.runtime.Block;
|
14
10
|
import org.jruby.runtime.ObjectAllocator;
|
15
11
|
import org.jruby.runtime.ThreadContext;
|
16
12
|
import org.jruby.runtime.builtin.IRubyObject;
|
17
|
-
|
18
|
-
import org.jruby.exceptions.RaiseException;
|
19
|
-
|
20
13
|
import org.jruby.util.ByteList;
|
21
14
|
|
22
|
-
|
23
|
-
import javax.net.ssl
|
24
|
-
import javax.net.ssl.
|
25
|
-
import
|
26
|
-
import
|
27
|
-
import
|
15
|
+
import javax.net.ssl.KeyManagerFactory;
|
16
|
+
import javax.net.ssl.SSLContext;
|
17
|
+
import javax.net.ssl.SSLEngine;
|
18
|
+
import javax.net.ssl.SSLEngineResult;
|
19
|
+
import javax.net.ssl.SSLException;
|
20
|
+
import javax.net.ssl.SSLSession;
|
21
|
+
import java.io.FileInputStream;
|
22
|
+
import java.io.IOException;
|
23
|
+
import java.nio.ByteBuffer;
|
24
|
+
import java.security.KeyManagementException;
|
25
|
+
import java.security.KeyStore;
|
26
|
+
import java.security.KeyStoreException;
|
27
|
+
import java.security.NoSuchAlgorithmException;
|
28
|
+
import java.security.UnrecoverableKeyException;
|
29
|
+
import java.security.cert.CertificateException;
|
30
|
+
|
31
|
+
import static javax.net.ssl.SSLEngineResult.Status;
|
32
|
+
import static javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
28
33
|
|
29
34
|
public class MiniSSL extends RubyObject {
|
30
35
|
private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
@@ -33,9 +38,12 @@ public class MiniSSL extends RubyObject {
|
|
33
38
|
}
|
34
39
|
};
|
35
40
|
|
41
|
+
// set to true to switch on our low-fi trace logging
|
42
|
+
private static boolean DEBUG = false;
|
43
|
+
|
36
44
|
public static void createMiniSSL(Ruby runtime) {
|
37
45
|
RubyModule mPuma = runtime.defineModule("Puma");
|
38
|
-
RubyModule ssl =
|
46
|
+
RubyModule ssl = mPuma.defineModuleUnder("MiniSSL");
|
39
47
|
|
40
48
|
mPuma.defineClassUnder("SSLError",
|
41
49
|
runtime.getClass("IOError"),
|
@@ -45,245 +53,329 @@ public class MiniSSL extends RubyObject {
|
|
45
53
|
eng.defineAnnotatedMethods(MiniSSL.class);
|
46
54
|
}
|
47
55
|
|
48
|
-
|
49
|
-
|
56
|
+
/**
|
57
|
+
* Fairly transparent wrapper around {@link java.nio.ByteBuffer} which adds the enhancements we need
|
58
|
+
*/
|
59
|
+
private static class MiniSSLBuffer {
|
60
|
+
ByteBuffer buffer;
|
61
|
+
|
62
|
+
private MiniSSLBuffer(int capacity) { buffer = ByteBuffer.allocate(capacity); }
|
63
|
+
private MiniSSLBuffer(byte[] initialContents) { buffer = ByteBuffer.wrap(initialContents); }
|
64
|
+
|
65
|
+
public void clear() { buffer.clear(); }
|
66
|
+
public void compact() { buffer.compact(); }
|
67
|
+
public void flip() { buffer.flip(); }
|
68
|
+
public boolean hasRemaining() { return buffer.hasRemaining(); }
|
69
|
+
public int position() { return buffer.position(); }
|
70
|
+
|
71
|
+
public ByteBuffer getRawBuffer() {
|
72
|
+
return buffer;
|
73
|
+
}
|
74
|
+
|
75
|
+
/**
|
76
|
+
* Writes bytes to the buffer after ensuring there's room
|
77
|
+
*/
|
78
|
+
public void put(byte[] bytes) {
|
79
|
+
if (buffer.remaining() < bytes.length) {
|
80
|
+
resize(buffer.limit() + bytes.length);
|
81
|
+
}
|
82
|
+
buffer.put(bytes);
|
83
|
+
}
|
84
|
+
|
85
|
+
/**
|
86
|
+
* Ensures that newCapacity bytes can be written to this buffer, only re-allocating if necessary
|
87
|
+
*/
|
88
|
+
public void resize(int newCapacity) {
|
89
|
+
if (newCapacity > buffer.capacity()) {
|
90
|
+
ByteBuffer dstTmp = ByteBuffer.allocate(newCapacity);
|
91
|
+
buffer.flip();
|
92
|
+
dstTmp.put(buffer);
|
93
|
+
buffer = dstTmp;
|
94
|
+
} else {
|
95
|
+
buffer.limit(newCapacity);
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
/**
|
100
|
+
* Drains the buffer to a ByteList, or returns null for an empty buffer
|
101
|
+
*/
|
102
|
+
public ByteList asByteList() {
|
103
|
+
buffer.flip();
|
104
|
+
if (!buffer.hasRemaining()) {
|
105
|
+
buffer.clear();
|
106
|
+
return null;
|
107
|
+
}
|
108
|
+
|
109
|
+
byte[] bss = new byte[buffer.limit()];
|
110
|
+
|
111
|
+
buffer.get(bss);
|
112
|
+
buffer.clear();
|
113
|
+
return new ByteList(bss);
|
114
|
+
}
|
115
|
+
|
116
|
+
@Override
|
117
|
+
public String toString() { return buffer.toString(); }
|
118
|
+
}
|
50
119
|
|
51
|
-
private SSLEngine
|
120
|
+
private SSLEngine engine;
|
121
|
+
private MiniSSLBuffer inboundNetData;
|
122
|
+
private MiniSSLBuffer outboundAppData;
|
123
|
+
private MiniSSLBuffer outboundNetData;
|
52
124
|
|
53
|
-
private ByteBuffer peerAppData;
|
54
|
-
private ByteBuffer peerNetData;
|
55
|
-
private ByteBuffer netData;
|
56
|
-
private ByteBuffer dummy;
|
57
|
-
|
58
125
|
public MiniSSL(Ruby runtime, RubyClass klass) {
|
59
126
|
super(runtime, klass);
|
60
|
-
|
61
|
-
this.runtime = runtime;
|
62
127
|
}
|
63
128
|
|
64
129
|
@JRubyMethod(meta = true)
|
65
|
-
public static IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject
|
66
|
-
|
67
|
-
IRubyObject newInstance = klass.newInstance(context,
|
68
|
-
new IRubyObject[] { key, cert },
|
69
|
-
Block.NULL_BLOCK);
|
130
|
+
public static IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject miniSSLContext) {
|
131
|
+
RubyClass klass = (RubyClass) recv;
|
70
132
|
|
71
|
-
|
133
|
+
return klass.newInstance(context,
|
134
|
+
new IRubyObject[] { miniSSLContext },
|
135
|
+
Block.NULL_BLOCK);
|
72
136
|
}
|
73
137
|
|
74
138
|
@JRubyMethod
|
75
|
-
public IRubyObject initialize(
|
76
|
-
throws
|
77
|
-
java.io.FileNotFoundException,
|
78
|
-
java.io.IOException,
|
79
|
-
java.io.FileNotFoundException,
|
80
|
-
java.security.NoSuchAlgorithmException,
|
81
|
-
java.security.KeyManagementException,
|
82
|
-
java.security.cert.CertificateException,
|
83
|
-
java.security.UnrecoverableKeyException
|
84
|
-
{
|
139
|
+
public IRubyObject initialize(ThreadContext threadContext, IRubyObject miniSSLContext)
|
140
|
+
throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
|
85
141
|
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
86
|
-
KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
|
87
|
-
|
88
|
-
char[] pass = "blahblah".toCharArray();
|
89
142
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
pass);
|
143
|
+
char[] password = miniSSLContext.callMethod(threadContext, "keystore_pass").convertToString().asJavaString().toCharArray();
|
144
|
+
ks.load(new FileInputStream(miniSSLContext.callMethod(threadContext, "keystore").convertToString().asJavaString()),
|
145
|
+
password);
|
94
146
|
|
95
147
|
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
96
|
-
kmf.init(ks,
|
97
|
-
|
98
|
-
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
99
|
-
tmf.init(ts);
|
148
|
+
kmf.init(ks, password);
|
100
149
|
|
101
150
|
SSLContext sslCtx = SSLContext.getInstance("TLS");
|
102
151
|
|
103
|
-
sslCtx.init(kmf.getKeyManagers(),
|
104
|
-
|
105
|
-
sslc = sslCtx;
|
106
|
-
|
107
|
-
engine = sslc.createSSLEngine();
|
152
|
+
sslCtx.init(kmf.getKeyManagers(), null, null);
|
153
|
+
engine = sslCtx.createSSLEngine();
|
108
154
|
engine.setUseClientMode(false);
|
109
|
-
// engine.setNeedClientAuth(true);
|
110
155
|
|
111
156
|
SSLSession session = engine.getSession();
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
netData.limit(0);
|
118
|
-
|
119
|
-
peerNetData.clear();
|
120
|
-
peerAppData.clear();
|
121
|
-
netData.clear();
|
122
|
-
|
123
|
-
dummy = ByteBuffer.allocate(0);
|
124
|
-
|
157
|
+
inboundNetData = new MiniSSLBuffer(session.getPacketBufferSize());
|
158
|
+
outboundAppData = new MiniSSLBuffer(session.getApplicationBufferSize());
|
159
|
+
outboundAppData.flip();
|
160
|
+
outboundNetData = new MiniSSLBuffer(session.getPacketBufferSize());
|
161
|
+
|
125
162
|
return this;
|
126
163
|
}
|
127
164
|
|
128
165
|
@JRubyMethod
|
129
166
|
public IRubyObject inject(IRubyObject arg) {
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
167
|
+
try {
|
168
|
+
byte[] bytes = arg.convertToString().getBytes();
|
169
|
+
|
170
|
+
log("Net Data post pre-inject: " + inboundNetData);
|
171
|
+
inboundNetData.put(bytes);
|
172
|
+
log("Net Data post post-inject: " + inboundNetData);
|
173
|
+
|
174
|
+
log("inject(): " + bytes.length + " encrypted bytes from request");
|
175
|
+
return this;
|
176
|
+
} catch (Exception e) {
|
177
|
+
e.printStackTrace();
|
178
|
+
throw new RuntimeException(e);
|
179
|
+
}
|
140
180
|
}
|
141
181
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
SSLEngineResult res;
|
182
|
+
private enum SSLOperation {
|
183
|
+
WRAP,
|
184
|
+
UNWRAP
|
185
|
+
}
|
147
186
|
|
148
|
-
|
187
|
+
private SSLEngineResult doOp(SSLOperation sslOp, MiniSSLBuffer src, MiniSSLBuffer dst) throws SSLException {
|
188
|
+
SSLEngineResult res = null;
|
189
|
+
boolean retryOp = true;
|
190
|
+
while (retryOp) {
|
191
|
+
switch (sslOp) {
|
192
|
+
case WRAP:
|
193
|
+
res = engine.wrap(src.getRawBuffer(), dst.getRawBuffer());
|
194
|
+
break;
|
195
|
+
case UNWRAP:
|
196
|
+
res = engine.unwrap(src.getRawBuffer(), dst.getRawBuffer());
|
197
|
+
break;
|
198
|
+
default:
|
199
|
+
throw new IllegalStateException("Unknown SSLOperation: " + sslOp);
|
200
|
+
}
|
149
201
|
|
150
|
-
|
151
|
-
|
202
|
+
switch (res.getStatus()) {
|
203
|
+
case BUFFER_OVERFLOW:
|
204
|
+
log("SSLOp#doRun(): overflow");
|
205
|
+
log("SSLOp#doRun(): dst data at overflow: " + dst);
|
206
|
+
// increase the buffer size to accommodate the overflowing data
|
207
|
+
int newSize = Math.max(engine.getSession().getPacketBufferSize(), engine.getSession().getApplicationBufferSize());
|
208
|
+
dst.resize(newSize + dst.position());
|
209
|
+
// retry the operation
|
210
|
+
retryOp = true;
|
211
|
+
break;
|
212
|
+
case BUFFER_UNDERFLOW:
|
213
|
+
log("SSLOp#doRun(): underflow");
|
214
|
+
log("SSLOp#doRun(): src data at underflow: " + src);
|
215
|
+
// need to wait for more data to come in before we retry
|
216
|
+
retryOp = false;
|
217
|
+
break;
|
218
|
+
default:
|
219
|
+
// other cases are OK and CLOSED. We're done here.
|
220
|
+
retryOp = false;
|
221
|
+
}
|
152
222
|
}
|
153
223
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
log("read: ", res);
|
161
|
-
|
162
|
-
if(peerNetData.hasRemaining()) {
|
163
|
-
log("STILL HAD peerNetData!");
|
224
|
+
// after each op, run any delegated tasks if needed
|
225
|
+
if(engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
226
|
+
Runnable runnable;
|
227
|
+
while ((runnable = engine.getDelegatedTask()) != null) {
|
228
|
+
runnable.run();
|
229
|
+
}
|
164
230
|
}
|
165
231
|
|
166
|
-
|
167
|
-
|
232
|
+
return res;
|
233
|
+
}
|
168
234
|
|
169
|
-
|
235
|
+
@JRubyMethod
|
236
|
+
public IRubyObject read() throws Exception {
|
237
|
+
try {
|
238
|
+
inboundNetData.flip();
|
170
239
|
|
171
|
-
|
172
|
-
|
173
|
-
|
240
|
+
if(!inboundNetData.hasRemaining()) {
|
241
|
+
return getRuntime().getNil();
|
242
|
+
}
|
174
243
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
244
|
+
log("read(): inboundNetData prepped for read: " + inboundNetData);
|
245
|
+
|
246
|
+
MiniSSLBuffer inboundAppData = new MiniSSLBuffer(engine.getSession().getApplicationBufferSize());
|
247
|
+
SSLEngineResult res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
|
248
|
+
log("read(): after initial unwrap", engine, res);
|
249
|
+
|
250
|
+
log("read(): Net Data post unwrap: " + inboundNetData);
|
251
|
+
|
252
|
+
HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
|
253
|
+
boolean done = false;
|
254
|
+
while (!done) {
|
255
|
+
switch (handshakeStatus) {
|
256
|
+
case NEED_WRAP:
|
257
|
+
res = doOp(SSLOperation.WRAP, inboundAppData, outboundNetData);
|
258
|
+
log("read(): after handshake wrap", engine, res);
|
259
|
+
break;
|
260
|
+
case NEED_UNWRAP:
|
261
|
+
res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData);
|
262
|
+
log("read(): after handshake unwrap", engine, res);
|
263
|
+
if (res.getStatus() == Status.BUFFER_UNDERFLOW) {
|
264
|
+
// need more data before we can shake more hands
|
265
|
+
done = true;
|
266
|
+
}
|
267
|
+
break;
|
268
|
+
default:
|
269
|
+
done = true;
|
270
|
+
}
|
271
|
+
handshakeStatus = engine.getHandshakeStatus();
|
272
|
+
}
|
181
273
|
|
182
|
-
|
183
|
-
|
274
|
+
if (inboundNetData.hasRemaining()) {
|
275
|
+
log("Net Data post pre-compact: " + inboundNetData);
|
276
|
+
inboundNetData.compact();
|
277
|
+
log("Net Data post post-compact: " + inboundNetData);
|
278
|
+
} else {
|
279
|
+
log("Net Data post pre-reset: " + inboundNetData);
|
280
|
+
inboundNetData.clear();
|
281
|
+
log("Net Data post post-reset: " + inboundNetData);
|
282
|
+
}
|
184
283
|
|
185
|
-
|
186
|
-
|
284
|
+
ByteList appDataByteList = inboundAppData.asByteList();
|
285
|
+
if (appDataByteList == null) {
|
286
|
+
return getRuntime().getNil();
|
287
|
+
}
|
187
288
|
|
188
|
-
|
289
|
+
RubyString str = getRuntime().newString("");
|
290
|
+
str.setValue(appDataByteList);
|
189
291
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
292
|
+
logPlain("\n");
|
293
|
+
log("read(): begin dump of request data >>>>\n");
|
294
|
+
if (str.asJavaString().getBytes().length < 1000) {
|
295
|
+
logPlain(str.asJavaString() + "\n");
|
296
|
+
}
|
297
|
+
logPlain("Num bytes: " + str.asJavaString().getBytes().length + "\n");
|
298
|
+
log("read(): end dump of request data <<<<\n");
|
299
|
+
return str;
|
300
|
+
} catch (Exception e) {
|
301
|
+
e.printStackTrace();
|
302
|
+
throw new RuntimeException(e);
|
197
303
|
}
|
198
|
-
|
199
|
-
// if(peerAppData.position() == 0 &&
|
200
|
-
// res.getStatus() == SSLEngineResult.Status.OK &&
|
201
|
-
// peerNetData.hasRemaining()) {
|
202
|
-
// res = engine.unwrap(peerNetData, peerAppData);
|
203
|
-
// }
|
204
|
-
|
205
|
-
byte[] bss = new byte[peerAppData.limit()];
|
206
|
-
|
207
|
-
peerAppData.get(bss);
|
208
|
-
|
209
|
-
RubyString str = getRuntime().newString("");
|
210
|
-
str.setValue(new ByteList(bss));
|
211
|
-
|
212
|
-
return str;
|
213
304
|
}
|
214
305
|
|
215
|
-
private static
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
if(hsStatus == HandshakeStatus.NEED_TASK) {
|
221
|
-
Runnable runnable;
|
222
|
-
while ((runnable = engine.getDelegatedTask()) != null) {
|
223
|
-
log("\trunning delegated task...");
|
224
|
-
runnable.run();
|
225
|
-
}
|
226
|
-
hsStatus = engine.getHandshakeStatus();
|
227
|
-
if (hsStatus == HandshakeStatus.NEED_TASK) {
|
228
|
-
throw new Exception(
|
229
|
-
"handshake shouldn't need additional tasks");
|
230
|
-
}
|
231
|
-
log("\tnew HandshakeStatus: " + hsStatus);
|
306
|
+
private static void log(String str, SSLEngine engine, SSLEngineResult result) {
|
307
|
+
if (DEBUG) {
|
308
|
+
log(str + " " + result.getStatus() + "/" + engine.getHandshakeStatus() +
|
309
|
+
"---bytes consumed: " + result.bytesConsumed() +
|
310
|
+
", bytes produced: " + result.bytesProduced());
|
232
311
|
}
|
233
|
-
|
234
|
-
return hsStatus;
|
235
312
|
}
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
"\t\"getStatus() / getHandshakeStatus()\" +\n" +
|
241
|
-
"\t\"bytesConsumed() / bytesProduced()\"\n");
|
242
|
-
|
243
|
-
HandshakeStatus hsStatus = result.getHandshakeStatus();
|
244
|
-
log(str +
|
245
|
-
result.getStatus() + "/" + hsStatus + ", " +
|
246
|
-
result.bytesConsumed() + "/" + result.bytesProduced() +
|
247
|
-
" bytes");
|
248
|
-
if (hsStatus == HandshakeStatus.FINISHED) {
|
249
|
-
log("\t...ready for application data");
|
313
|
+
|
314
|
+
private static void log(String str) {
|
315
|
+
if (DEBUG) {
|
316
|
+
System.out.println("MiniSSL.java: " + str);
|
250
317
|
}
|
251
318
|
}
|
252
319
|
|
253
|
-
private static void
|
254
|
-
|
320
|
+
private static void logPlain(String str) {
|
321
|
+
if (DEBUG) {
|
322
|
+
System.out.println(str);
|
323
|
+
}
|
255
324
|
}
|
256
|
-
|
257
|
-
|
258
325
|
|
259
326
|
@JRubyMethod
|
260
|
-
public IRubyObject write(IRubyObject arg)
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
327
|
+
public IRubyObject write(IRubyObject arg) {
|
328
|
+
try {
|
329
|
+
log("write(): begin dump of response data >>>>\n");
|
330
|
+
logPlain("\n");
|
331
|
+
if (arg.asJavaString().getBytes().length < 1000) {
|
332
|
+
logPlain(arg.asJavaString() + "\n");
|
333
|
+
}
|
334
|
+
logPlain("Num bytes: " + arg.asJavaString().getBytes().length + "\n");
|
335
|
+
log("write(): end dump of response data <<<<\n");
|
265
336
|
|
266
|
-
|
337
|
+
byte[] bls = arg.convertToString().getBytes();
|
338
|
+
outboundAppData = new MiniSSLBuffer(bls);
|
267
339
|
|
268
|
-
|
340
|
+
return getRuntime().newFixnum(bls.length);
|
341
|
+
} catch (Exception e) {
|
342
|
+
e.printStackTrace();
|
343
|
+
throw new RuntimeException(e);
|
344
|
+
}
|
269
345
|
}
|
270
346
|
|
271
347
|
@JRubyMethod
|
272
|
-
public IRubyObject extract() {
|
273
|
-
|
348
|
+
public IRubyObject extract() throws SSLException {
|
349
|
+
try {
|
350
|
+
ByteList dataByteList = outboundNetData.asByteList();
|
351
|
+
if (dataByteList != null) {
|
352
|
+
RubyString str = getRuntime().newString("");
|
353
|
+
str.setValue(dataByteList);
|
354
|
+
return str;
|
355
|
+
}
|
274
356
|
|
275
|
-
|
276
|
-
|
277
|
-
|
357
|
+
if (!outboundAppData.hasRemaining()) {
|
358
|
+
return getRuntime().getNil();
|
359
|
+
}
|
278
360
|
|
279
|
-
|
361
|
+
outboundNetData.clear();
|
362
|
+
SSLEngineResult res = doOp(SSLOperation.WRAP, outboundAppData, outboundNetData);
|
363
|
+
log("extract(): bytes consumed: " + res.bytesConsumed() + "\n");
|
364
|
+
log("extract(): bytes produced: " + res.bytesProduced() + "\n");
|
365
|
+
dataByteList = outboundNetData.asByteList();
|
366
|
+
if (dataByteList == null) {
|
367
|
+
return getRuntime().getNil();
|
368
|
+
}
|
280
369
|
|
281
|
-
|
282
|
-
|
370
|
+
RubyString str = getRuntime().newString("");
|
371
|
+
str.setValue(dataByteList);
|
283
372
|
|
284
|
-
|
285
|
-
str.setValue(new ByteList(bss));
|
373
|
+
log("extract(): " + dataByteList.getRealSize() + " encrypted bytes for response");
|
286
374
|
|
287
|
-
|
375
|
+
return str;
|
376
|
+
} catch (Exception e) {
|
377
|
+
e.printStackTrace();
|
378
|
+
throw new RuntimeException(e);
|
379
|
+
}
|
288
380
|
}
|
289
381
|
}
|
data/lib/puma/binder.rb
CHANGED
@@ -121,26 +121,36 @@ module Puma
|
|
121
121
|
|
122
122
|
@listeners << [str, io]
|
123
123
|
when "ssl"
|
124
|
-
if IS_JRUBY
|
125
|
-
@events.error "SSL not supported on JRuby"
|
126
|
-
raise UnsupportedOption
|
127
|
-
end
|
128
|
-
|
129
124
|
params = Rack::Utils.parse_query uri.query
|
130
125
|
require 'puma/minissl'
|
131
126
|
|
132
127
|
ctx = MiniSSL::Context.new
|
133
|
-
unless params['key']
|
134
|
-
@events.error "Please specify the SSL key via 'key='"
|
135
|
-
end
|
136
128
|
|
137
|
-
|
129
|
+
if defined?(JRUBY_VERSION)
|
130
|
+
unless params['keystore']
|
131
|
+
@events.error "Please specify the Java keystore via 'keystore='"
|
132
|
+
end
|
138
133
|
|
139
|
-
|
140
|
-
|
141
|
-
|
134
|
+
ctx.keystore = params['keystore']
|
135
|
+
|
136
|
+
unless params['keystore-pass']
|
137
|
+
@events.error "Please specify the Java keystore password via 'keystore-pass='"
|
138
|
+
end
|
139
|
+
|
140
|
+
ctx.keystore_pass = params['keystore-pass']
|
141
|
+
else
|
142
|
+
unless params['key']
|
143
|
+
@events.error "Please specify the SSL key via 'key='"
|
144
|
+
end
|
145
|
+
|
146
|
+
ctx.key = params['key']
|
142
147
|
|
143
|
-
|
148
|
+
unless params['cert']
|
149
|
+
@events.error "Please specify the SSL cert via 'cert='"
|
150
|
+
end
|
151
|
+
|
152
|
+
ctx.cert = params['cert']
|
153
|
+
end
|
144
154
|
|
145
155
|
ctx.verify_mode = MiniSSL::VERIFY_NONE
|
146
156
|
|
@@ -215,11 +225,6 @@ module Puma
|
|
215
225
|
|
216
226
|
def add_ssl_listener(host, port, ctx,
|
217
227
|
optimize_for_latency=true, backlog=1024)
|
218
|
-
if IS_JRUBY
|
219
|
-
@events.error "SSL not supported on JRuby"
|
220
|
-
raise UnsupportedOption
|
221
|
-
end
|
222
|
-
|
223
228
|
require 'puma/minissl'
|
224
229
|
|
225
230
|
s = TCPServer.new(host, port)
|
@@ -239,11 +244,6 @@ module Puma
|
|
239
244
|
end
|
240
245
|
|
241
246
|
def inherited_ssl_listener(fd, ctx)
|
242
|
-
if IS_JRUBY
|
243
|
-
@events.error "SSL not supported on JRuby"
|
244
|
-
raise UnsupportedOption
|
245
|
-
end
|
246
|
-
|
247
247
|
require 'puma/minissl'
|
248
248
|
s = TCPServer.for_fd(fd)
|
249
249
|
@ios << MiniSSL::Server.new(s, ctx)
|
data/lib/puma/cluster.rb
CHANGED
@@ -183,7 +183,7 @@ module Puma
|
|
183
183
|
|
184
184
|
# If we're not running under a Bundler context, then
|
185
185
|
# report the info about the context we will be using
|
186
|
-
if !ENV['
|
186
|
+
if !ENV['BUNDLE_GEMFILE'] and File.exist?("Gemfile")
|
187
187
|
log "+ Gemfile in context: #{File.expand_path("Gemfile")}"
|
188
188
|
end
|
189
189
|
|
data/lib/puma/const.rb
CHANGED
@@ -28,8 +28,8 @@ module Puma
|
|
28
28
|
# too taxing on performance.
|
29
29
|
module Const
|
30
30
|
|
31
|
-
PUMA_VERSION = VERSION = "2.
|
32
|
-
CODE_NAME = "
|
31
|
+
PUMA_VERSION = VERSION = "2.9.0".freeze
|
32
|
+
CODE_NAME = "Team High Five".freeze
|
33
33
|
|
34
34
|
FAST_TRACK_KA_TIMEOUT = 0.2
|
35
35
|
|
data/lib/puma/minissl.rb
CHANGED
@@ -69,7 +69,7 @@ module Puma
|
|
69
69
|
|
70
70
|
return data.bytesize if need == 0
|
71
71
|
|
72
|
-
data = data[
|
72
|
+
data = data[wrote..-1]
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
@@ -91,31 +91,35 @@ module Puma
|
|
91
91
|
class Context
|
92
92
|
attr_accessor :verify_mode
|
93
93
|
|
94
|
-
|
95
|
-
|
94
|
+
if defined?(JRUBY_VERSION)
|
95
|
+
# jruby-specific Context properties: java uses a keystore and password pair rather than a cert/key pair
|
96
|
+
attr_reader :keystore
|
97
|
+
attr_accessor :keystore_pass
|
96
98
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
99
|
+
def keystore=(keystore)
|
100
|
+
raise ArgumentError, "No such keystore file '#{keystore}'" unless File.exist? keystore
|
101
|
+
@keystore = keystore
|
102
|
+
end
|
103
|
+
else
|
104
|
+
# non-jruby Context properties
|
105
|
+
attr_reader :key
|
106
|
+
attr_reader :cert
|
107
|
+
|
108
|
+
def key=(key)
|
109
|
+
raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
|
110
|
+
@key = key
|
111
|
+
end
|
101
112
|
|
102
|
-
|
103
|
-
|
104
|
-
|
113
|
+
def cert=(cert)
|
114
|
+
raise ArgumentError, "No such cert file '#{cert}'" unless File.exist? cert
|
115
|
+
@cert = cert
|
116
|
+
end
|
105
117
|
end
|
106
118
|
end
|
107
119
|
|
108
120
|
VERIFY_NONE = 0
|
109
121
|
VERIFY_PEER = 1
|
110
122
|
|
111
|
-
#if defined?(JRUBY_VERSION)
|
112
|
-
#class Engine
|
113
|
-
#def self.server(key, cert)
|
114
|
-
#new(key, cert)
|
115
|
-
#end
|
116
|
-
#end
|
117
|
-
#end
|
118
|
-
|
119
123
|
class Server
|
120
124
|
def initialize(socket, ctx)
|
121
125
|
@socket = socket
|
@@ -128,14 +132,14 @@ module Puma
|
|
128
132
|
|
129
133
|
def accept
|
130
134
|
io = @socket.accept
|
131
|
-
engine = Engine.server @ctx
|
135
|
+
engine = Engine.server @ctx
|
132
136
|
|
133
137
|
Socket.new io, engine
|
134
138
|
end
|
135
139
|
|
136
140
|
def accept_nonblock
|
137
141
|
io = @socket.accept_nonblock
|
138
|
-
engine = Engine.server @ctx
|
142
|
+
engine = Engine.server @ctx
|
139
143
|
|
140
144
|
Socket.new io, engine
|
141
145
|
end
|
data/lib/puma/server.rb
CHANGED
@@ -614,10 +614,10 @@ module Puma
|
|
614
614
|
begin
|
615
615
|
res_body.each do |part|
|
616
616
|
if chunked
|
617
|
-
client
|
618
|
-
client
|
617
|
+
fast_write client, part.bytesize.to_s(16)
|
618
|
+
fast_write client, line_ending
|
619
619
|
fast_write client, part
|
620
|
-
client
|
620
|
+
fast_write client, line_ending
|
621
621
|
else
|
622
622
|
fast_write client, part
|
623
623
|
end
|
@@ -626,7 +626,7 @@ module Puma
|
|
626
626
|
end
|
627
627
|
|
628
628
|
if chunked
|
629
|
-
client
|
629
|
+
fast_write client, CLOSE_CHUNKED
|
630
630
|
client.flush
|
631
631
|
end
|
632
632
|
rescue SystemCallError, IOError
|
data/puma.gemspec
CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.extensions = ["ext/puma_http11/extconf.rb"]
|
24
24
|
s.files = `git ls-files`.split($/)
|
25
25
|
s.homepage = "http://puma.io"
|
26
|
-
s.license = "BSD"
|
26
|
+
s.license = "BSD-3-Clause"
|
27
27
|
s.rdoc_options = ["--main", "README.md"]
|
28
28
|
s.require_paths = ["lib"]
|
29
29
|
s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
|
data/test/test_minissl.rb
CHANGED
@@ -1,25 +1,29 @@
|
|
1
1
|
require 'test/unit'
|
2
|
-
|
3
|
-
unless defined? JRUBY_VERSION
|
4
|
-
|
5
2
|
require 'puma'
|
6
3
|
require 'puma/minissl'
|
7
4
|
|
8
5
|
class TestMiniSSL < Test::Unit::TestCase
|
9
6
|
|
10
|
-
|
11
|
-
|
7
|
+
if defined?(JRUBY_VERSION)
|
8
|
+
def test_raises_with_invalid_keystore_file
|
9
|
+
ctx = Puma::MiniSSL::Context.new
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
exception = assert_raise(ArgumentError) { ctx.keystore = "/no/such/keystore" }
|
12
|
+
assert_equal("No such keystore file '/no/such/keystore'", exception.message)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
def test_raises_with_invalid_key_file
|
16
|
+
ctx = Puma::MiniSSL::Context.new
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
exception = assert_raise(ArgumentError) { ctx.key = "/no/such/key" }
|
19
|
+
assert_equal("No such key file '/no/such/key'", exception.message)
|
20
|
+
end
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
22
|
+
def test_raises_with_invalid_cert_file
|
23
|
+
ctx = Puma::MiniSSL::Context.new
|
24
24
|
|
25
|
+
exception = assert_raise(ArgumentError) { ctx.cert = "/no/such/cert" }
|
26
|
+
assert_equal("No such cert file '/no/such/cert'", exception.message)
|
27
|
+
end
|
28
|
+
end
|
25
29
|
end
|
data/test/test_puma_server.rb
CHANGED
@@ -18,47 +18,12 @@ class TestPumaServer < Test::Unit::TestCase
|
|
18
18
|
|
19
19
|
@events = Puma::Events.new STDOUT, STDERR
|
20
20
|
@server = Puma::Server.new @app, @events
|
21
|
-
|
22
|
-
if defined?(JRUBY_VERSION)
|
23
|
-
@ssl_key = File.expand_path "../../examples/puma/keystore.jks", __FILE__
|
24
|
-
@ssl_cert = @ssl_key
|
25
|
-
else
|
26
|
-
@ssl_key = File.expand_path "../../examples/puma/puma_keypair.pem", __FILE__
|
27
|
-
@ssl_cert = File.expand_path "../../examples/puma/cert_puma.pem", __FILE__
|
28
|
-
end
|
29
21
|
end
|
30
22
|
|
31
23
|
def teardown
|
32
24
|
@server.stop(true)
|
33
25
|
end
|
34
26
|
|
35
|
-
def test_url_scheme_for_https
|
36
|
-
ctx = Puma::MiniSSL::Context.new
|
37
|
-
|
38
|
-
ctx.key = @ssl_key
|
39
|
-
ctx.cert = @ssl_cert
|
40
|
-
|
41
|
-
ctx.verify_mode = Puma::MiniSSL::VERIFY_NONE
|
42
|
-
|
43
|
-
@server.add_ssl_listener @host, @port, ctx
|
44
|
-
@server.run
|
45
|
-
|
46
|
-
http = Net::HTTP.new @host, @port
|
47
|
-
http.use_ssl = true
|
48
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
49
|
-
|
50
|
-
body = nil
|
51
|
-
http.start do
|
52
|
-
req = Net::HTTP::Get.new "/", {}
|
53
|
-
|
54
|
-
http.request(req) do |rep|
|
55
|
-
body = rep.body
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
assert_equal "https", body
|
60
|
-
end unless defined? JRUBY_VERSION
|
61
|
-
|
62
27
|
def test_proper_stringio_body
|
63
28
|
data = nil
|
64
29
|
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require "rbconfig"
|
2
|
+
require 'test/unit'
|
3
|
+
require 'socket'
|
4
|
+
require 'openssl'
|
5
|
+
|
6
|
+
require 'puma/minissl'
|
7
|
+
require 'puma/server'
|
8
|
+
|
9
|
+
require 'net/https'
|
10
|
+
|
11
|
+
class TestPumaServerSSL < Test::Unit::TestCase
|
12
|
+
|
13
|
+
def setup
|
14
|
+
@port = 3212
|
15
|
+
@host = "127.0.0.1"
|
16
|
+
|
17
|
+
@app = lambda { |env| [200, {}, [env['rack.url_scheme']]] }
|
18
|
+
|
19
|
+
ctx = Puma::MiniSSL::Context.new
|
20
|
+
|
21
|
+
if defined?(JRUBY_VERSION)
|
22
|
+
ctx.keystore = File.expand_path "../../examples/puma/keystore.jks", __FILE__
|
23
|
+
ctx.keystore_pass = 'blahblah'
|
24
|
+
else
|
25
|
+
ctx.key = File.expand_path "../../examples/puma/puma_keypair.pem", __FILE__
|
26
|
+
ctx.cert = File.expand_path "../../examples/puma/cert_puma.pem", __FILE__
|
27
|
+
end
|
28
|
+
|
29
|
+
ctx.verify_mode = Puma::MiniSSL::VERIFY_NONE
|
30
|
+
|
31
|
+
@events = Puma::Events.new STDOUT, STDERR
|
32
|
+
@server = Puma::Server.new @app, @events
|
33
|
+
@server.add_ssl_listener @host, @port, ctx
|
34
|
+
@server.run
|
35
|
+
|
36
|
+
@http = Net::HTTP.new @host, @port
|
37
|
+
@http.use_ssl = true
|
38
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
39
|
+
end
|
40
|
+
|
41
|
+
def teardown
|
42
|
+
@server.stop(true)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_url_scheme_for_https
|
46
|
+
body = nil
|
47
|
+
@http.start do
|
48
|
+
req = Net::HTTP::Get.new "/", {}
|
49
|
+
|
50
|
+
@http.request(req) do |rep|
|
51
|
+
body = rep.body
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
assert_equal "https", body
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_very_large_return
|
59
|
+
giant = "x" * 2056610
|
60
|
+
|
61
|
+
@server.app = proc do
|
62
|
+
[200, {}, [giant]]
|
63
|
+
end
|
64
|
+
|
65
|
+
body = nil
|
66
|
+
@http.start do
|
67
|
+
req = Net::HTTP::Get.new "/"
|
68
|
+
@http.request(req) do |rep|
|
69
|
+
body = rep.body
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
assert_equal giant.bytesize, body.bytesize
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_form_submit
|
77
|
+
body = nil
|
78
|
+
@http.start do
|
79
|
+
req = Net::HTTP::Post.new '/'
|
80
|
+
req.set_form_data('a' => '1', 'b' => '2')
|
81
|
+
|
82
|
+
@http.request(req) do |rep|
|
83
|
+
body = rep.body
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
assert_equal "https", body
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
metadata
CHANGED
@@ -1,86 +1,77 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
5
|
-
prerelease:
|
4
|
+
version: 2.9.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Evan Phoenix
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2014-
|
11
|
+
date: 2014-07-13 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rack
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '1.1'
|
22
|
-
- - <
|
20
|
+
- - "<"
|
23
21
|
- !ruby/object:Gem::Version
|
24
22
|
version: '2.0'
|
25
23
|
type: :runtime
|
26
24
|
prerelease: false
|
27
25
|
version_requirements: !ruby/object:Gem::Requirement
|
28
|
-
none: false
|
29
26
|
requirements:
|
30
|
-
- -
|
27
|
+
- - ">="
|
31
28
|
- !ruby/object:Gem::Version
|
32
29
|
version: '1.1'
|
33
|
-
- - <
|
30
|
+
- - "<"
|
34
31
|
- !ruby/object:Gem::Version
|
35
32
|
version: '2.0'
|
36
33
|
- !ruby/object:Gem::Dependency
|
37
34
|
name: rdoc
|
38
35
|
requirement: !ruby/object:Gem::Requirement
|
39
|
-
none: false
|
40
36
|
requirements:
|
41
|
-
- - ~>
|
37
|
+
- - "~>"
|
42
38
|
- !ruby/object:Gem::Version
|
43
39
|
version: '4.0'
|
44
40
|
type: :development
|
45
41
|
prerelease: false
|
46
42
|
version_requirements: !ruby/object:Gem::Requirement
|
47
|
-
none: false
|
48
43
|
requirements:
|
49
|
-
- - ~>
|
44
|
+
- - "~>"
|
50
45
|
- !ruby/object:Gem::Version
|
51
46
|
version: '4.0'
|
52
47
|
- !ruby/object:Gem::Dependency
|
53
48
|
name: rake-compiler
|
54
49
|
requirement: !ruby/object:Gem::Requirement
|
55
|
-
none: false
|
56
50
|
requirements:
|
57
|
-
- - ~>
|
51
|
+
- - "~>"
|
58
52
|
- !ruby/object:Gem::Version
|
59
|
-
version: 0.8
|
53
|
+
version: '0.8'
|
60
54
|
type: :development
|
61
55
|
prerelease: false
|
62
56
|
version_requirements: !ruby/object:Gem::Requirement
|
63
|
-
none: false
|
64
57
|
requirements:
|
65
|
-
- - ~>
|
58
|
+
- - "~>"
|
66
59
|
- !ruby/object:Gem::Version
|
67
|
-
version: 0.8
|
60
|
+
version: '0.8'
|
68
61
|
- !ruby/object:Gem::Dependency
|
69
62
|
name: hoe
|
70
63
|
requirement: !ruby/object:Gem::Requirement
|
71
|
-
none: false
|
72
64
|
requirements:
|
73
|
-
- - ~>
|
65
|
+
- - "~>"
|
74
66
|
- !ruby/object:Gem::Version
|
75
|
-
version: '3.
|
67
|
+
version: '3.12'
|
76
68
|
type: :development
|
77
69
|
prerelease: false
|
78
70
|
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
none: false
|
80
71
|
requirements:
|
81
|
-
- - ~>
|
72
|
+
- - "~>"
|
82
73
|
- !ruby/object:Gem::Version
|
83
|
-
version: '3.
|
74
|
+
version: '3.12'
|
84
75
|
description: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server
|
85
76
|
for Ruby/Rack applications. Puma is intended for use in both development and production
|
86
77
|
environments. In order to get the best throughput, it is highly recommended that
|
@@ -164,14 +155,6 @@ files:
|
|
164
155
|
- lib/puma/util.rb
|
165
156
|
- lib/rack/handler/puma.rb
|
166
157
|
- puma.gemspec
|
167
|
-
- tools/jungle/README.md
|
168
|
-
- tools/jungle/init.d/README.md
|
169
|
-
- tools/jungle/init.d/puma
|
170
|
-
- tools/jungle/init.d/run-puma
|
171
|
-
- tools/jungle/upstart/README.md
|
172
|
-
- tools/jungle/upstart/puma-manager.conf
|
173
|
-
- tools/jungle/upstart/puma.conf
|
174
|
-
- tools/trickletest.rb
|
175
158
|
- test/test_app_status.rb
|
176
159
|
- test/test_cli.rb
|
177
160
|
- test/test_config.rb
|
@@ -183,38 +166,46 @@ files:
|
|
183
166
|
- test/test_null_io.rb
|
184
167
|
- test/test_persistent.rb
|
185
168
|
- test/test_puma_server.rb
|
169
|
+
- test/test_puma_server_ssl.rb
|
186
170
|
- test/test_rack_handler.rb
|
187
171
|
- test/test_rack_server.rb
|
188
172
|
- test/test_tcp_rack.rb
|
189
173
|
- test/test_thread_pool.rb
|
190
174
|
- test/test_unix_socket.rb
|
191
175
|
- test/test_ws.rb
|
176
|
+
- tools/jungle/README.md
|
177
|
+
- tools/jungle/init.d/README.md
|
178
|
+
- tools/jungle/init.d/puma
|
179
|
+
- tools/jungle/init.d/run-puma
|
180
|
+
- tools/jungle/upstart/README.md
|
181
|
+
- tools/jungle/upstart/puma-manager.conf
|
182
|
+
- tools/jungle/upstart/puma.conf
|
183
|
+
- tools/trickletest.rb
|
192
184
|
homepage: http://puma.io
|
193
185
|
licenses:
|
194
|
-
- BSD
|
186
|
+
- BSD-3-Clause
|
187
|
+
metadata: {}
|
195
188
|
post_install_message:
|
196
189
|
rdoc_options:
|
197
|
-
- --main
|
190
|
+
- "--main"
|
198
191
|
- README.md
|
199
192
|
require_paths:
|
200
193
|
- lib
|
201
194
|
required_ruby_version: !ruby/object:Gem::Requirement
|
202
|
-
none: false
|
203
195
|
requirements:
|
204
|
-
- -
|
196
|
+
- - ">="
|
205
197
|
- !ruby/object:Gem::Version
|
206
198
|
version: 1.8.7
|
207
199
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
208
|
-
none: false
|
209
200
|
requirements:
|
210
|
-
- -
|
201
|
+
- - ">="
|
211
202
|
- !ruby/object:Gem::Version
|
212
203
|
version: '0'
|
213
204
|
requirements: []
|
214
|
-
rubyforge_project:
|
215
|
-
rubygems_version:
|
205
|
+
rubyforge_project:
|
206
|
+
rubygems_version: 2.2.2
|
216
207
|
signing_key:
|
217
|
-
specification_version:
|
208
|
+
specification_version: 4
|
218
209
|
summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
|
219
210
|
Ruby/Rack applications
|
220
211
|
test_files:
|
@@ -229,6 +220,7 @@ test_files:
|
|
229
220
|
- test/test_null_io.rb
|
230
221
|
- test/test_persistent.rb
|
231
222
|
- test/test_puma_server.rb
|
223
|
+
- test/test_puma_server_ssl.rb
|
232
224
|
- test/test_rack_handler.rb
|
233
225
|
- test/test_rack_server.rb
|
234
226
|
- test/test_tcp_rack.rb
|