unicorn-shopify 5.2.0.4 → 5.2.0.5

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: '0842915fc92ef3d24c5d173cedc7a5ab3182006a'
4
- data.tar.gz: 414db070f72af988c29d43bf1c6014fd57ec32e4
3
+ metadata.gz: 15234ad243f343ca91236020b735d34a6600225e
4
+ data.tar.gz: 32175e0fa8ac820fd1b999ef31f4fa44f78ee547
5
5
  SHA512:
6
- metadata.gz: b1baa2c7986292ca8693f32d10548e5e503230633facae91e254856fa563c83cd11a943cbeb5f547499b751f2f88ee7775b3c4e5c0160938b3d7a89b45817ac3
7
- data.tar.gz: f7c3dabd1ba8759403b3690ddcd9155b0c935ea22151e04e29577ca4306eb2a0ec7eb0a82494ebd4514b0a0dbde308559c49becf4cb3d336ffd5e3034c4ad064
6
+ metadata.gz: 8da8bc2ea24a713f003675713dff5b319eff51a3d842933b6fe68701eb20d1ff8b1173d4440921265b9ed55e8828231861aacc3042a42d7005cd1d75b28c3c31
7
+ data.tar.gz: f3b841c4ac7199cebe533c8f0bc9f53afcdb833c6f5cd673c19230d1bef243d110f1f0db91380a79dfd9234bf8120b7536bb2b4d67414823d3d9fe52d9fcba90
@@ -2,6 +2,7 @@
2
2
  # :enddoc:
3
3
  # no stable API here
4
4
  require 'unicorn_http'
5
+ require 'raindrops'
5
6
 
6
7
  # TODO: remove redundant names
7
8
  Unicorn.const_set(:HttpRequest, Unicorn::HttpParser)
@@ -25,8 +26,10 @@ class Unicorn::HttpParser
25
26
 
26
27
  # :stopdoc:
27
28
  HTTP_RESPONSE_START = [ 'HTTP'.freeze, '/1.1 '.freeze ]
29
+ EMPTY_ARRAY = [].freeze
28
30
  @@input_class = Unicorn::TeeInput
29
31
  @@check_client_connection = false
32
+ @@tcpi_inspect_ok = true
30
33
 
31
34
  def self.input_class
32
35
  @@input_class
@@ -80,11 +83,7 @@ class Unicorn::HttpParser
80
83
  false until add_parse(socket.kgio_read!(16384))
81
84
  end
82
85
 
83
- # detect if the socket is valid by writing a partial response:
84
- if @@check_client_connection && headers?
85
- self.response_start_sent = true
86
- HTTP_RESPONSE_START.each { |c| socket.write(c) }
87
- end
86
+ check_client_connection(socket) if @@check_client_connection
88
87
 
89
88
  e['rack.input'] = 0 == content_length ?
90
89
  NULL_IO : @@input_class.new(socket, self)
@@ -105,4 +104,68 @@ class Unicorn::HttpParser
105
104
  def hijacked?
106
105
  env.include?('rack.hijack_io'.freeze)
107
106
  end
