rainbows 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.manifest CHANGED
@@ -34,6 +34,7 @@ lib/rainbows/const.rb
34
34
  lib/rainbows/dev_fd_response.rb
35
35
  lib/rainbows/error.rb
36
36
  lib/rainbows/ev_core.rb
37
+ lib/rainbows/ev_core/cap_input.rb
37
38
  lib/rainbows/event_machine.rb
38
39
  lib/rainbows/event_machine/response_chunk_pipe.rb
39
40
  lib/rainbows/event_machine/response_pipe.rb
@@ -183,6 +184,7 @@ t/t0102-rack-input-short.sh
183
184
  t/t0103-rack-input-limit.sh
184
185
  t/t0104-rack-input-limit-tiny.sh
185
186
  t/t0105-rack-input-limit-bigger.sh
187
+ t/t0106-rack-input-keepalive.sh
186
188
  t/t0200-async-response.sh
187
189
  t/t0201-async-response-no-autochunk.sh
188
190
  t/t0300-async_sinatra.sh
data/ChangeLog CHANGED
@@ -1,5 +1,42 @@
1
- ChangeLog from git://git.bogomips.org/rainbows.git (v0.97.0..v2.0.0)
1
+ ChangeLog from git://git.bogomips.org/rainbows.git (v0.97.0..v2.0.1)
2
2
 
3
+ commit b4835c6d542c6369f2523ab68fc41b0202d7c6dc
4
+ Author: Eric Wong <normalperson@yhbt.net>
5
+ Date: Fri Dec 3 01:23:11 2010 +0000
6
+
7
+ Rainbows! 2.0.1 - upload pipelining fixes
8
+
9
+ For HTTP clients living on the edge and pipelining uploads, we
10
+ now fully support pipelined requests (as long as the application
11
+ consumes each request in its entirety).
12
+
13
+ commit c096e735efea5050b0559748633403f0387ea3b3
14
+ Author: Eric Wong <normalperson@yhbt.net>
15
+ Date: Fri Dec 3 01:12:08 2010 +0000
16
+
17
+ fix pipelining of requests with bodies
18
+
19
+ All synchronous models have this fixed in unicorn 3.0.1,
20
+ so only Rev and EventMachine-based concurrency models
21
+ require code changes.
22
+
23
+ commit 64889d9136fa5466269232c26a2f235dd763d8f0
24
+ Author: Eric Wong <normalperson@yhbt.net>
25
+ Date: Thu Dec 2 07:38:14 2010 +0000
26
+
27
+ ev_core: refactor and split cap_input out
28
+
29
+ Hopefully it makes more sense now and is easier to
30
+ digest for new hackers.
31
+
32
+ commit 945b5760d86b9dd00e65bd0625b98cf75f6a8257
33
+ Author: Eric Wong <normalperson@yhbt.net>
34
+ Date: Wed Dec 1 21:29:34 2010 -0800
35
+
36
+ ev_core: split out prepare_request_body
37
+
38
+ We may have other uses for this in the future...
39
+
3
40
  commit 90789761f0cc78d3726f3a2eda1c5fe95c015ac2
4
41
  Author: Eric Wong <normalperson@yhbt.net>
5
42
  Date: Fri Nov 19 19:09:59 2010 -0800
data/GIT-VERSION-FILE CHANGED
@@ -1 +1 @@
1
- GIT_VERSION = 2.0.0
1
+ GIT_VERSION = 2.0.1
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v2.0.0.GIT
4
+ DEF_VER=v2.0.1.GIT
5
5
 
6
6
  LF='
7
7
  '
data/NEWS CHANGED
@@ -1,3 +1,9 @@
1
+ === 2.0.1 / 2010-12-03 01:26 UTC
2
+
3
+ For HTTP clients living on the edge and pipelining uploads, we
4
+ now fully support pipelined requests (as long as the application
5
+ consumes each request in its entirety).
6
+
1
7
  === 2.0.0 / 2010-11-20 03:10 UTC
2
8
 
3
9
  This release is targeted at the minority of web applications
@@ -2,7 +2,7 @@
2
2
  # :enddoc:
3
3
  module Rainbows::Const
4
4
 
5
- RAINBOWS_VERSION = '2.0.0'
5
+ RAINBOWS_VERSION = '2.0.1'
6
6
 
7
7
  include Unicorn::Const
8
8
 
@@ -7,6 +7,7 @@ module Rainbows::EvCore
7
7
  G = Rainbows::G
8
8
  NULL_IO = Unicorn::HttpRequest::NULL_IO
9
9
  HttpParser = Unicorn::HttpParser
10
+ autoload :CapInput, 'rainbows/ev_core/cap_input'
10
11
 
11
12
  # Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ]
12
13
  ASYNC_CALLBACK = "async.callback".freeze
@@ -25,6 +26,9 @@ module Rainbows::EvCore
25
26
  @state = :close
26
27
  end
27
28
 
29
+ def want_more
30
+ end
31
+
28
32
  def handle_error(e)
29
33
  msg = Rainbows::Error.response(e) and write(msg)
30
34
  ensure
@@ -43,33 +47,41 @@ module Rainbows::EvCore
43
47
  rv
44
48
  end
45
49
 
50
+ def prepare_request_body
51
+ # since we don't do streaming input, we have no choice but
52
+ # to take over 100-continue handling from the Rack application
53
+ if @env[HTTP_EXPECT] =~ /\A100-continue\z/i
54
+ write(EXPECT_100_RESPONSE)
55
+ @env.delete(HTTP_EXPECT)
56
+ end
57
+ @input = mkinput
58
+ @hp.filter_body(@buf2 = "", @buf)
59
+ @input << @buf2
60
+ on_read("")
61
+ end
62
+
46
63
  # TeeInput doesn't map too well to this right now...
47
64
  def on_read(data)
48
65
  case @state
49
66
  when :headers
50
67
  @buf << data
51
- @hp.parse or return
68
+ @hp.parse or return want_more
52
69
  @state = :body
53
- len = @hp.content_length
54
- if len == 0
70
+ if 0 == @hp.content_length
55
71
  @input = NULL_IO
56
72
  app_call # common case
57
73
  else # nil or len > 0
58
- # since we don't do streaming input, we have no choice but
59
- # to take over 100-continue handling from the Rack application
60
- if @env[HTTP_EXPECT] =~ /\A100-continue\z/i
61
- write(EXPECT_100_RESPONSE)
62
- @env.delete(HTTP_EXPECT)
63
- end
64
- @input = CapInput.new(len, self)
65
- @hp.filter_body(@buf2 = "", @buf)
66
- @input << @buf2
67
- on_read("")
74
+ prepare_request_body
68
75
  end
69
76
  when :body
70
77
  if @hp.body_eof?
71
- @state = :trailers
72
- on_read(data)
78
+ if @hp.content_length
79
+ @input.rewind
80
+ app_call
81
+ else
82
+ @state = :trailers
83
+ on_read(data)
84
+ end
73
85
  elsif data.size > 0
74
86
  @hp.filter_body(@buf2, @buf << data)
75
87
  @input << @buf2
@@ -79,48 +91,33 @@ module Rainbows::EvCore
79
91
  if @hp.trailers(@env, @buf << data)
80
92
  @input.rewind
81
93
  app_call
94
+ else
95
+ want_more
82
96
  end
83
97
  end
84
98
  rescue => e
85
99
  handle_error(e)
86
100
  end
87
101
 
88
- class CapInput < Struct.new(:io, :client, :bytes_left)
89
- MAX_BODY = Unicorn::Const::MAX_BODY
90
- TmpIO = Unicorn::TmpIO
91
-
92
- def self.err(client, msg)
93
- client.write(Rainbows::Const::ERROR_413_RESPONSE)
94
- client.quit
95
-
96
- # zip back up the stack
97
- raise IOError, msg, []
98
- end
99
-
100
- def self.new(len, client)
101
- max = Rainbows.max_bytes
102
- if len
103
- if max && (len > max)
104
- err(client, "Content-Length too big: #{len} > #{max}")
105
- end
106
- len <= MAX_BODY ? StringIO.new("") : TmpIO.new
107
- else
108
- max ? super(TmpIO.new, client, max) : TmpIO.new
109
- end
110
- end
102
+ def err_413(msg)
103
+ write(Rainbows::Const::ERROR_413_RESPONSE)
104
+ quit
105
+ # zip back up the stack
106
+ raise IOError, msg, []
107
+ end
111
108
 
