fast_send 1.1.2 → 1.1.3
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/.gitignore +51 -0
- data/Gemfile +2 -4
- data/Rakefile +3 -36
- data/fast_send.gemspec +7 -44
- data/lib/fast_send/socket_handler.rb +10 -13
- data/lib/fast_send/version.rb +3 -0
- data/lib/fast_send.rb +5 -7
- data/spec/fast_send_with_mocks_spec.rb +4 -2
- data/spec/fast_send_with_puma_spec.rb +1 -0
- metadata +4 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea16771c56f207d5c40555b4981d955e20724177
|
4
|
+
data.tar.gz: 691ef28f1a505a95c974c5060fc66eff6147ad22
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a354a9e5b09f1d598147428351f824f39b42c1b29e48633ee334791bc68d3c95edc2bc551f2eb7087c8e29f37b20c9ff33360528f7424422e0de403575cda916
|
7
|
+
data.tar.gz: eae00df9f9beb28595c2de2023915245525a27892ed67e2b6ee192446e24822b9f80929051ad6f1bf1a8bb2ede2529bf3ae6364758db3166097ff8466d9ac7e3
|
data/.gitignore
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# rcov generated
|
2
|
+
coverage
|
3
|
+
coverage.data
|
4
|
+
|
5
|
+
# rdoc generated
|
6
|
+
rdoc
|
7
|
+
|
8
|
+
# yard generated
|
9
|
+
doc
|
10
|
+
.yardoc
|
11
|
+
|
12
|
+
# bundler
|
13
|
+
.bundle
|
14
|
+
Gemfile.lock
|
15
|
+
.ruby-version
|
16
|
+
|
17
|
+
# jeweler generated
|
18
|
+
pkg
|
19
|
+
|
20
|
+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
21
|
+
#
|
22
|
+
# * Create a file at ~/.gitignore
|
23
|
+
# * Include files you want ignored
|
24
|
+
# * Run: git config --global core.excludesfile ~/.gitignore
|
25
|
+
#
|
26
|
+
# After doing this, these files will be ignored in all your git projects,
|
27
|
+
# saving you from having to 'pollute' every project you touch with them
|
28
|
+
#
|
29
|
+
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
30
|
+
#
|
31
|
+
# For MacOS:
|
32
|
+
#
|
33
|
+
#.DS_Store
|
34
|
+
|
35
|
+
# For TextMate
|
36
|
+
#*.tmproj
|
37
|
+
#tmtags
|
38
|
+
|
39
|
+
# For emacs:
|
40
|
+
#*~
|
41
|
+
#\#*
|
42
|
+
#.\#*
|
43
|
+
|
44
|
+
# For vim:
|
45
|
+
#*.swp
|
46
|
+
|
47
|
+
# For redcar:
|
48
|
+
#.redcar
|
49
|
+
|
50
|
+
# For rubinius:
|
51
|
+
#*.rbc
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1,38 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'bundler'
|
5
|
-
begin
|
6
|
-
Bundler.setup(:default, :development)
|
7
|
-
rescue Bundler::BundlerError => e
|
8
|
-
$stderr.puts e.message
|
9
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
-
exit e.status_code
|
11
|
-
end
|
12
|
-
require 'rake'
|
13
|
-
|
14
|
-
require 'jeweler'
|
15
|
-
require_relative 'lib/fast_send'
|
16
|
-
Jeweler::Tasks.new do |gem|
|
17
|
-
gem.version = FastSend::VERSION
|
18
|
-
gem.name = "fast_send"
|
19
|
-
gem.homepage = "https://github.com/WeTransfer/fast_send"
|
20
|
-
gem.license = "MIT"
|
21
|
-
gem.description = %Q{Send bursts of large files quickly via Rack}
|
22
|
-
gem.summary = %Q{and do so bypassing the Ruby VM}
|
23
|
-
gem.email = "me@julik.nl"
|
24
|
-
gem.authors = ["Julik Tarkhanov"]
|
25
|
-
# dependencies defined in Gemfile
|
26
|
-
end
|
27
|
-
|
28
|
-
Jeweler::RubygemsDotOrgTasks.new
|
29
|
-
|
30
|
-
require 'rspec/core'
|
1
|
+
require 'bundler/gem_tasks'
|
31
2
|
require 'rspec/core/rake_task'
|
32
|
-
RSpec::Core::RakeTask.new(:spec) do |spec|
|
33
|
-
spec.rspec_opts = ["-c"]
|
34
|
-
spec.pattern = FileList['spec/**/*_spec.rb']
|
35
|
-
end
|
36
|
-
|
37
|
-
task :default => :spec
|
38
3
|
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
task default: :spec
|
data/fast_send.gemspec
CHANGED
@@ -1,13 +1,9 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
1
|
# -*- encoding: utf-8 -*-
|
5
2
|
# stub: fast_send 1.1.2 ruby lib
|
6
|
-
|
3
|
+
require File.dirname(__FILE__) + '/lib/fast_send/version'
|
7
4
|
Gem::Specification.new do |s|
|
8
5
|
s.name = "fast_send"
|
9
|
-
s.version =
|
10
|
-
|
6
|
+
s.version = FastSend::VERSION
|
11
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
8
|
s.require_paths = ["lib"]
|
13
9
|
s.authors = ["Julik Tarkhanov"]
|
@@ -18,47 +14,14 @@ Gem::Specification.new do |s|
|
|
18
14
|
"LICENSE.txt",
|
19
15
|
"README.md"
|
20
16
|
]
|
21
|
-
s.files =
|
22
|
-
"Gemfile",
|
23
|
-
"LICENSE.txt",
|
24
|
-
"README.md",
|
25
|
-
"Rakefile",
|
26
|
-
"config.ru",
|
27
|
-
"fast_send.gemspec",
|
28
|
-
"lib/fast_send.rb",
|
29
|
-
"lib/fast_send/null_logger.rb",
|
30
|
-
"lib/fast_send/socket_handler.rb",
|
31
|
-
"spec/fast_send_with_mocks_spec.rb",
|
32
|
-
"spec/fast_send_with_puma_spec.rb",
|
33
|
-
"spec/test_app.ru"
|
34
|
-
]
|
17
|
+
s.files = `git ls-files -z`.split("\x0")
|
35
18
|
s.homepage = "https://github.com/WeTransfer/fast_send"
|
36
19
|
s.licenses = ["MIT"]
|
37
20
|
s.rubygems_version = "2.4.5.1"
|
38
21
|
s.summary = "and do so bypassing the Ruby VM"
|
39
22
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
s.add_development_dependency(%q<rake>, [">= 0"])
|
45
|
-
s.add_development_dependency(%q<jeweler>, ["> 2"])
|
46
|
-
s.add_development_dependency(%q<rspec>, ["~> 3"])
|
47
|
-
s.add_development_dependency(%q<puma>, [">= 0"])
|
48
|
-
s.add_development_dependency(%q<sendfile>, [">= 0"])
|
49
|
-
else
|
50
|
-
s.add_dependency(%q<rake>, [">= 0"])
|
51
|
-
s.add_dependency(%q<jeweler>, ["> 2"])
|
52
|
-
s.add_dependency(%q<rspec>, ["~> 3"])
|
53
|
-
s.add_dependency(%q<puma>, [">= 0"])
|
54
|
-
s.add_dependency(%q<sendfile>, [">= 0"])
|
55
|
-
end
|
56
|
-
else
|
57
|
-
s.add_dependency(%q<rake>, [">= 0"])
|
58
|
-
s.add_dependency(%q<jeweler>, ["> 2"])
|
59
|
-
s.add_dependency(%q<rspec>, ["~> 3"])
|
60
|
-
s.add_dependency(%q<puma>, [">= 0"])
|
61
|
-
s.add_dependency(%q<sendfile>, [">= 0"])
|
62
|
-
end
|
23
|
+
s.add_development_dependency("rake", [">= 0"])
|
24
|
+
s.add_development_dependency("rspec", ["~> 3"])
|
25
|
+
s.add_development_dependency("puma", [">= 0"])
|
26
|
+
s.add_development_dependency("sendfile", [">= 0"])
|
63
27
|
end
|
64
|
-
|
@@ -12,6 +12,10 @@ class FastSend::SocketHandler < Struct.new(:stream, :logger, :started_proc, :abo
|
|
12
12
|
# Is raised when it is not possible to send a chunk of data
|
13
13
|
# to the client using non-blocking sends for longer than the preset timeout
|
14
14
|
SlowLoris = Class.new(StandardError)
|
15
|
+
|
16
|
+
# Exceptions that indicate a client being too slow or dropping out
|
17
|
+
# due to failing reads/writes
|
18
|
+
CLIENT_DISCONNECT_EXCEPTIONS = [SlowLoris] + ::FastSend::CLIENT_DISCONNECTS
|
15
19
|
|
16
20
|
# Whether we are forced to use blocking IO for sendfile()
|
17
21
|
USE_BLOCKING_SENDFILE = !!(RUBY_PLATFORM =~ /darwin/)
|
@@ -55,13 +59,14 @@ class FastSend::SocketHandler < Struct.new(:stream, :logger, :started_proc, :abo
|
|
55
59
|
|
56
60
|
logger.info { "Response written in full - %d bytes" % bytes_written }
|
57
61
|
done_proc.call(bytes_written)
|
58
|
-
rescue *
|
62
|
+
rescue *CLIENT_DISCONNECT_EXCEPTIONS => e
|
59
63
|
logger.warn { "Client closed connection: #{e.class}(#{e.message})" }
|
60
64
|
aborted_proc.call(e)
|
61
65
|
rescue Exception => e
|
62
|
-
logger.fatal { "Aborting response due to error: #{e.class}(#{e.message})" }
|
66
|
+
logger.fatal { "Aborting response due to error: #{e.class}(#{e.message}) and will propagate" }
|
63
67
|
aborted_proc.call(e)
|
64
68
|
error_proc.call(e)
|
69
|
+
raise e unless StandardError === e # Re-raise system errors, signals and other Exceptions
|
65
70
|
ensure
|
66
71
|
# With rack.hijack the consensus seems to be that the hijack
|
67
72
|
# proc is responsible for closing the socket. We also use no-keepalive
|
@@ -71,14 +76,6 @@ class FastSend::SocketHandler < Struct.new(:stream, :logger, :started_proc, :abo
|
|
71
76
|
cleanup_proc.call(bytes_written)
|
72
77
|
end
|
73
78
|
end
|
74
|
-
|
75
|
-
# Returns an array of Exception classes we can rescue from (using a splat)
|
76
|
-
#
|
77
|
-
# @return [Array<Class>] the classes
|
78
|
-
def client_disconnect_exeptions
|
79
|
-
[SlowLoris] + ::FastSend::CLIENT_DISCONNECTS
|
80
|
-
end
|
81
|
-
|
82
79
|
|
83
80
|
# This is majorly useful - if the socket is not selectable after a certain
|
84
81
|
# timeout, it might be a slow loris or a connection that hung up on us. So if
|
@@ -110,7 +107,7 @@ class FastSend::SocketHandler < Struct.new(:stream, :logger, :started_proc, :abo
|
|
110
107
|
#
|
111
108
|
# @param socket[Socket] the socket to write to
|
112
109
|
# @param file[File] the IO you can read from
|
113
|
-
# @yields num_bytes_written[
|
110
|
+
# @yields num_bytes_written[Integer] the number of bytes written on each `IO.copy_stream() call`
|
114
111
|
# @return [void]
|
115
112
|
def sendfile(socket, file)
|
116
113
|
chunk = SENDFILE_CHUNK_SIZE
|
@@ -152,7 +149,7 @@ class FastSend::SocketHandler < Struct.new(:stream, :logger, :started_proc, :abo
|
|
152
149
|
#
|
153
150
|
# @param socket[Socket] the socket to write to
|
154
151
|
# @param file[File] the IO you can read from
|
155
|
-
# @yields num_bytes_written[
|
152
|
+
# @yields num_bytes_written[Integer] the number of bytes written on each `IO.copy_stream() call`
|
156
153
|
# @return [void]
|
157
154
|
def copy_stream(socket, file)
|
158
155
|
chunk = SENDFILE_CHUNK_SIZE
|
@@ -177,7 +174,7 @@ class FastSend::SocketHandler < Struct.new(:stream, :logger, :started_proc, :abo
|
|
177
174
|
#
|
178
175
|
# @param socket[Socket] the socket to write to
|
179
176
|
# @param file[File] the IO you can read from
|
180
|
-
# @yields num_bytes_written[
|
177
|
+
# @yields num_bytes_written[Integer] the number of bytes written on each `IO.copy_stream() call`
|
181
178
|
# @return [void]
|
182
179
|
def copy_nio(socket, file)
|
183
180
|
chunk = SENDFILE_CHUNK_SIZE
|
data/lib/fast_send.rb
CHANGED
@@ -31,11 +31,6 @@
|
|
31
31
|
# `fast_send.error' => ->(exception) { } # the response is not sent completely due to an error in the application
|
32
32
|
# `fast_send.cleanup' => ->(sent_total) { } # Called at the end of the response, in an ensure block
|
33
33
|
class FastSend
|
34
|
-
require_relative 'fast_send/socket_handler'
|
35
|
-
require_relative 'fast_send/null_logger'
|
36
|
-
|
37
|
-
VERSION = '1.1.2'
|
38
|
-
|
39
34
|
# All exceptions that get raised when the client closes a connection before receiving the entire response
|
40
35
|
CLIENT_DISCONNECTS = [Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN, Errno::EPROTOTYPE]
|
41
36
|
|
@@ -43,8 +38,11 @@ class FastSend
|
|
43
38
|
require 'java'
|
44
39
|
CLIENT_DISCONNECTS << Java::JavaIo::IOException
|
45
40
|
end
|
46
|
-
|
47
|
-
|
41
|
+
|
42
|
+
require_relative 'fast_send/version'
|
43
|
+
require_relative 'fast_send/socket_handler'
|
44
|
+
require_relative 'fast_send/null_logger'
|
45
|
+
|
48
46
|
# Gets raised if a fast_send.something is mentioned in
|
49
47
|
# the response headers but is not supported as a callback
|
50
48
|
# (the dangers of hashmaps as datastructures is that you
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require_relative '../lib/fast_send'
|
2
2
|
require 'logger'
|
3
|
+
require 'tempfile'
|
4
|
+
|
3
5
|
describe 'FastSend when used with a mock Socket' do
|
4
6
|
let(:logger) {
|
5
7
|
Logger.new(nil).tap{|l| l.level = Logger::DEBUG }
|
@@ -327,8 +329,8 @@ describe 'FastSend when used with a mock Socket' do
|
|
327
329
|
|
328
330
|
bytes_sent_cbs = callbacks[1..-3]
|
329
331
|
bytes_sent_cbs.each_with_index do | c, i |
|
330
|
-
expect(c[1]).to be_kind_of(
|
331
|
-
expect(c[2]).to be_kind_of(
|
332
|
+
expect(c[1]).to be_kind_of(Integer)
|
333
|
+
expect(c[2]).to be_kind_of(Integer)
|
332
334
|
end
|
333
335
|
end
|
334
336
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fast_send
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: jeweler
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '2'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '2'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: rspec
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -88,6 +74,7 @@ extra_rdoc_files:
|
|
88
74
|
- LICENSE.txt
|
89
75
|
- README.md
|
90
76
|
files:
|
77
|
+
- ".gitignore"
|
91
78
|
- Gemfile
|
92
79
|
- LICENSE.txt
|
93
80
|
- README.md
|
@@ -97,6 +84,7 @@ files:
|
|
97
84
|
- lib/fast_send.rb
|
98
85
|
- lib/fast_send/null_logger.rb
|
99
86
|
- lib/fast_send/socket_handler.rb
|
87
|
+
- lib/fast_send/version.rb
|
100
88
|
- spec/fast_send_with_mocks_spec.rb
|
101
89
|
- spec/fast_send_with_puma_spec.rb
|
102
90
|
- spec/test_app.ru
|
@@ -120,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
108
|
version: '0'
|
121
109
|
requirements: []
|
122
110
|
rubyforge_project:
|
123
|
-
rubygems_version: 2.
|
111
|
+
rubygems_version: 2.6.11
|
124
112
|
signing_key:
|
125
113
|
specification_version: 4
|
126
114
|
summary: and do so bypassing the Ruby VM
|