rainbows 2.0.0 → 2.0.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/.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