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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 296319ebd9dc03db03c92e724df519984fafb751
4
- data.tar.gz: eceba679f90bf6d5c777a067d6fad24468ba8cb1
3
+ metadata.gz: 266572579d245f72975fd917d11fce58d24993ba
4
+ data.tar.gz: 027bb7a4b437f3634762ca7dfabed7dbc8b1d578
5
5
  SHA512:
6
- metadata.gz: 2bc1d883375fc4071a2d8c41b5c8388e9de5501e241e5bc83a652a9283030f997e366acde96f5fbc333ab89c19618996a8872a1c7f7890a96d0898169e8b75e5
7
- data.tar.gz: cfdd494e863019165dcb8d88359eb2ed545c6f494426447b2cffea72f8ec4c8a0e65f09b3bae0133ba9030c8de2bcd9eb3a7966b553e15d172da10643a087937
6
+ metadata.gz: 0c1d3a83abac0739e058425450ddeab6a920309a7cb2fc0eeab3be75df5b52e616a99db6619842a04aceaaf3cda9d2ca67e89145db8c89429e4c9d51686dfe14
7
+ data.tar.gz: ca8d4f6c4bbb2fcb0c0ef7fac7138ccfd50db3bbfb39bcd8c68d8ebb4fa5864704d4f018328ec465738c9c92d268e2cf61bc25a8be1ba0820e5de1528ff9a92a
@@ -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
- private
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
- def check_client_connection(socket)
113
- if @@raindrops_tcp_info_defined
114
- tcp_info = Raindrops::TCP_Info.new(socket)
115
- raise Errno::EPIPE, "client closed connection state=#{tcp_info.state} socket_class=#{socket.class}", [] if closed_state?(tcp_info.state)
116
- elsif headers?
117
- self.response_start_sent = true
118
- HTTP_RESPONSE_START.each { |c| socket.write(c) }
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 closed_state?(state)
123
- case state
124
- when 1 # ESTABLISHED
125
- false
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
@@ -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
@@ -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 {
@@ -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.5
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-02-26 00:00:00.000000000 Z
11
+ date: 2017-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack