yahns 1.14.0 → 1.14.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/GIT-VERSION-GEN +1 -1
- data/lib/yahns/http_response.rb +56 -58
- data/lib/yahns/proxy_http_response.rb +1 -1
- data/lib/yahns/queue_epoll.rb +1 -1
- data/lib/yahns/queue_kqueue.rb +1 -1
- data/test/test_auto_chunk.rb +21 -1
- data/test/test_proxy_pass.rb +33 -0
- data/test/test_rack_hijack.rb +6 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 100f23910c77a7e45fdb98c841bf13a166eb0b63
|
4
|
+
data.tar.gz: ea3c7b2801fa134773bc079f637ccf419b5e6ef5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ee178fa9b9b1122a4446353ca6c6f4744aa1589679deef510fe3afeae40f72f66b8ccb96b56476e2e67383b6cd17f10f23c1fedfd81ab588056944e5693fb83
|
7
|
+
data.tar.gz: 1f7a89edf6427deeb0f01b26461c744fa56dc22edc5f84d14eacfb48a50618a5622dcc28e67041843d1ff5de2d6b40c4144b580f044e8770f1e453e268ab10a0
|
data/GIT-VERSION-GEN
CHANGED
data/lib/yahns/http_response.rb
CHANGED
@@ -131,68 +131,66 @@ def http_response_write(res, opt)
|
|
131
131
|
term = false
|
132
132
|
hdr_only, chunk_ok = opt
|
133
133
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
count = $2.to_i - offset + 1
|
148
|
-
end
|
149
|
-
kv_str(buf, key, value)
|
150
|
-
when %r{\AConnection\z}i
|
151
|
-
# allow Rack apps to tell us they want to drop the client
|
152
|
-
alive = false if value =~ /\bclose\b/i
|
153
|
-
when %r{\AContent-Length\z}i
|
154
|
-
term = true
|
155
|
-
clen = value.to_i
|
156
|
-
flags |= MSG_MORE if clen > 0 && !hdr_only
|
157
|
-
kv_str(buf, key, value)
|
158
|
-
when %r{\ATransfer-Encoding\z}i
|
159
|
-
term = true if value =~ /\bchunked\b/i
|
160
|
-
kv_str(buf, key, value)
|
161
|
-
when "rack.hijack"
|
162
|
-
hijack = value
|
163
|
-
else
|
164
|
-
kv_str(buf, key, value)
|
134
|
+
code = status.to_i
|
135
|
+
hdr_only ||= Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(code)
|
136
|
+
msg = Rack::Utils::HTTP_STATUS_CODES[code]
|
137
|
+
buf = "#{response_start}#{msg ? %Q(#{code} #{msg}) : status}\r\n" \
|
138
|
+
"Date: #{httpdate}\r\n".dup
|
139
|
+
headers.each do |key, value|
|
140
|
+
case key
|
141
|
+
when %r{\ADate\z}i
|
142
|
+
next
|
143
|
+
when %r{\AContent-Range\z}i
|
144
|
+
if %r{\Abytes (\d+)-(\d+)/\d+\z} =~ value
|
145
|
+
offset = $1.to_i
|
146
|
+
count = $2.to_i - offset + 1
|
165
147
|
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
148
|
+
kv_str(buf, key, value)
|
149
|
+
when %r{\AConnection\z}i
|
150
|
+
# allow Rack apps to tell us they want to drop the client
|
151
|
+
alive = false if value =~ /\bclose\b/i
|
152
|
+
when %r{\AContent-Length\z}i
|
170
153
|
term = true
|
171
|
-
|
172
|
-
|
154
|
+
clen = value.to_i
|
155
|
+
flags |= MSG_MORE if clen > 0 && !hdr_only
|
156
|
+
kv_str(buf, key, value)
|
157
|
+
when %r{\ATransfer-Encoding\z}i
|
158
|
+
term = true if value =~ /\bchunked\b/i
|
159
|
+
kv_str(buf, key, value)
|
160
|
+
when "rack.hijack"
|
161
|
+
hijack = value
|
162
|
+
else
|
163
|
+
kv_str(buf, key, value)
|
173
164
|
end
|
174
|
-
alive &&= term
|
175
|
-
buf << (alive ? "Connection: keep-alive\r\n\r\n".freeze
|
176
|
-
: "Connection: close\r\n\r\n".freeze)
|
177
|
-
case rv = kgio_syssend(buf, flags)
|
178
|
-
when nil # all done, likely
|
179
|
-
buf.clear
|
180
|
-
buf = nil # recycle any memory we used ASAP
|
181
|
-
break
|
182
|
-
when String
|
183
|
-
flags = MSG_DONTWAIT
|
184
|
-
buf = rv # unlikely, hope the skb grows
|
185
|
-
when :wait_writable, :wait_readable # unlikely
|
186
|
-
if self.class.output_buffering
|
187
|
-
alive = hijack ? hijack : alive
|
188
|
-
rv = response_header_blocked(buf, body, alive, offset, count)
|
189
|
-
body = nil # ensure we do not close body in ensure
|
190
|
-
return rv
|
191
|
-
else
|
192
|
-
response_wait_write(rv) or return :close
|
193
|
-
end
|
194
|
-
end while true
|
195
165
|
end
|
166
|
+
count ||= clen
|
167
|
+
|
168
|
+
if !term && chunk_ok && !hdr_only
|
169
|
+
term = true
|
170
|
+
body = Yahns::ChunkBody.new(body, opt)
|
171
|
+
buf << "Transfer-Encoding: chunked\r\n".freeze
|
172
|
+
end
|
173
|
+
alive &&= (term || hdr_only)
|
174
|
+
buf << (alive ? "Connection: keep-alive\r\n\r\n".freeze
|
175
|
+
: "Connection: close\r\n\r\n".freeze)
|
176
|
+
case rv = kgio_syssend(buf, flags)
|
177
|
+
when nil # all done, likely
|
178
|
+
buf.clear
|
179
|
+
buf = nil # recycle any memory we used ASAP
|
180
|
+
break
|
181
|
+
when String
|
182
|
+
flags = MSG_DONTWAIT
|
183
|
+
buf = rv # unlikely, hope the skb grows
|
184
|
+
when :wait_writable, :wait_readable # unlikely
|
185
|
+
if self.class.output_buffering
|
186
|
+
alive = hijack ? hijack : alive
|
187
|
+
rv = response_header_blocked(buf, body, alive, offset, count)
|
188
|
+
body = nil # ensure we do not close body in ensure
|
189
|
+
return rv
|
190
|
+
else
|
191
|
+
response_wait_write(rv) or return :close
|
192
|
+
end
|
193
|
+
end while @hs.headers?
|
196
194
|
|
197
195
|
return response_hijacked(hijack) if hijack
|
198
196
|
return http_response_done(alive) if hdr_only
|
@@ -120,7 +120,7 @@ def proxy_res_headers(res, req_res)
|
|
120
120
|
|
121
121
|
# chunk the response ourselves if the client supports it,
|
122
122
|
# but the backend does not terminate properly
|
123
|
-
if alive && ! term
|
123
|
+
if alive && ! term && have_body
|
124
124
|
if env['HTTP_VERSION'] == 'HTTP/1.1'.freeze
|
125
125
|
res << "Transfer-Encoding: chunked\r\n".freeze
|
126
126
|
else # we can't persist HTTP/1.0 and HTTP/0.9 w/o Content-Length
|
data/lib/yahns/queue_epoll.rb
CHANGED
data/lib/yahns/queue_kqueue.rb
CHANGED
data/test/test_auto_chunk.rb
CHANGED
@@ -18,7 +18,12 @@ def test_auto_head
|
|
18
18
|
app = Rack::Builder.new do
|
19
19
|
use Rack::ContentType, "text/plain"
|
20
20
|
run(lambda do |env|
|
21
|
-
[
|
21
|
+
case env['PATH_INFO']
|
22
|
+
when '/204'
|
23
|
+
[ 204, {}, [] ]
|
24
|
+
else
|
25
|
+
[ 200, {}, %w(a b c) ]
|
26
|
+
end
|
22
27
|
end)
|
23
28
|
end
|
24
29
|
app(:rack, app) { listen "#{host}:#{port}" }
|
@@ -50,6 +55,21 @@ def test_auto_head
|
|
50
55
|
assert_equal 200, res.code.to_i
|
51
56
|
assert_equal 'abc', res.body
|
52
57
|
end
|
58
|
+
|
59
|
+
s = TCPSocket.new(host, port)
|
60
|
+
s.write("GET /204 HTTP/1.1\r\nHost: example.com\r\n\r\n")
|
61
|
+
buf = s.readpartial(1024)
|
62
|
+
assert_match %r{\r\n\r\n\z}, buf
|
63
|
+
refute_match %r{^Transfer-Encoding}i, buf
|
64
|
+
assert_match %r{^Connection: keep-alive\r\n}, buf
|
65
|
+
assert_nil IO.select([s], nil, nil, 1), 'connection persists..'
|
66
|
+
|
67
|
+
# maek sure another on the same connection works
|
68
|
+
s.write("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
|
69
|
+
buf = s.readpartial(1024)
|
70
|
+
assert_match %r{\AHTTP/1\.1 200}, buf
|
71
|
+
assert_match(%r{^Transfer-Encoding: chunked\r\n}, buf)
|
72
|
+
s.close
|
53
73
|
ensure
|
54
74
|
quit_wait(pid)
|
55
75
|
end
|
data/test/test_proxy_pass.rb
CHANGED
@@ -154,6 +154,9 @@ def chunky.each
|
|
154
154
|
env['rack.hijack'].call.close
|
155
155
|
# should not be seen:
|
156
156
|
[ 123, [ %w(Content-Type text/html), %w(Content-Length 0) ], [] ]
|
157
|
+
when '/204'
|
158
|
+
buf = env['rack.input'].read # drain
|
159
|
+
[ 204, {}, [] ]
|
157
160
|
else
|
158
161
|
buf = env['rack.input'].read
|
159
162
|
[ 201, {
|
@@ -271,6 +274,7 @@ def test_proxy_pass
|
|
271
274
|
end
|
272
275
|
end
|
273
276
|
|
277
|
+
check_204_on_put(host, port)
|
274
278
|
check_forbidden_put(host, port)
|
275
279
|
check_eof_body(host, port)
|
276
280
|
check_pipelining(host, port)
|
@@ -639,4 +643,33 @@ def check_forbidden_put(host, port)
|
|
639
643
|
ensure
|
640
644
|
to_close.each(&:close)
|
641
645
|
end
|
646
|
+
|
647
|
+
def check_204_on_put(host, port)
|
648
|
+
s = TCPSocket.new(host, port)
|
649
|
+
s.write("PUT /204 HTTP/1.1\r\nHost: example.com\r\n" \
|
650
|
+
"Content-Length: 11\r\n" \
|
651
|
+
"Content-Type: application/octet-stream\r\n" \
|
652
|
+
"\r\nhello worldPUT")
|
653
|
+
buf = s.readpartial(1024)
|
654
|
+
assert_match %r{\AHTTP/1\.1 204}, buf
|
655
|
+
assert_match %r{\r\n\r\n\z}, buf
|
656
|
+
refute_match %r{^Transfer-Encoding}i, buf
|
657
|
+
refute_match %r{^Content-Length}i, buf
|
658
|
+
assert_match %r{^Connection: keep-alive\r\n}, buf
|
659
|
+
assert_nil IO.select([s], nil, nil, 1), 'connection persists..'
|
660
|
+
|
661
|
+
# make sure another on the same connection works
|
662
|
+
s.write(" / HTTP/1.1\r\nHost: example.com\r\n" \
|
663
|
+
"Content-Length: 11\r\n" \
|
664
|
+
"Content-Type: application/octet-stream\r\n" \
|
665
|
+
"\r\nhello world")
|
666
|
+
buf = s.readpartial(1024)
|
667
|
+
assert_match %r{\r\n\r\nhello world\z}, buf
|
668
|
+
assert_match %r{\AHTTP/1\.1 201}, buf
|
669
|
+
assert_match(%r{^Content-Length: 11\r\n}, buf)
|
670
|
+
assert_match %r{^Connection: keep-alive\r\n}, buf
|
671
|
+
assert_nil IO.select([s], nil, nil, 1), 'connection persists..'
|
672
|
+
ensure
|
673
|
+
s.close if s
|
674
|
+
end
|
642
675
|
end
|
data/test/test_rack_hijack.rb
CHANGED
@@ -86,6 +86,12 @@ def test_hijack
|
|
86
86
|
assert_equal "rack.input contents: BLAH", res.body
|
87
87
|
assert_equal 201, res.code.to_i
|
88
88
|
assert_equal "1.0", res.http_version
|
89
|
+
|
90
|
+
# ancient "HTTP/0.9"
|
91
|
+
c = get_tcp_client(host, port)
|
92
|
+
c.write("GET /hijack_res\r\n\r\n")
|
93
|
+
res = Timeout.timeout(30) { c.read }
|
94
|
+
assert_equal 'response.hijacked', res
|
89
95
|
ensure
|
90
96
|
quit_wait(pid)
|
91
97
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yahns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.14.
|
4
|
+
version: 1.14.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yahns hackers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kgio
|