unicorn-simon 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/unicorn/http_request.rb +30 -19
- data/lib/unicorn/http_server.rb +3 -3
- data/test/unit/test_request.rb +14 -14
- data/test/unit/test_server.rb +0 -53
- 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: 266572579d245f72975fd917d11fce58d24993ba
|
4
|
+
data.tar.gz: 027bb7a4b437f3634762ca7dfabed7dbc8b1d578
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c1d3a83abac0739e058425450ddeab6a920309a7cb2fc0eeab3be75df5b52e616a99db6619842a04aceaaf3cda9d2ca67e89145db8c89429e4c9d51686dfe14
|
7
|
+
data.tar.gz: ca8d4f6c4bbb2fcb0c0ef7fac7138ccfd50db3bbfb39bcd8c68d8ebb4fa5864704d4f018328ec465738c9c92d268e2cf61bc25a8be1ba0820e5de1528ff9a92a
|
data/lib/unicorn/http_request.rb
CHANGED
@@ -29,8 +29,8 @@ class Unicorn::HttpParser
|
|
29
29
|
# Drop these frozen strings when Ruby 2.2 becomes more prevalent,
|
30
30
|
# 2.2+ optimizes hash assignments when used with literal string keys
|
31
31
|
HTTP_RESPONSE_START = [ 'HTTP', '/1.1 ']
|
32
|
+
EMPTY_ARRAY = [].freeze
|
32
33
|
@@input_class = Unicorn::TeeInput
|
33
|
-
@@raindrops_tcp_info_defined = defined?(Raindrops::TCP_Info)
|
34
34
|
@@check_client_connection = false
|
35
35
|
|
36
36
|
def self.input_class
|
@@ -64,7 +64,7 @@ def self.check_client_connection=(bool)
|
|
64
64
|
# returns an environment hash suitable for Rack if successful
|
65
65
|
# This does minimal exception trapping and it is up to the caller
|
66
66
|
# to handle any socket errors (e.g. user aborted upload).
|
67
|
-
def read(socket)
|
67
|
+
def read(socket, listener)
|
68
68
|
clear
|
69
69
|
e = env
|
70
70
|
|
@@ -85,7 +85,7 @@ def read(socket)
|
|
85
85
|
false until add_parse(socket.kgio_read!(16384))
|
86
86
|
end
|
87
87
|
|
88
|
-
check_client_connection(socket) if @@check_client_connection
|
88
|
+
check_client_connection(socket, listener) if @@check_client_connection
|
89
89
|
|
90
90
|
e['rack.input'] = 0 == content_length ?
|
91
91
|
NULL_IO : @@input_class.new(socket, self)
|
@@ -107,26 +107,37 @@ def hijacked?
|
|
107
107
|
env.include?('rack.hijack_io'.freeze)
|
108
108
|
end
|
109
109
|
|
110
|
-
|
110
|
+
if defined?(Raindrops::TCP_Info)
|
111
|
+
def check_client_connection(socket, listener) # :nodoc:
|
112
|
+
if Kgio::TCPServer === listener
|
113
|
+
@@tcp_info ||= Raindrops::TCP_Info.new(socket)
|
114
|
+
@@tcp_info.get!(socket)
|
115
|
+
raise Errno::EPIPE, "client closed connection".freeze, EMPTY_ARRAY if closed_state?(tcp_info.state)
|
116
|
+
else
|
117
|
+
write_http_header(socket)
|
118
|
+
end
|
119
|
+
end
|
111
120
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
121
|
+
def closed_state?(state) # :nodoc:
|
122
|
+
case state
|
123
|
+
when 1 # ESTABLISHED
|
124
|
+
false
|
125
|
+
when 8, 6, 7, 9, 11 # CLOSE_WAIT, TIME_WAIT, CLOSE, LAST_ACK, CLOSING
|
126
|
+
true
|
127
|
+
else
|
128
|
+
false
|
129
|
+
end
|
130
|
+
end
|
131
|
+
else
|
132
|
+
def check_client_connection(socket, listener) # :nodoc:
|
133
|
+
write_http_header(socket)
|
119
134
|
end
|
120
135
|
end
|
121
136
|
|
122
|
-
def
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
when 6, 7, 8, 9, 11 # TIME_WAIT, CLOSE, CLOSE_WAIT, LAST_ACK, CLOSING
|
127
|
-
true
|
128
|
-
else
|
129
|
-
false
|
137
|
+
def write_http_header(socket) # :nodoc:
|
138
|
+
if headers?
|
139
|
+
self.response_start_sent = true
|
140
|
+
HTTP_RESPONSE_START.each { |c| socket.write(c) }
|
130
141
|
end
|
131
142
|
end
|
132
143
|
end
|
data/lib/unicorn/http_server.rb
CHANGED
@@ -559,8 +559,8 @@ def e100_response_write(client, env)
|
|
559
559
|
|
560
560
|
# once a client is accepted, it is processed in its entirety here
|
561
561
|
# in 3 easy steps: read request, call app, write app response
|
562
|
-
def process_client(client)
|
563
|
-
status, headers, body = @app.call(env = @request.read(client))
|
562
|
+
def process_client(client, listener)
|
563
|
+
status, headers, body = @app.call(env = @request.read(client, listener))
|
564
564
|
|
565
565
|
begin
|
566
566
|
return if @request.hijacked?
|
@@ -656,7 +656,7 @@ def worker_loop(worker)
|
|
656
656
|
# Unicorn::Worker#kgio_tryaccept is not like accept(2) at all,
|
657
657
|
# but that will return false
|
658
658
|
if client = sock.kgio_tryaccept
|
659
|
-
process_client(client)
|
659
|
+
process_client(client, sock)
|
660
660
|
nr += 1
|
661
661
|
worker.tick = time_now.to_i
|
662
662
|
end
|
data/test/unit/test_request.rb
CHANGED
@@ -30,7 +30,7 @@ def setup
|
|
30
30
|
def test_options
|
31
31
|
client = MockRequest.new("OPTIONS * HTTP/1.1\r\n" \
|
32
32
|
"Host: foo\r\n\r\n")
|
33
|
-
env = @request.read(client)
|
33
|
+
env = @request.read(client, nil)
|
34
34
|
assert_equal '', env['REQUEST_PATH']
|
35
35
|
assert_equal '', env['PATH_INFO']
|
36
36
|
assert_equal '*', env['REQUEST_URI']
|
@@ -40,7 +40,7 @@ def test_options
|
|
40
40
|
def test_absolute_uri_with_query
|
41
41
|
client = MockRequest.new("GET http://e:3/x?y=z HTTP/1.1\r\n" \
|
42
42
|
"Host: foo\r\n\r\n")
|
43
|
-
env = @request.read(client)
|
43
|
+
env = @request.read(client, nil)
|
44
44
|
assert_equal '/x', env['REQUEST_PATH']
|
45
45
|
assert_equal '/x', env['PATH_INFO']
|
46
46
|
assert_equal 'y=z', env['QUERY_STRING']
|
@@ -50,7 +50,7 @@ def test_absolute_uri_with_query
|
|
50
50
|
def test_absolute_uri_with_fragment
|
51
51
|
client = MockRequest.new("GET http://e:3/x#frag HTTP/1.1\r\n" \
|
52
52
|
"Host: foo\r\n\r\n")
|
53
|
-
env = @request.read(client)
|
53
|
+
env = @request.read(client, nil)
|
54
54
|
assert_equal '/x', env['REQUEST_PATH']
|
55
55
|
assert_equal '/x', env['PATH_INFO']
|
56
56
|
assert_equal '', env['QUERY_STRING']
|
@@ -61,7 +61,7 @@ def test_absolute_uri_with_fragment
|
|
61
61
|
def test_absolute_uri_with_query_and_fragment
|
62
62
|
client = MockRequest.new("GET http://e:3/x?a=b#frag HTTP/1.1\r\n" \
|
63
63
|
"Host: foo\r\n\r\n")
|
64
|
-
env = @request.read(client)
|
64
|
+
env = @request.read(client, nil)
|
65
65
|
assert_equal '/x', env['REQUEST_PATH']
|
66
66
|
assert_equal '/x', env['PATH_INFO']
|
67
67
|
assert_equal 'a=b', env['QUERY_STRING']
|
@@ -73,7 +73,7 @@ def test_absolute_uri_unsupported_schemes
|
|
73
73
|
%w(ssh+http://e/ ftp://e/x http+ssh://e/x).each do |abs_uri|
|
74
74
|
client = MockRequest.new("GET #{abs_uri} HTTP/1.1\r\n" \
|
75
75
|
"Host: foo\r\n\r\n")
|
76
|
-
assert_raises(HttpParserError) { @request.read(client) }
|
76
|
+
assert_raises(HttpParserError) { @request.read(client, nil) }
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
@@ -81,7 +81,7 @@ def test_x_forwarded_proto_https
|
|
81
81
|
client = MockRequest.new("GET / HTTP/1.1\r\n" \
|
82
82
|
"X-Forwarded-Proto: https\r\n" \
|
83
83
|
"Host: foo\r\n\r\n")
|
84
|
-
env = @request.read(client)
|
84
|
+
env = @request.read(client, nil)
|
85
85
|
assert_equal "https", env['rack.url_scheme']
|
86
86
|
res = @lint.call(env)
|
87
87
|
end
|
@@ -90,7 +90,7 @@ def test_x_forwarded_proto_http
|
|
90
90
|
client = MockRequest.new("GET / HTTP/1.1\r\n" \
|
91
91
|
"X-Forwarded-Proto: http\r\n" \
|
92
92
|
"Host: foo\r\n\r\n")
|
93
|
-
env = @request.read(client)
|
93
|
+
env = @request.read(client, nil)
|
94
94
|
assert_equal "http", env['rack.url_scheme']
|
95
95
|
res = @lint.call(env)
|
96
96
|
end
|
@@ -99,14 +99,14 @@ def test_x_forwarded_proto_invalid
|
|
99
99
|
client = MockRequest.new("GET / HTTP/1.1\r\n" \
|
100
100
|
"X-Forwarded-Proto: ftp\r\n" \
|
101
101
|
"Host: foo\r\n\r\n")
|
102
|
-
env = @request.read(client)
|
102
|
+
env = @request.read(client, nil)
|
103
103
|
assert_equal "http", env['rack.url_scheme']
|
104
104
|
res = @lint.call(env)
|
105
105
|
end
|
106
106
|
|
107
107
|
def test_rack_lint_get
|
108
108
|
client = MockRequest.new("GET / HTTP/1.1\r\nHost: foo\r\n\r\n")
|
109
|
-
env = @request.read(client)
|
109
|
+
env = @request.read(client, nil)
|
110
110
|
assert_equal "http", env['rack.url_scheme']
|
111
111
|
assert_equal '127.0.0.1', env['REMOTE_ADDR']
|
112
112
|
res = @lint.call(env)
|
@@ -114,7 +114,7 @@ def test_rack_lint_get
|
|
114
114
|
|
115
115
|
def test_no_content_stringio
|
116
116
|
client = MockRequest.new("GET / HTTP/1.1\r\nHost: foo\r\n\r\n")
|
117
|
-
env = @request.read(client)
|
117
|
+
env = @request.read(client, nil)
|
118
118
|
assert_equal StringIO, env['rack.input'].class
|
119
119
|
end
|
120
120
|
|
@@ -122,7 +122,7 @@ def test_zero_content_stringio
|
|
122
122
|
client = MockRequest.new("PUT / HTTP/1.1\r\n" \
|
123
123
|
"Content-Length: 0\r\n" \
|
124
124
|
"Host: foo\r\n\r\n")
|
125
|
-
env = @request.read(client)
|
125
|
+
env = @request.read(client, nil)
|
126
126
|
assert_equal StringIO, env['rack.input'].class
|
127
127
|
end
|
128
128
|
|
@@ -130,7 +130,7 @@ def test_real_content_not_stringio
|
|
130
130
|
client = MockRequest.new("PUT / HTTP/1.1\r\n" \
|
131
131
|
"Content-Length: 1\r\n" \
|
132
132
|
"Host: foo\r\n\r\n")
|
133
|
-
env = @request.read(client)
|
133
|
+
env = @request.read(client, nil)
|
134
134
|
assert_equal Unicorn::TeeInput, env['rack.input'].class
|
135
135
|
end
|
136
136
|
|
@@ -141,7 +141,7 @@ def test_rack_lint_put
|
|
141
141
|
"Content-Length: 5\r\n" \
|
142
142
|
"\r\n" \
|
143
143
|
"abcde")
|
144
|
-
env = @request.read(client)
|
144
|
+
env = @request.read(client, nil)
|
145
145
|
assert ! env.include?(:http_body)
|
146
146
|
res = @lint.call(env)
|
147
147
|
end
|
@@ -167,7 +167,7 @@ def client.kgio_read!(*args)
|
|
167
167
|
"\r\n")
|
168
168
|
count.times { assert_equal bs, client.syswrite(buf) }
|
169
169
|
assert_equal 0, client.sysseek(0)
|
170
|
-
env = @request.read(client)
|
170
|
+
env = @request.read(client, nil)
|
171
171
|
assert ! env.include?(:http_body)
|
172
172
|
assert_equal length, env['rack.input'].size
|
173
173
|
count.times {
|
data/test/unit/test_server.rb
CHANGED
@@ -103,59 +103,6 @@ def test_simple_server
|
|
103
103
|
assert_equal 'hello!\n', results[0], "Handler didn't really run"
|
104
104
|
end
|
105
105
|
|
106
|
-
def test_client_shutdown_writes
|
107
|
-
bs = 15609315 * rand
|
108
|
-
sock = TCPSocket.new('127.0.0.1', @port)
|
109
|
-
sock.syswrite("PUT /hello HTTP/1.1\r\n")
|
110
|
-
sock.syswrite("Host: example.com\r\n")
|
111
|
-
sock.syswrite("Transfer-Encoding: chunked\r\n")
|
112
|
-
sock.syswrite("Trailer: X-Foo\r\n")
|
113
|
-
sock.syswrite("\r\n")
|
114
|
-
sock.syswrite("%x\r\n" % [ bs ])
|
115
|
-
sock.syswrite("F" * bs)
|
116
|
-
sock.syswrite("\r\n0\r\nX-")
|
117
|
-
"Foo: bar\r\n\r\n".each_byte do |x|
|
118
|
-
sock.syswrite x.chr
|
119
|
-
sleep 0.05
|
120
|
-
end
|
121
|
-
# we wrote the entire request before shutting down, server should
|
122
|
-
# continue to process our request and never hit EOFError on our sock
|
123
|
-
sock.shutdown(Socket::SHUT_WR)
|
124
|
-
buf = sock.read
|
125
|
-
assert_equal 'hello!\n', buf.split(/\r\n\r\n/).last
|
126
|
-
next_client = Net::HTTP.get(URI.parse("http://127.0.0.1:#@port/"))
|
127
|
-
assert_equal 'hello!\n', next_client
|
128
|
-
lines = File.readlines("test_stderr.#$$.log")
|
129
|
-
assert lines.grep(/^Unicorn::ClientShutdown: /).empty?
|
130
|
-
assert_nil sock.close
|
131
|
-
end
|
132
|
-
|
133
|
-
def test_client_shutdown_write_truncates
|
134
|
-
bs = 15609315 * rand
|
135
|
-
sock = TCPSocket.new('127.0.0.1', @port)
|
136
|
-
sock.syswrite("PUT /hello HTTP/1.1\r\n")
|
137
|
-
sock.syswrite("Host: example.com\r\n")
|
138
|
-
sock.syswrite("Transfer-Encoding: chunked\r\n")
|
139
|
-
sock.syswrite("Trailer: X-Foo\r\n")
|
140
|
-
sock.syswrite("\r\n")
|
141
|
-
sock.syswrite("%x\r\n" % [ bs ])
|
142
|
-
sock.syswrite("F" * (bs / 2.0))
|
143
|
-
|
144
|
-
# shutdown prematurely, this will force the server to abort
|
145
|
-
# processing on us even during app dispatch
|
146
|
-
sock.shutdown(Socket::SHUT_WR)
|
147
|
-
IO.select([sock], nil, nil, 60) or raise "Timed out"
|
148
|
-
buf = sock.read
|
149
|
-
assert_equal "", buf
|
150
|
-
next_client = Net::HTTP.get(URI.parse("http://127.0.0.1:#@port/"))
|
151
|
-
assert_equal 'hello!\n', next_client
|
152
|
-
lines = File.readlines("test_stderr.#$$.log")
|
153
|
-
lines = lines.grep(/^Unicorn::ClientShutdown: bytes_read=\d+/)
|
154
|
-
assert_equal 1, lines.size
|
155
|
-
assert_match %r{\AUnicorn::ClientShutdown: bytes_read=\d+ true$}, lines[0]
|
156
|
-
assert_nil sock.close
|
157
|
-
end
|
158
|
-
|
159
106
|
def test_client_malformed_body
|
160
107
|
bs = 15653984
|
161
108
|
sock = TCPSocket.new('127.0.0.1', @port)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unicorn-simon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- unicorn hackers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|