unicorn-shopify 5.2.0.4 → 5.2.0.5

Sign up to get free protection for your applications and to get access to all the features.
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