112
- def <<(buf)
113
- if (self.bytes_left -= buf.size) < 0
114
- io.close
115
- CapInput.err(client, "chunked request body too big")
109
+ MAX_BODY = Unicorn::Const::MAX_BODY
110
+ TmpIO = Unicorn::TmpIO
111
+ def mkinput
112
+ max = Rainbows.max_bytes
113
+ len = @hp.content_length
114
+ if len
115
+ if max && (len > max)
116
+ err_413("Content-Length too big: #{len} > #{max}")
116
117
  end
117
- io << buf
118
+ len <= MAX_BODY ? StringIO.new("") : TmpIO.new
119
+ else
120
+ max ? CapInput.new(TmpIO.new, self) : TmpIO.new
118
121
  end
119
-
120
- def gets; io.gets; end
121
- def each(&block); io.each(&block); end
122
- def size; io.size; end
123
- def rewind; io.rewind; end
124
- def read(*args); io.read(*args); end
125
122
  end
126
123
  end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: binary -*-
2
+ # :enddoc:
3
+ class Rainbows::EvCore::CapInput
4
+ def initialize(io, client)
5
+ @io, @client, @bytes_left = io, client, Rainbows.max_bytes
6
+ end
7
+
8
+ def <<(buf)
9
+ if (@bytes_left -= buf.size) < 0
10
+ @io.close
11
+ @client.err_413("chunked request body too big")
12
+ end
13
+ @io << buf
14
+ end
15
+
16
+ def gets; @io.gets; end
17
+ def each(&block); @io.each(&block); end
18
+ def size; @io.size; end
19
+ def rewind; @io.rewind; end
20
+ def read(*args); @io.read(*args); end
21
+ end
@@ -16,6 +16,10 @@ module Rainbows
16
16
  @deferred = nil
17
17
  end
18
18
 
19
+ def want_more
20
+ enable unless enabled?
21
+ end
22
+
19
23
  def quit
20
24
  super
21
25
  close if @deferred.nil? && @_write_buffer.empty?
@@ -143,13 +147,13 @@ module Rainbows
143
147
  when :close
144
148
  close if @_write_buffer.empty?
145
149
  when :headers
146
- if @hp.parse
147
- app_call
148
- else
150
+ if @buf.empty?
149
151
  unless enabled?
150
152
  enable
151
153
  KATO[self] = Time.now
152
154
  end
155
+ else
156
+ on_read("")
153
157
  end
154
158
  end
155
159
  rescue => e
@@ -0,0 +1,72 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 7 "rack.input pipelining test"
4
+
5
+ t_begin "setup and startup" && {
6
+ rainbows_setup $model
7
+ rtmpfiles req
8
+ rainbows -D sha1.ru -c $unicorn_config
9
+ body=hello
10
+ body_size=$(printf $body | wc -c)
11
+ body_sha1=$(printf $body | rsha1)
12
+ rainbows_wait_start
13
+ }
14
+
15
+ t_begin "send pipelined identity requests" && {
16
+
17
+ {
18
+ printf 'PUT / HTTP/1.0\r\n'
19
+ printf 'Connection: keep-alive\r\n'
20
+ printf 'Content-Length: %d\r\n\r\n%s' $body_size $body
21
+ printf 'PUT / HTTP/1.1\r\nHost: example.com\r\n'
22
+ printf 'Content-Length: %d\r\n\r\n%s' $body_size $body
23
+ printf 'PUT / HTTP/1.0\r\n'
24
+ printf 'Content-Length: %d\r\n\r\n%s' $body_size $body
25
+ } > $req
26
+ (
27
+ cat $fifo > $tmp &
28
+ cat $req
29
+ wait
30
+ echo ok > $ok
31
+ ) | socat - TCP4:$listen > $fifo
32
+ test x"$(cat $ok)" = xok
33
+ }
34
+
35
+ t_begin "check responses" && {
36
+ dbgcat tmp
37
+ test 3 -eq $(grep $body_sha1 $tmp | wc -l)
38
+ }
39
+
40
+ t_begin "send pipelined chunked requests" && {
41
+
42
+ {
43
+ printf 'PUT / HTTP/1.0\r\n'
44
+ printf 'Connection: keep-alive\r\n'
45
+ printf 'Transfer-Encoding: chunked\r\n\r\n'
46
+ printf '%x\r\n%s\r\n0\r\n\r\n' $body_size $body
47
+ printf 'PUT / HTTP/1.1\r\nHost: example.com\r\n'
48
+ printf 'Transfer-Encoding: chunked\r\n\r\n'
49
+ printf '%x\r\n%s\r\n0\r\n\r\n' $body_size $body
50
+ printf 'PUT / HTTP/1.0\r\n'
51
+ printf 'Transfer-Encoding: chunked\r\n\r\n'
52
+ printf '%x\r\n%s\r\n0\r\n\r\n' $body_size $body
53
+ } > $req
54
+ (
55
+ cat $fifo > $tmp &
56
+ cat $req
57
+ wait
58
+ echo ok > $ok
59
+ ) | socat - TCP4:$listen > $fifo
60
+ test x"$(cat $ok)" = xok
61
+ }
62
+
63
+ t_begin "check responses" && {
64
+ dbgcat tmp
65
+ test 3 -eq $(grep $body_sha1 $tmp | wc -l)
66
+ }
67
+
68
+ t_begin "kill server" && kill $rainbows_pid
69
+
70
+ t_begin "no errors in stderr log" && check_stderr
71
+
72
+ t_done
data/t/test_isolate.rb CHANGED
@@ -16,7 +16,7 @@ $stdout.reopen($stderr)
16
16
  Isolate.now!(opts) do
17
17
  gem 'rack', '1.1.0' # Cramp currently requires ~> 1.1.0
18
18
  gem 'kgio', '2.0.0'
19
- gem 'unicorn', '3.0.0'
19
+ gem 'unicorn', '3.0.1'
20
20
  gem 'kcar', '0.1.1'
21
21
 
22
22
  if engine == "ruby"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rainbows
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 13
5
5
  prerelease: false
6
6
  segments:
7
7
  - 2
8
8
  - 0
9
- - 0
10
- version: 2.0.0
9
+ - 1
10
+ version: 2.0.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Rainbows! hackers
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-11-20 00:00:00 +00:00
18
+ date: 2010-12-03 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -88,6 +88,7 @@ extra_rdoc_files:
88
88
  - lib/rainbows/dev_fd_response.rb
89
89
  - lib/rainbows/error.rb
90
90
  - lib/rainbows/ev_core.rb
91
+ - lib/rainbows/ev_core/cap_input.rb
91
92
  - lib/rainbows/event_machine.rb
92
93
  - lib/rainbows/event_machine/response_chunk_pipe.rb
93
94
  - lib/rainbows/event_machine/response_pipe.rb
@@ -192,6 +193,7 @@ files:
192
193
  - lib/rainbows/dev_fd_response.rb
193
194
  - lib/rainbows/error.rb
194
195
  - lib/rainbows/ev_core.rb
196
+ - lib/rainbows/ev_core/cap_input.rb
195
197
  - lib/rainbows/event_machine.rb
196
198
  - lib/rainbows/event_machine/response_chunk_pipe.rb
197
199
  - lib/rainbows/event_machine/response_pipe.rb
@@ -341,6 +343,7 @@ files:
341
343
  - t/t0103-rack-input-limit.sh
342
344
  - t/t0104-rack-input-limit-tiny.sh
343
345
  - t/t0105-rack-input-limit-bigger.sh
346
+ - t/t0106-rack-input-keepalive.sh
344
347
  - t/t0200-async-response.sh
345
348
  - t/t0201-async-response-no-autochunk.sh
346
349
  - t/t0300-async_sinatra.sh