puma 0.8.1 → 0.8.2

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.

data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "hoe"
4
+ gem "rdoc"
5
+ gem "rake-compiler"
6
+ gem "rack"
@@ -1,4 +1,5 @@
1
1
  COPYING
2
+ Gemfile
2
3
  History.txt
3
4
  LICENSE
4
5
  Manifest.txt
@@ -17,23 +18,24 @@ examples/monitrc
17
18
  examples/random_thrash.rb
18
19
  examples/simpletest.rb
19
20
  examples/webrick_compare.rb
20
- ext/puma_http11/Http11Service.java
21
+ ext/puma_http11/PumaHttp11Service.java
21
22
  ext/puma_http11/ext_help.h
22
23
  ext/puma_http11/extconf.rb
23
- ext/puma_http11/puma_http11.c
24
24
  ext/puma_http11/http11_parser.c
25
25
  ext/puma_http11/http11_parser.h
26
26
  ext/puma_http11/http11_parser.java.rl
27
27
  ext/puma_http11/http11_parser.rl
28
28
  ext/puma_http11/http11_parser_common.rl
29
- ext/puma_http11/org/jruby/mongrel/Http11.java
30
- ext/puma_http11/org/jruby/mongrel/Http11Parser.java
29
+ ext/puma_http11/org/jruby/puma/Http11.java
30
+ ext/puma_http11/org/jruby/puma/Http11Parser.java
31
+ ext/puma_http11/puma_http11.c
31
32
  lib/puma.rb
32
33
  lib/puma/cli.rb
33
34
  lib/puma/const.rb
34
35
  lib/puma/events.rb
35
36
  lib/puma/gems.rb
36
37
  lib/puma/mime_types.yml
38
+ lib/puma/rack_patch.rb
37
39
  lib/puma/server.rb
38
40
  lib/puma/thread_pool.rb
39
41
  lib/puma/utils.rb
@@ -45,6 +47,7 @@ tasks/native.rake
45
47
  tasks/ragel.rake
46
48
  test/lobster.ru
47
49
  test/mime.yaml
50
+ test/test_cli.rb
48
51
  test/test_http10.rb
49
52
  test/test_http11.rb
50
53
  test/test_persistent.rb
data/Rakefile CHANGED
@@ -6,5 +6,7 @@
6
6
 
7
7
  require 'rubygems'
8
8
 
9
+ IS_JRUBY = defined?(RUBY_ENGINE) ? RUBY_ENGINE == "jruby" : false
10
+
9
11
  # load rakefile extensions (tasks)
10
12
  Dir['tasks/*.rake'].sort.each { |f| load f }
@@ -3,9 +3,9 @@ import java.io.IOException;
3
3
  import org.jruby.Ruby;
4
4
  import org.jruby.runtime.load.BasicLibraryService;
5
5
 
6
- import org.jruby.mongrel.Http11;
6
+ import org.jruby.puma.Http11;
7
7
 
