unicorn-simon 0.0.5 → 0.0.6
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.
- 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
|