fast_send 1.2.0 → 1.2.1

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
- SHA1:
3
- metadata.gz: 26069db40cb9f389a16d39c87a6171dd6f341256
4
- data.tar.gz: 937f14723306d0d7dcdd58b8a1178a895bcbcbdd
2
+ SHA256:
3
+ metadata.gz: 6e2c4890b5649cc57d8ada06a7d603dce77e5d98f3fed5f08cc8509f36b2f474
4
+ data.tar.gz: 55bbe6a60c743baf0b587f9d8b9f11141110f6fe8d497a1bc110620487524edf
5
5
  SHA512:
6
- metadata.gz: 325587ad50e76b729cc2075b31800d0da68410004bc5826fa936a86ae2fa68da66bfc44511167070bea6a201524d73bd63f7ca84f66e94781ef1a30b21a30cdb
7
- data.tar.gz: 25d732c665b5ad6fc96b7a822cdf28225d30e55fec78b0124b61468ec59ccd8f45bef02bc3b6d9c8c7bd6b71e645193019fd98b18d8e12ab66c3f3a91db54d94
6
+ metadata.gz: 18f09fb016ffbfec08b34b1e249c618500c72099c247f77673ac974ec2f666c7a9da9fdab605a344f42c1f60760cfd2790d5740db1fdd9e2afe2fea2bf587d97
7
+ data.tar.gz: 52de47120c17aa8c4fa10d9586c6039d04538517cc6da7be069c5082adc5755f162843183494061ec6947a698f684462b33521849d0fe4464a1aea726ea5a910
@@ -30,8 +30,6 @@ class FastSend::SocketHandler < Struct.new(:stream, :logger, :started_proc, :abo
30
30
  SENDFILE_CHUNK_SIZE = 2*1024*1024
31
31
 
32
32
  def call(socket)
33
- return if socket.closed?
34
-
35
33
  writer_method_name = if socket.respond_to?(:sendfile)
36
34
  :sendfile
37
35
  elsif RUBY_PLATFORM == 'java'
@@ -39,44 +37,40 @@ class FastSend::SocketHandler < Struct.new(:stream, :logger, :started_proc, :abo
39
37
  else
40
38
  :copy_stream
41
39
  end
42
-
43
- logger.debug { "Will do file-to-socket using %s" % writer_method_name }
44
-
45
- begin
46
- logger.debug { "Starting the response" }
47
-
48
- bytes_written = 0
49
-
50
- started_proc.call(bytes_written)
51
-
52
- stream.each_file do | file |
53
- logger.debug { "Sending %s" % file.inspect }
54
- # Run the sending method, depending on the implementation
55
- send(writer_method_name, socket, file) do |n_bytes_sent|
56
- bytes_written += n_bytes_sent
57
- logger.debug { "Written %d bytes" % bytes_written }
58
- written_proc.call(n_bytes_sent, bytes_written)
59
- end
40
+
41
+ logger.debug { "Starting the response, writing via #{writer_method_name}" }
42
+ bytes_written = 0
43
+ started_proc.call(bytes_written)
44
+
45
+ return if socket.closed? # Only do this now as we need to have bytes_written set
46
+
47
+ stream.each_file do | file |
48
+ logger.debug { "Sending %s" % file.inspect }
49
+ # Run the sending method, depending on the implementation
50
+ send(writer_method_name, socket, file) do |n_bytes_sent|
51
+ bytes_written += n_bytes_sent
52
+ logger.debug { "Written %d bytes" % bytes_written }
53
+ written_proc.call(n_bytes_sent, bytes_written)
60
54
  end
61
-
62
- logger.info { "Response written in full - %d bytes" % bytes_written }
63
- done_proc.call(bytes_written)
64
- rescue *CLIENT_DISCONNECT_EXCEPTIONS => e
65
- logger.warn { "Client closed connection: #{e.class}(#{e.message})" }
66
- aborted_proc.call(e)
67
- rescue Exception => e
68
- logger.fatal { "Aborting response due to error: #{e.class}(#{e.message}) and will propagate" }
69
- aborted_proc.call(e)
70
- error_proc.call(e)
71
- raise e unless StandardError === e # Re-raise system errors, signals and other Exceptions
72
- ensure
73
- # With rack.hijack the consensus seems to be that the hijack
74
- # proc is responsible for closing the socket. We also use no-keepalive
75
- # so this should not pose any problems.
76
- socket.close unless socket.closed?
77
- logger.debug { "Performing cleanup" }
78
- cleanup_proc.call(bytes_written)
79
55
  end
56
+
57
+ logger.info { "Response written in full - %d bytes" % bytes_written }
58
+ done_proc.call(bytes_written)
59
+ rescue *CLIENT_DISCONNECT_EXCEPTIONS => e
60
+ logger.warn { "Client closed connection: #{e.class}(#{e.message})" }
61
+ aborted_proc.call(e)
62
+ rescue Exception => e
63
+ logger.fatal { "Aborting response due to error: #{e.class}(#{e.message}) and will propagate" }
64
+ aborted_proc.call(e)
65
+ error_proc.call(e)
66
+ raise e unless StandardError === e # Re-raise system errors, signals and other Exceptions
67
+ ensure
68
+ # With rack.hijack the consensus seems to be that the hijack
69
+ # proc is responsible for closing the socket. We also use no-keepalive
70
+ # so this should not pose any problems.
71
+ socket.close unless socket.closed?
72
+ logger.debug { "Performing cleanup" }
73
+ cleanup_proc.call(bytes_written)
80
74
  end
81
75
 
82
76
  # This is majorly useful - if the socket is not selectable after a certain
@@ -1,3 +1,3 @@
1
1
  class FastSend
2
- VERSION = "1.2.0"
2
+ VERSION = "1.2.1"
3
3
  end
@@ -239,7 +239,29 @@ describe 'FastSend when used with a mock Socket' do
239
239
 
240
240
  expect(output.size).to eq(source_size)
241
241
  end
242
-
242
+
243
+ it 'calls the cleanup proc even if the socket enters the handler in a closed state' do
244
+ source_size = (64 + 54) * 1024 * 1024
245
+ cleanup_proc = double('Cleanup')
246
+ app = ->(env) { [200, {'fast_send.cleanup' => cleanup_proc}, EachFileResponse.new] }
247
+
248
+ handler = described_class.new(app)
249
+
250
+ status, headers, body = handler.call({'rack.hijack?' => true, 'rack.logger' => logger})
251
+ expect(status).to eq(200)
252
+ expect(body).to eq([])
253
+
254
+ output = Tempfile.new('response_body')
255
+
256
+ already_closed_socket = FakeSocket.new(output)
257
+ already_closed_socket.close
258
+
259
+ hijack = headers.fetch('rack.hijack')
260
+
261
+ # The cleanup proc gets called with the number of bytes transferred
262
+ expect(cleanup_proc).to receive(:call).with(0)
263
+ hijack.call(already_closed_socket)
264
+ end
243
265
 
244
266
  it 'can execute the hijack proc twice without resending the data' do
245
267
  source_size = (64 + 54) * 1024 * 1024
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_send
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julik Tarkhanov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-05 00:00:00.000000000 Z
11
+ date: 2020-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -108,8 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
110
  requirements: []
111
- rubyforge_project:
112
- rubygems_version: 2.6.11
111
+ rubygems_version: 3.0.3
113
112
  signing_key:
114
113
  specification_version: 4
115
114
  summary: and do so bypassing the Ruby VM