107
+
108
+ if defined?(Raindrops::TCP_Info)
109
+ def check_client_connection(socket) # :nodoc:
110
+ if Unicorn::TCPClient === socket
111
+ @@tcp_info ||= Raindrops::TCP_Info.new(socket)
112
+ @@tcp_info.get!(socket)
113
+ raise Errno::EPIPE, "client closed connection".freeze,
114
+ EMPTY_ARRAY if closed_state?(@@tcp_info.state)
115
+ else
116
+ write_http_header(socket)
117
+ end
118
+ end
119
+
120
+ def closed_state?(state) # :nodoc:
121
+ case state
122
+ when 1 # ESTABLISHED
123
+ false
124
+ when 8, 6, 7, 9, 11 # CLOSE_WAIT, TIME_WAIT, CLOSE, LAST_ACK, CLOSING
125
+ true
126
+ else
127
+ false
128
+ end
129
+ end
130
+ else
131
+
132
+ # Ruby 2.2+ can show struct tcp_info as a string Socket::Option#inspect.
133
+ # Not that efficient, but probably still better than doing unnecessary
134
+ # work after a client gives up.
135
+ def check_client_connection(socket) # :nodoc:
136
+ if Unicorn::TCPClient === socket && @@tcpi_inspect_ok
137
+ opt = socket.getsockopt(:IPPROTO_TCP, :TCP_INFO).inspect
138
+ if opt =~ /\bstate=(\S+)/
139
+ @@tcpi_inspect_ok = true
140
+ raise Errno::EPIPE, "client closed connection".freeze,
141
+ EMPTY_ARRAY if closed_state_str?($1)
142
+ else
143
+ @@tcpi_inspect_ok = false
144
+ write_http_header(socket)
145
+ end
146
+ opt.clear
147
+ else
148
+ write_http_header(socket)
149
+ end
150
+ end
151
+
152
+ def closed_state_str?(state)
153
+ case state
154
+ when 'ESTABLISHED'
155
+ false
156
+ # not a typo, ruby maps TCP_CLOSE (no 'D') to state=CLOSED (w/ 'D')
157
+ when 'CLOSE_WAIT', 'TIME_WAIT', 'CLOSED', 'LAST_ACK', 'CLOSING'
158
+ true
159
+ else
160
+ false
161
+ end
162
+ end
163
+ end
164
+
165
+ def write_http_header(socket) # :nodoc:
166
+ if headers?
167
+ self.response_start_sent = true
168
+ HTTP_RESPONSE_START.each { |c| socket.write(c) }
169
+ end
170
+ end
108
171
  end
@@ -534,7 +534,7 @@ class Unicorn::HttpServer
534
534
  def handle_error(client, e)
535
535
  code = case e
536
536
  when EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::ENOTCONN
537
- Unicorn.log_error(@logger, "client disconnected", e)
537
+ Unicorn.log_error(@logger, "client disconnected", e.class.new)
538
538
  # client disconnected on us and there's nothing we can do
539
539
  when Unicorn::RequestURITooLongError
540
540
  414
@@ -3,6 +3,18 @@
3
3
  require 'socket'
4
4
 
5
5
  module Unicorn
6
+
7
+ # Instead of using a generic Kgio::Socket for everything,
8
+ # tag TCP sockets so we can use TCP_INFO under Linux without
9
+ # incurring extra syscalls for Unix domain sockets.
10
+ # TODO: remove these when we remove kgio
11
+ TCPClient = Class.new(Kgio::Socket) # :nodoc:
12
+ class TCPSrv < Kgio::TCPServer # :nodoc:
13
+ def kgio_tryaccept # :nodoc:
14
+ super(TCPClient)
15
+ end
16
+ end
17
+
6
18
  module SocketHelper
7
19
 
8
20
  # internal interface
@@ -148,7 +160,7 @@ module Unicorn
148
160
  end
149
161
  sock.bind(Socket.pack_sockaddr_in(port, addr))
150
162
  sock.autoclose = false
151
- Kgio::TCPServer.for_fd(sock.fileno)
163
+ TCPSrv.for_fd(sock.fileno)
152
164
  end
153
165
 
154
166
  # returns rfc2732-style (e.g. "[::1]:666") addresses for IPv6
@@ -185,7 +197,7 @@ module Unicorn
185
197
  def server_cast(sock)
186
198
  begin
187
199
  Socket.unpack_sockaddr_in(sock.getsockname)
188
- Kgio::TCPServer.for_fd(sock.fileno)
200
+ TCPSrv.for_fd(sock.fileno)
189
201
  rescue ArgumentError
190
202
  Kgio::UNIXServer.for_fd(sock.fileno)
191
203
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unicorn-shopify
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.0.4
4
+ version: 5.2.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - unicorn hackers