8
- public class Http11Service implements BasicLibraryService {
8
+ public class PumaHttp11Service implements BasicLibraryService {
9
9
  public boolean basicLoad(final Ruby runtime) throws IOException {
10
10
  Http11.createHttp11(runtime);
11
11
  return true;
@@ -1,4 +1,4 @@
1
- package org.jruby.mongrel;
1
+ package org.jruby.puma;
2
2
 
3
3
  import org.jruby.util.ByteList;
4
4
 
@@ -121,7 +121,9 @@ public class Http11Parser {
121
121
 
122
122
  p = off;
123
123
  pe = len;
124
- byte[] data = buffer.unsafeBytes();
124
+ // get a copy of the bytes, since it may not start at 0
125
+ // FIXME: figure out how to just use the bytes in-place
126
+ byte[] data = buffer.bytes();
125
127
  parser.buffer = buffer;
126
128
 
127
129
  %% write exec;
@@ -1,4 +1,4 @@
1
- package org.jruby.mongrel;
1
+ package org.jruby.puma;
2
2
 
3
3
  import org.jruby.Ruby;
4
4
  import org.jruby.RubyClass;
@@ -45,21 +45,22 @@ public class Http11 extends RubyObject {
45
45
  };
46
46
 
47
47
  public static void createHttp11(Ruby runtime) {
48
- RubyModule mMongrel = runtime.defineModule("Mongrel");
49
- mMongrel.defineClassUnder("HttpParserError",runtime.getClass("IOError"),runtime.getClass("IOError").getAllocator());
48
+ RubyModule mPuma = runtime.defineModule("Puma");
49
+ mPuma.defineClassUnder("HttpParserError",runtime.getClass("IOError"),runtime.getClass("IOError").getAllocator());
50
50
 
51
- RubyClass cHttpParser = mMongrel.defineClassUnder("HttpParser",runtime.getObject(),ALLOCATOR);
51
+ RubyClass cHttpParser = mPuma.defineClassUnder("HttpParser",runtime.getObject(),ALLOCATOR);
52
52
  cHttpParser.defineAnnotatedMethods(Http11.class);
53
53
  }
54
54
 
55
55
  private Ruby runtime;
56
56
  private RubyClass eHttpParserError;
57
57
  private Http11Parser hp;
58
+ private RubyString body;
58
59
 
59
60
  public Http11(Ruby runtime, RubyClass clazz) {
60
61
  super(runtime,clazz);
61
62
  this.runtime = runtime;
62
- this.eHttpParserError = (RubyClass)runtime.getModule("Mongrel").getConstant("HttpParserError");
63
+ this.eHttpParserError = (RubyClass)runtime.getModule("Puma").getConstant("HttpParserError");
63
64
  this.hp = new Http11Parser();
64
65
  this.hp.parser.http_field = http_field;
65
66
  this.hp.parser.request_method = request_method;
@@ -86,7 +87,6 @@ public class Http11 extends RubyObject {
86
87
  validateMaxLength(vlen, MAX_FIELD_VALUE_LENGTH, MAX_FIELD_VALUE_LENGTH_ERR);
87
88
 
88
89
  v = RubyString.newString(runtime, new ByteList(Http11.this.hp.parser.buffer,value,vlen));
89
- f = RubyString.newString(runtime, "HTTP_");
90
90
  ByteList b = new ByteList(Http11.this.hp.parser.buffer,field,flen);
91
91
  for(int i = 0,j = b.length();i<j;i++) {
92
92
  if((b.get(i) & 0xFF) == '-') {
@@ -95,7 +95,15 @@ public class Http11 extends RubyObject {
95
95
  b.set(i, (byte)Character.toUpperCase((char)b.get(i)));
96
96
  }
97
97
  }
98
- f.cat(b);
98
+
99
+ String as = b.toString();
100
+
101
+ if(as.equals("CONTENT_LENGTH") || as.equals("CONTENT_TYPE")) {
102
+ f = RubyString.newString(runtime, b);
103
+ } else {
104
+ f = RubyString.newString(runtime, "HTTP_");
105
+ f.cat(b);
106
+ }
99
107
  req.op_aset(req.getRuntime().getCurrentContext(), f,v);
100
108
  }
101
109
  };
@@ -154,36 +162,7 @@ public class Http11 extends RubyObject {
154
162
 
155
163
  private Http11Parser.ElementCB header_done = new Http11Parser.ElementCB() {
156
164
  public void call(Object data, int at, int length) {
157
- RubyHash req = (RubyHash)data;
158
- ThreadContext context = req.getRuntime().getCurrentContext();
159
- IRubyObject temp,ctype,clen;
160
-
161
- clen = req.op_aref(context, runtime.newString("HTTP_CONTENT_LENGTH"));
162
- if(!clen.isNil()) {
163
- req.op_aset(context, runtime.newString("CONTENT_LENGTH"),clen);
164
- }
165
-
166
- ctype = req.op_aref(context, runtime.newString("HTTP_CONTENT_TYPE"));
167
- if(!ctype.isNil()) {
168
- req.op_aset(context, runtime.newString("CONTENT_TYPE"),ctype);
169
- }
170
-
171
- req.op_aset(context, runtime.newString("GATEWAY_INTERFACE"),runtime.newString("CGI/1.2"));
172
- if(!(temp = req.op_aref(context, runtime.newString("HTTP_HOST"))).isNil()) {
173
- String s = temp.toString();
174
- int colon = s.indexOf(':');
175
- if(colon != -1) {
176
- req.op_aset(context, runtime.newString("SERVER_NAME"),runtime.newString(s.substring(0,colon)));
177
- req.op_aset(context, runtime.newString("SERVER_PORT"),runtime.newString(s.substring(colon+1)));
178
- } else {
179
- req.op_aset(context, runtime.newString("SERVER_NAME"),temp);
180
- req.op_aset(context, runtime.newString("SERVER_PORT"),runtime.newString("80"));
181
- }
182
- }
183
-
184
- req.setInstanceVariable("@http_body", RubyString.newString(runtime, new ByteList(hp.parser.buffer, at, length)));
185
- req.op_aset(context, runtime.newString("SERVER_PROTOCOL"),runtime.newString("HTTP/1.1"));
186
- req.op_aset(context, runtime.newString("SERVER_SOFTWARE"),runtime.newString("Mongrel 1.2.0.beta.1"));
165
+ body = RubyString.newString(runtime, new ByteList(hp.parser.buffer, at, length));
187
166
  }
188
167
  };
189
168
 
@@ -238,4 +217,9 @@ public class Http11 extends RubyObject {
238
217
  public IRubyObject nread() {
239
218
  return runtime.newFixnum(this.hp.parser.nread);
240
219
  }
220
+
221
+ @JRubyMethod
222
+ public IRubyObject body() {
223
+ return body;
224
+ }
241
225
  }// Http11
@@ -1,6 +1,6 @@
1
1
 
2
- // line 1 "ext/http11/http11_parser.java.rl"
3
- package org.jruby.mongrel;
2
+ // line 1 "ext/puma_http11/http11_parser.java.rl"
3
+ package org.jruby.puma;
4
4
 
5
5
  import org.jruby.util.ByteList;
6
6
 
@@ -9,12 +9,12 @@ public class Http11Parser {
9
9
  /** Machine **/
10
10
 
11
11
 
12
- // line 65 "ext/http11/http11_parser.java.rl"
12
+ // line 65 "ext/puma_http11/http11_parser.java.rl"
13
13
 
14
14
 
15
15
  /** Data **/
16
16
 
17
- // line 18 "ext/http11/org/jruby/mongrel/Http11Parser.java"
17
+ // line 18 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
18
18
  private static byte[] init__http_parser_actions_0()
19
19
  {
20
20
  return new byte [] {
@@ -200,7 +200,7 @@ static final int http_parser_error = 0;
200
200
  static final int http_parser_en_main = 1;
201
201
 
202
202
 
203
- // line 69 "ext/http11/http11_parser.java.rl"
203
+ // line 69 "ext/puma_http11/http11_parser.java.rl"
204
204
 
205
205
  public static interface ElementCB {
206
206
  public void call(Object data, int at, int length);
@@ -236,12 +236,12 @@ static final int http_parser_en_main = 1;
236
236
  cs = 0;
237
237
 
238
238
 
239
- // line 240 "ext/http11/org/jruby/mongrel/Http11Parser.java"
239
+ // line 240 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
240
240
  {
241
241
  cs = http_parser_start;
242
242
  }
243
243
 
244
- // line 104 "ext/http11/http11_parser.java.rl"
244
+ // line 104 "ext/puma_http11/http11_parser.java.rl"
245
245
 
246
246
  body_start = 0;
247
247
  content_len = 0;
@@ -262,11 +262,13 @@ static final int http_parser_en_main = 1;
262
262
 
263
263
  p = off;
264
264
  pe = len;
265
- byte[] data = buffer.unsafeBytes();
265
+ // get a copy of the bytes, since it may not start at 0
266
+ // FIXME: figure out how to just use the bytes in-place
267
+ byte[] data = buffer.bytes();
266
268
  parser.buffer = buffer;
267
269
 
268
270
 
269
- // line 270 "ext/http11/org/jruby/mongrel/Http11Parser.java"
271
+ // line 272 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
270
272
  {
271
273
  int _klen;
272
274
  int _trans = 0;
@@ -347,29 +349,29 @@ case 1:
347
349
  switch ( _http_parser_actions[_acts++] )
348
350
  {
349
351
  case 0:
350
- // line 13 "ext/http11/http11_parser.java.rl"
352
+ // line 13 "ext/puma_http11/http11_parser.java.rl"
351
353
  {parser.mark = p; }
352
354
  break;
353
355
  case 1:
354
- // line 15 "ext/http11/http11_parser.java.rl"
356
+ // line 15 "ext/puma_http11/http11_parser.java.rl"
355
357
  { parser.field_start = p; }
356
358
  break;
357
359
  case 2:
358
- // line 16 "ext/http11/http11_parser.java.rl"
360
+ // line 16 "ext/puma_http11/http11_parser.java.rl"
359
361
  { /* FIXME stub */ }
360
362
  break;
361
363
  case 3:
362
- // line 17 "ext/http11/http11_parser.java.rl"
364
+ // line 17 "ext/puma_http11/http11_parser.java.rl"
363
365
  {
364
366
  parser.field_len = p-parser.field_start;
365
367
  }
366
368
  break;
367
369
  case 4:
368
- // line 21 "ext/http11/http11_parser.java.rl"
370
+ // line 21 "ext/puma_http11/http11_parser.java.rl"
369
371
  { parser.mark = p; }
370
372
  break;
371
373
  case 5:
372
- // line 22 "ext/http11/http11_parser.java.rl"
374
+ // line 22 "ext/puma_http11/http11_parser.java.rl"
373
375
  {
374
376
  if(parser.http_field != null) {
375
377
  parser.http_field.call(parser.data, parser.field_start, parser.field_len, parser.mark, p-parser.mark);
@@ -377,53 +379,53 @@ case 1:
377
379
  }
378
380
  break;
379
381
  case 6:
380
- // line 27 "ext/http11/http11_parser.java.rl"
382
+ // line 27 "ext/puma_http11/http11_parser.java.rl"
381
383
  {
382
384
  if(parser.request_method != null)
383
385
  parser.request_method.call(parser.data, parser.mark, p-parser.mark);
384
386
  }
385
387
  break;
386
388
  case 7:
387
- // line 31 "ext/http11/http11_parser.java.rl"
389
+ // line 31 "ext/puma_http11/http11_parser.java.rl"
388
390
  {
389
391
  if(parser.request_uri != null)
390
392
  parser.request_uri.call(parser.data, parser.mark, p-parser.mark);
391
393
  }
392
394
  break;
393
395
  case 8:
394
- // line 35 "ext/http11/http11_parser.java.rl"
396
+ // line 35 "ext/puma_http11/http11_parser.java.rl"
395
397
  {
396
398
  if(parser.fragment != null)
397
399
  parser.fragment.call(parser.data, parser.mark, p-parser.mark);
398
400
  }
399
401
  break;
400
402
  case 9:
401
- // line 40 "ext/http11/http11_parser.java.rl"
403
+ // line 40 "ext/puma_http11/http11_parser.java.rl"
402
404
  {parser.query_start = p; }
403
405
  break;
404
406
  case 10:
405
- // line 41 "ext/http11/http11_parser.java.rl"
407
+ // line 41 "ext/puma_http11/http11_parser.java.rl"
406
408
  {
407
409
  if(parser.query_string != null)
408
410
  parser.query_string.call(parser.data, parser.query_start, p-parser.query_start);
409
411
  }
410
412
  break;
411
413
  case 11:
412
- // line 46 "ext/http11/http11_parser.java.rl"
414
+ // line 46 "ext/puma_http11/http11_parser.java.rl"
413
415
  {
414
416
  if(parser.http_version != null)
415
417
  parser.http_version.call(parser.data, parser.mark, p-parser.mark);
416
418
  }
417
419
  break;
418
420
  case 12:
419
- // line 51 "ext/http11/http11_parser.java.rl"
421
+ // line 51 "ext/puma_http11/http11_parser.java.rl"
420
422
  {
421
423
  if(parser.request_path != null)
422
424
  parser.request_path.call(parser.data, parser.mark, p-parser.mark);
423
425
  }
424
426
  break;
425
427
  case 13:
426
- // line 56 "ext/http11/http11_parser.java.rl"
428
+ // line 56 "ext/puma_http11/http11_parser.java.rl"
427
429
  {
428
430
  parser.body_start = p + 1;
429
431
  if(parser.header_done != null)
@@ -431,7 +433,7 @@ case 1:
431
433
  { p += 1; _goto_targ = 5; if (true) continue _goto;}
432
434
  }
433
435
  break;
434
- // line 435 "ext/http11/org/jruby/mongrel/Http11Parser.java"
436
+ // line 437 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
435
437
  }
436
438
  }
437
439
  }
@@ -451,7 +453,7 @@ case 5:
451
453
  break; }
452
454
  }
453
455
 
454
- // line 128 "ext/http11/http11_parser.java.rl"
456
+ // line 130 "ext/puma_http11/http11_parser.java.rl"
455
457
 
456
458
  parser.cs = cs;
457
459
  parser.nread += (p - off);
@@ -4,6 +4,8 @@ require 'uri'
4
4
  require 'puma/server'
5
5
  require 'puma/const'
6
6
 
7
+ require 'rack/commonlogger'
8
+
7
9
  module Puma
8
10
  class CLI
9
11
  DefaultTCPHost = "0.0.0.0"
@@ -31,12 +33,25 @@ module Puma
31
33
  def setup_options
32
34
  @options = {
33
35
  :min_threads => 0,
34
- :max_threads => 16
36
+ :max_threads => 16,
37
+ :quiet => false
35
38
  }
36
39
 
37
40
  @binds = []
38
41
 
39
42
  @parser = OptionParser.new do |o|
43
+ o.on "-b", "--bind URI", "URI to bind to (tcp:// and unix:// only)" do |arg|
44
+ @binds << arg
45
+ end
46
+
47
+ o.on "--pidfile PATH", "Use PATH as a pidfile" do |arg|
48
+ @options[:pidfile] = arg
49
+ end
50
+
51
+ o.on "-q", "--quiet", "Quiet down the output" do
52
+ @options[:quiet] = true
53
+ end
54
+
40
55
  o.on '-t', '--threads INT', "min:max threads to use (default 0:16)" do |arg|
41
56
  min, max = arg.split(":")
42
57
  if max
@@ -48,9 +63,6 @@ module Puma
48
63
  end
49
64
  end
50
65
 
51
- o.on "-b", "--bind URI", "URI to bind to (tcp:// and unix:// only)" do |arg|
52
- @binds << arg
53
- end
54
66
  end
55
67
 
56
68
  @parser.banner = "puma <options> <rackup file>"
@@ -72,8 +84,20 @@ module Puma
72
84
  end
73
85
  end
74
86
 
75
- def run
87
+ def write_pid
88
+ if path = @options[:pidfile]
89
+ File.open(path, "w") do |f|
90
+ f.puts Process.pid
91
+ end
92
+ end
93
+ end
94
+
95
+ def parse_options
76
96
  @parser.parse! @argv
97
+ end
98
+
99
+ def run
100
+ parse_options
77
101
 
78
102
  @rackup = ARGV.shift || "config.ru"
79
103
 
@@ -82,6 +106,11 @@ module Puma
82
106
  end
83
107
 
84
108
  load_rackup
109
+ write_pid
110
+
111
+ unless @quiet
112
+ @app = Rack::CommonLogger.new(@app, STDOUT)
113
+ end
85
114
 
86
115
  if @binds.empty?
87
116
  @options[:Host] ||= DefaultTCPHost
@@ -125,7 +154,11 @@ module Puma
125
154
 
126
155
  log "Use Ctrl-C to stop"
127
156
 
128
- server.run.join
157
+ begin
158
+ server.run.join
159
+ rescue Interrupt
160
+ log " - Shutting down..."
161
+ end
129
162
  end
130
163
  end
131
164
  end
@@ -71,7 +71,7 @@ module Puma
71
71
 
72
72
  PATH_INFO = 'PATH_INFO'.freeze
73
73
 
74
- PUMA_VERSION = VERSION = "0.8.1".freeze
74
+ PUMA_VERSION = VERSION = "0.8.2".freeze
75
75
 
76
76
  PUMA_TMP_BASE = "puma".freeze
77
77
 
@@ -0,0 +1,22 @@
1
+ require 'rack/commonlogger'
2
+
3
+ module Rack
4
+ # Patch CommonLogger to use after_reply
5
+ class CommonLogger
6
+ remove_method :call
7
+
8
+ def call(env)
9
+ began_at = Time.now
10
+ status, header, body = @app.call(env)
11
+ header = Utils::HeaderHash.new(header)
12
+
13
+ if ary = env['rack.after_reply']
14
+ ary << lambda { log(env, status, header, began_at) }
15
+ else
16
+ body = BodyProxy.new(body) { log(env, status, header, began_at) }
17
+ end
18
+
19
+ [status, header, body]
20
+ end
21
+ end
22
+ end
@@ -142,7 +142,11 @@ module Puma
142
142
  nparsed = parser.execute(env, data, nparsed)
143
143
 
144
144
  if parser.finished?
145
- return unless handle_request env, client, parser.body
145
+ cl = env[CONTENT_LENGTH]
146
+
147
+ return unless handle_request(env, client, parser.body, cl)
148
+
149
+ nparsed += parser.body.size if cl
146
150
 
147
151
  if data.size > nparsed
148
152
  data.slice!(0, nparsed)
@@ -219,12 +223,15 @@ module Puma
219
223
  env[REMOTE_ADDR] = client.peeraddr.last
220
224
  end
221
225
 
222
- def handle_request(env, client, body)
226
+ def handle_request(env, client, body, cl)
223
227
  normalize_env env, client
224
228
 
225
- body = read_body env, client, body
226
-
227
- return false unless body
229
+ if cl
230
+ body = read_body env, client, body, cl
231
+ return false unless body
232
+ else
233
+ body = StringIO.new("")
234
+ end
228
235
 
229
236
  env["rack.input"] = body
230
237
  env["rack.url_scheme"] = env["HTTPS"] ? "https" : "http"
@@ -325,8 +332,8 @@ module Puma
325
332
  return keep_alive
326
333
  end
327
334
 
328
- def read_body(env, client, body)
329
- content_length = env[CONTENT_LENGTH].to_i
335
+ def read_body(env, client, body, cl)
336
+ content_length = cl.to_i
330
337
 
331
338
  remain = content_length - body.size
332
339
 
@@ -4,13 +4,27 @@ require 'puma'
4
4
  module Rack
5
5
  module Handler
6
6
  module Puma
7
- DEFAULT_OPTIONS = {:Host => '0.0.0.0', :Port => 8080, :Threads => '0:16'}
7
+ DEFAULT_OPTIONS = {
8
+ :Host => '0.0.0.0',
9
+ :Port => 8080,
10
+ :Threads => '0:16',
11
+ :Quiet => false
12
+ }
8
13
 
9
14
  def self.run(app, options = {})
10
15
  options = DEFAULT_OPTIONS.merge(options)
16
+
17
+ unless options[:Quiet]
18
+ app = Rack::CommonLogger.new(app, STDOUT)
19
+ end
20
+
11
21
  server = ::Puma::Server.new(app)
12
22
  min, max = options[:Threads].split(':', 2)
13
23
 
24
+ puts "Puma #{::Puma::Const::PUMA_VERSION} starting..."
25
+ puts "* Min threads: #{min}, max threads: #{max}"
26
+ puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}"
27
+
14
28
  server.add_tcp_listener options[:Host], options[:Port]
15
29
  server.min_threads = Integer(min)
16
30
  server.max_threads = Integer(max)
@@ -23,7 +37,8 @@ module Rack
23
37
  {
24
38
  "Host=HOST" => "Hostname to listen on (default: localhost)",
25
39
  "Port=PORT" => "Port to listen on (default: 8080)",
26
- "Threads=MIN:MAX" => "min:max threads to use (default 0:16)"
40
+ "Threads=MIN:MAX" => "min:max threads to use (default 0:16)",
41
+ "Quiet" => "Don't report each request"
27
42
  }
28
43
  end
29
44
  end
@@ -2,38 +2,38 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "puma"
5
- s.version = "0.8.1"
5
+ s.version = "0.8.2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Evan Phoenix"]
9
- s.date = "2011-10-25"
9
+ s.date = "2011-11-22"
10
10
  s.description = "Puma is a small library that provides a very fast and concurrent HTTP 1.1 server for Ruby web applications. It is designed for running rack apps only.\n\nWhat makes Puma so fast is the careful use of an Ragel extension to provide fast, accurate HTTP 1.1 protocol parsing. This makes the server scream without too many portability issues."
11
11
  s.email = ["evan@phx.io"]
12
12
  s.executables = ["puma"]
13
13
  s.extensions = ["ext/puma_http11/extconf.rb"]
14
14
  s.extra_rdoc_files = ["History.txt", "Manifest.txt"]
15
- s.files = ["COPYING", "History.txt", "LICENSE", "Manifest.txt", "README.md", "Rakefile", "TODO", "bin/puma", "examples/builder.rb", "examples/camping/README", "examples/camping/blog.rb", "examples/camping/tepee.rb", "examples/httpd.conf", "examples/mime.yaml", "examples/mongrel.conf", "examples/monitrc", "examples/random_thrash.rb", "examples/simpletest.rb", "examples/webrick_compare.rb", "ext/puma_http11/Http11Service.java", "ext/puma_http11/ext_help.h", "ext/puma_http11/extconf.rb", "ext/puma_http11/puma_http11.c", "ext/puma_http11/http11_parser.c", "ext/puma_http11/http11_parser.h", "ext/puma_http11/http11_parser.java.rl", "ext/puma_http11/http11_parser.rl", "ext/puma_http11/http11_parser_common.rl", "ext/puma_http11/org/jruby/mongrel/Http11.java", "ext/puma_http11/org/jruby/mongrel/Http11Parser.java", "lib/puma.rb", "lib/puma/cli.rb", "lib/puma/const.rb", "lib/puma/events.rb", "lib/puma/gems.rb", "lib/puma/mime_types.yml", "lib/puma/server.rb", "lib/puma/thread_pool.rb", "lib/puma/utils.rb", "lib/rack/handler/puma.rb", "puma.gemspec", "tasks/gem.rake", "tasks/java.rake", "tasks/native.rake", "tasks/ragel.rake", "test/lobster.ru", "test/mime.yaml", "test/test_http10.rb", "test/test_http11.rb", "test/test_persistent.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb", "test/testhelp.rb", "tools/trickletest.rb", ".gemtest"]
15
+ s.files = ["COPYING", "Gemfile", "History.txt", "LICENSE", "Manifest.txt", "README.md", "Rakefile", "TODO", "bin/puma", "examples/builder.rb", "examples/camping/README", "examples/camping/blog.rb", "examples/camping/tepee.rb", "examples/httpd.conf", "examples/mime.yaml", "examples/mongrel.conf", "examples/monitrc", "examples/random_thrash.rb", "examples/simpletest.rb", "examples/webrick_compare.rb", "ext/puma_http11/PumaHttp11Service.java", "ext/puma_http11/ext_help.h", "ext/puma_http11/extconf.rb", "ext/puma_http11/http11_parser.c", "ext/puma_http11/http11_parser.h", "ext/puma_http11/http11_parser.java.rl", "ext/puma_http11/http11_parser.rl", "ext/puma_http11/http11_parser_common.rl", "ext/puma_http11/org/jruby/puma/Http11.java", "ext/puma_http11/org/jruby/puma/Http11Parser.java", "ext/puma_http11/puma_http11.c", "lib/puma.rb", "lib/puma/cli.rb", "lib/puma/const.rb", "lib/puma/events.rb", "lib/puma/gems.rb", "lib/puma/mime_types.yml", "lib/puma/rack_patch.rb", "lib/puma/server.rb", "lib/puma/thread_pool.rb", "lib/puma/utils.rb", "lib/rack/handler/puma.rb", "puma.gemspec", "tasks/gem.rake", "tasks/java.rake", "tasks/native.rake", "tasks/ragel.rake", "test/lobster.ru", "test/mime.yaml", "test/test_cli.rb", "test/test_http10.rb", "test/test_http11.rb", "test/test_persistent.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb", "test/testhelp.rb", "tools/trickletest.rb", ".gemtest"]
16
16
  s.rdoc_options = ["--main", "README.md"]
17
17
  s.require_paths = ["lib"]
18
18
  s.rubyforge_project = "puma"
19
19
  s.rubygems_version = "1.8.10"
20
20
  s.summary = "Puma is a small library that provides a very fast and concurrent HTTP 1.1 server for Ruby web applications"
21
- s.test_files = ["test/test_http10.rb", "test/test_http11.rb", "test/test_persistent.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb"]
21
+ s.test_files = ["test/test_cli.rb", "test/test_http10.rb", "test/test_http11.rb", "test/test_persistent.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb"]
22
22
 
23
23
  if s.respond_to? :specification_version then
24
24
  s.specification_version = 3
25
25
 
26
26
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
27
- s.add_runtime_dependency(%q<rack>, ["~> 1.3"])
27
+ s.add_runtime_dependency(%q<rack>, ["~> 1.2"])
28
28
  s.add_development_dependency(%q<rake-compiler>, ["~> 0.7.0"])
29
29
  s.add_development_dependency(%q<hoe>, ["~> 2.10"])
30
30
  else
31
- s.add_dependency(%q<rack>, ["~> 1.3"])
31
+ s.add_dependency(%q<rack>, ["~> 1.2"])
32
32
  s.add_dependency(%q<rake-compiler>, ["~> 0.7.0"])
33
33
  s.add_dependency(%q<hoe>, ["~> 2.10"])
34
34
  end
35
35
  else
36
- s.add_dependency(%q<rack>, ["~> 1.3"])
36
+ s.add_dependency(%q<rack>, ["~> 1.2"])
37
37
  s.add_dependency(%q<rake-compiler>, ["~> 0.7.0"])
38
38
  s.add_dependency(%q<hoe>, ["~> 2.10"])
39
39
  end
@@ -8,7 +8,7 @@ HOE = Hoe.spec 'puma' do
8
8
  spec_extras[:extensions] = ["ext/puma_http11/extconf.rb"]
9
9
  spec_extras[:executables] = ['puma']
10
10
 
11
- dependency 'rack', '~> 1.3'
11
+ dependency 'rack', '~> 1.2'
12
12
 
13
13
  extra_dev_deps << ['rake-compiler', "~> 0.7.0"]
14
14
 
@@ -1,9 +1,9 @@
1
- if ENV['JAVA']
1
+ if IS_JRUBY
2
2
 
3
3
  require 'rake/javaextensiontask'
4
4
 
5
5
  # build http11 java extension
6
- Rake::JavaExtensionTask.new('http11', HOE.spec) do |ext|
6
+ Rake::JavaExtensionTask.new('puma_http11', HOE.spec) do |ext|
7
7
  ext.java_compiling do |gs|
8
8
  gs.dependencies.delete gs.dependencies.find { |d| d.name == 'daemons' }
9
9
  end
@@ -1,25 +1,36 @@
1
- # use rake-compiler for building the extension
2
- require 'rake/extensiontask'
3
-
4
- # build http11 C extension
5
- Rake::ExtensionTask.new('puma_http11', HOE.spec) do |ext|
6
- # define target for extension (supporting fat binaries)
7
- if RUBY_PLATFORM =~ /mingw|mswin/ then
8
- RUBY_VERSION =~ /(\d+\.\d+)/
9
- ext.lib_dir = "lib/#{$1}"
10
- elsif ENV['CROSS']
11
- # define cross-compilation tasks when not on Windows.
12
- ext.cross_compile = true
13
- ext.cross_platform = ['i386-mswin32', 'i386-mingw32']
14
-
15
- ext.cross_compiling do |gs|
16
- gs.dependencies.delete gs.dependencies.find { |d| d.name == 'daemons' }
1
+ unless IS_JRUBY
2
+
3
+ # use rake-compiler for building the extension
4
+ require 'rake/extensiontask'
5
+
6
+ # build http11 C extension
7
+ Rake::ExtensionTask.new('puma_http11', HOE.spec) do |ext|
8
+ # define target for extension (supporting fat binaries)
9
+ if RUBY_PLATFORM =~ /mingw|mswin/ then
10
+ RUBY_VERSION =~ /(\d+\.\d+)/
11
+ ext.lib_dir = "lib/#{$1}"
12
+ elsif ENV['CROSS']
13
+ # define cross-compilation tasks when not on Windows.
14
+ ext.cross_compile = true
15
+ ext.cross_platform = ['i386-mswin32', 'i386-mingw32']
16
+
17
+ ext.cross_compiling do |gs|
18
+ gs.dependencies.delete gs.dependencies.find { |d| d.name == 'daemons' }
19
+ end
17
20
  end
21
+
22
+ # cleanup versioned library directory
23
+ CLEAN.include 'lib/{1.8,1.9}'
18
24
  end
25
+ end
19
26
 
20
- # cleanup versioned library directory
21
- CLEAN.include 'lib/{1.8,1.9}'
27
+ task :ext_clean do
28
+ sh "rm -rf lib/puma_http11.bundle"
29
+ sh "rm -rf lib/puma_http11.jar"
30
+ sh "rm -rf lib/puma_http11.so"
22
31
  end
23
32
 
24
33
  # ensure things are built prior testing
25
34
  task :test => [:compile]
35
+
36
+ task :clean => :ext_clean
@@ -1,7 +1,7 @@
1
1
 
2
2
  # the following tasks ease the build of C file from Ragel one
3
3
 
4
- file 'ext/http11/http11_parser.c' => ['ext/http11/http11_parser.rl'] do |t|
4
+ file 'ext/puma_http11/http11_parser.c' => ['ext/puma_http11/http11_parser.rl'] do |t|
5
5
  begin
6
6
  sh "ragel #{t.prerequisites.last} -C -G2 -o #{t.name}"
7
7
  rescue
@@ -9,7 +9,7 @@ file 'ext/http11/http11_parser.c' => ['ext/http11/http11_parser.rl'] do |t|
9
9
  end
10
10
  end
11
11
 
12
- file 'ext/http11/org/jruby/puma/Http11Parser.java' => ['ext/http11/http11_parser.java.rl'] do |t|
12
+ file 'ext/puma_http11/org/jruby/puma/Http11Parser.java' => ['ext/puma_http11/http11_parser.java.rl'] do |t|
13
13
  begin
14
14
  sh "ragel #{t.prerequisites.last} -J -G2 -o #{t.name}"
15
15
  rescue
@@ -17,4 +17,8 @@ file 'ext/http11/org/jruby/puma/Http11Parser.java' => ['ext/http11/http11_parser
17
17
  end
18
18
  end
19
19
 
20
- task :ragel => (defined?(JRUBY_VERSION) ? 'ext/http11/org/jruby/puma/Http11Parser.java' : 'ext/http11/http11_parser.c')
20
+ if IS_JRUBY
21
+ task :ragel => 'ext/puma_http11/org/jruby/puma/Http11Parser.java'
22
+ else
23
+ task :ragel => 'ext/puma_http11/http11_parser.c'
24
+ end
@@ -0,0 +1,19 @@
1
+ require 'test/unit'
2
+ require 'puma/cli'
3
+ require 'tempfile'
4
+
5
+ class TestCLI < Test::Unit::TestCase
6
+ def setup
7
+ @pid_file = Tempfile.new("puma-test")
8
+ @pid_path = @pid_file.path
9
+ @pid_file.close!
10
+ end
11
+
12
+ def test_pid_file
13
+ cli = Puma::CLI.new ["--pidfile", @pid_path]
14
+ cli.parse_options
15
+ cli.write_pid
16
+
17
+ assert_equal File.read(@pid_path).strip.to_i, Process.pid
18
+ end
19
+ end
@@ -1,5 +1,6 @@
1
1
  require 'puma'
2
2
  require 'test/unit'
3
+ require 'timeout'
3
4
 
4
5
  class TestPersistent < Test::Unit::TestCase
5
6
  def setup
@@ -8,9 +9,17 @@ class TestPersistent < Test::Unit::TestCase
8
9
  @http10_request = "GET / HTTP/1.0\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
9
10
  @keep_request = "GET / HTTP/1.0\r\nHost: test.com\r\nContent-Type: text/plain\r\nConnection: Keep-Alive\r\n\r\n"
10
11
 
12
+ @valid_post = "POST / HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\nContent-Length: 5\r\n\r\nhello"
13
+
11
14
  @headers = { "X-Header" => "Works" }
12
15
  @body = ["Hello"]
13
- @simple = lambda { |env| [200, @headers, @body] }
16
+ @inputs = []
17
+
18
+ @simple = lambda do |env|
19
+ @inputs << env['rack.input']
20
+ [200, @headers, @body]
21
+ end
22
+
14
23
  @server = Puma::Server.new @simple
15
24
  @server.add_tcp_listener "127.0.0.1", 9988
16
25
  @server.run
@@ -25,7 +34,9 @@ class TestPersistent < Test::Unit::TestCase
25
34
 
26
35
  def lines(count, s=@client)
27
36
  str = ""
28
- count.times { str << s.gets }
37
+ timeout(5) do
38
+ count.times { str << s.gets }
39
+ end
29
40
  str
30
41
  end
31
42
 
@@ -51,6 +62,20 @@ class TestPersistent < Test::Unit::TestCase
51
62
  assert_equal "Hello", @client.read(5)
52
63
  end
53
64
 
65
+ def test_post_then_get
66
+ @client << @valid_post
67
+ sz = @body[0].size.to_s
68
+
69
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
70
+ assert_equal "Hello", @client.read(5)
71
+
72
+ @client << @valid_request
73
+ sz = @body[0].size.to_s
74
+
75
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
76
+ assert_equal "Hello", @client.read(5)
77
+ end
78
+
54
79
  def test_chunked
55
80
  @body << "Chunked"
56
81
 
@@ -156,4 +181,25 @@ class TestPersistent < Test::Unit::TestCase
156
181
  assert_equal "Hello", @client.read(5)
157
182
  end
158
183
 
184
+ def test_second_request_not_in_first_req_body
185
+ @server.persistent_timeout = 3
186
+
187
+ req = @valid_request.to_s
188
+ req << "GET /second HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
189
+
190
+ @client << req
191
+
192
+ sz = @body[0].size.to_s
193
+
194
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
195
+ assert_equal "Hello", @client.read(5)
196
+
197
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
198
+ assert_equal "Hello", @client.read(5)
199
+
200
+ assert_equal "", @inputs[0].string
201
+ assert_equal "", @inputs[1].string
202
+
203
+ end
204
+
159
205
  end
@@ -47,10 +47,17 @@ class TestRackServer < Test::Unit::TestCase
47
47
  @simple = lambda { |env| [200, { "X-Header" => "Works" }, ["Hello"]] }
48
48
  @server = Puma::Server.new @simple
49
49
  @server.add_tcp_listener "127.0.0.1", 9998
50
+
51
+ @stopped = false
50
52
  end
51
53
 
52
- def teardown
54
+ def stop
53
55
  @server.stop(true)
56
+ @stopped = true
57
+ end
58
+
59
+ def teardown
60
+ @server.stop(true) unless @stopped
54
61
  end
55
62
 
56
63
  def test_lint
@@ -102,6 +109,8 @@ class TestRackServer < Test::Unit::TestCase
102
109
 
103
110
  hit(['http://localhost:9998/test'])
104
111
 
112
+ stop
113
+
105
114
  assert_match %r!GET /test HTTP/1\.1!, log.string
106
115
  end
107
116
  end
@@ -3,32 +3,35 @@ require 'puma/server'
3
3
 
4
4
  require 'socket'
5
5
 
6
- class TestPumaUnixSocket < Test::Unit::TestCase
7
-
8
- App = lambda { |env| [200, {}, ["Works"]] }
9
-
10
- Path = "test/puma.sock"
11
-
12
- def setup
13
- @server = Puma::Server.new App
14
- @server.add_unix_listener Path
15
- @server.run
16
- end
17
-
18
- def teardown
19
- @server.stop(true)
20
- File.unlink Path if File.exists? Path
21
- end
22
-
23
- def test_server
24
- sock = UNIXSocket.new Path
25
-
26
- sock << "GET / HTTP/1.0\r\nHost: blah.com\r\n\r\n"
27
-
28
- expected = "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Length: 5\r\n\r\nWorks"
29
-
30
- assert_equal expected, sock.read(expected.size)
31
-
32
- sock.close
6
+ # UNIX sockets are not recommended on JRuby
7
+ unless defined?(JRUBY_VERSION)
8
+ class TestPumaUnixSocket < Test::Unit::TestCase
9
+
10
+ App = lambda { |env| [200, {}, ["Works"]] }
11
+
12
+ Path = "test/puma.sock"
13
+
14
+ def setup
15
+ @server = Puma::Server.new App
16
+ @server.add_unix_listener Path
17
+ @server.run
18
+ end
19
+
20
+ def teardown
21
+ @server.stop(true)
22
+ File.unlink Path if File.exists? Path
23
+ end
24
+
25
+ def test_server
26
+ sock = UNIXSocket.new Path
27
+
28
+ sock << "GET / HTTP/1.0\r\nHost: blah.com\r\n\r\n"
29
+
30
+ expected = "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Length: 5\r\n\r\nWorks"
31
+
32
+ assert_equal expected, sock.read(expected.size)
33
+
34
+ sock.close
35
+ end
33
36
  end
34
- end
37
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- hash: 61
4
+ hash: 59
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 8
9
- - 1
10
- version: 0.8.1
9
+ - 2
10
+ version: 0.8.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Evan Phoenix
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-10-25 00:00:00 Z
18
+ date: 2011-11-22 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rack
@@ -25,11 +25,11 @@ dependencies:
25
25
  requirements:
26
26
  - - ~>
27
27
  - !ruby/object:Gem::Version
28
- hash: 9
28
+ hash: 11
29
29
  segments:
30
30
  - 1
31
- - 3
32
- version: "1.3"
31
+ - 2
32
+ version: "1.2"
33
33
  type: :runtime
34
34
  version_requirements: *id001
35
35
  - !ruby/object:Gem::Dependency
@@ -78,6 +78,7 @@ extra_rdoc_files:
78
78
  - Manifest.txt
79
79
  files:
80
80
  - COPYING
81
+ - Gemfile
81
82
  - History.txt
82
83
  - LICENSE
83
84
  - Manifest.txt
@@ -96,23 +97,24 @@ files:
96
97
  - examples/random_thrash.rb
97
98
  - examples/simpletest.rb
98
99
  - examples/webrick_compare.rb
99
- - ext/puma_http11/Http11Service.java
100
+ - ext/puma_http11/PumaHttp11Service.java
100
101
  - ext/puma_http11/ext_help.h
101
102
  - ext/puma_http11/extconf.rb
102
- - ext/puma_http11/puma_http11.c
103
103
  - ext/puma_http11/http11_parser.c
104
104
  - ext/puma_http11/http11_parser.h
105
105
  - ext/puma_http11/http11_parser.java.rl
106
106
  - ext/puma_http11/http11_parser.rl
107
107
  - ext/puma_http11/http11_parser_common.rl
108
- - ext/puma_http11/org/jruby/mongrel/Http11.java
109
- - ext/puma_http11/org/jruby/mongrel/Http11Parser.java
108
+ - ext/puma_http11/org/jruby/puma/Http11.java
109
+ - ext/puma_http11/org/jruby/puma/Http11Parser.java
110
+ - ext/puma_http11/puma_http11.c
110
111
  - lib/puma.rb
111
112
  - lib/puma/cli.rb
112
113
  - lib/puma/const.rb
113
114
  - lib/puma/events.rb
114
115
  - lib/puma/gems.rb
115
116
  - lib/puma/mime_types.yml
117
+ - lib/puma/rack_patch.rb
116
118
  - lib/puma/server.rb
117
119
  - lib/puma/thread_pool.rb
118
120
  - lib/puma/utils.rb
@@ -124,6 +126,7 @@ files:
124
126
  - tasks/ragel.rake
125
127
  - test/lobster.ru
126
128
  - test/mime.yaml
129
+ - test/test_cli.rb
127
130
  - test/test_http10.rb
128
131
  - test/test_http11.rb
129
132
  - test/test_persistent.rb
@@ -170,6 +173,7 @@ signing_key:
170
173
  specification_version: 3
171
174
  summary: Puma is a small library that provides a very fast and concurrent HTTP 1.1 server for Ruby web applications
172
175
  test_files:
176
+ - test/test_cli.rb
173
177
  - test/test_http10.rb
174
178
  - test/test_http11.rb
175
179
  - test/test_persistent.rb