sendfile 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.
- data/ext/sendfile.c +7 -6
- data/sendfile.gemspec +1 -1
- data/test/test_sendfile.rb +241 -243
- metadata +2 -2
data/ext/sendfile.c
CHANGED
@@ -157,15 +157,16 @@ static VALUE nogvl_sendfile(void *data)
|
|
157
157
|
{
|
158
158
|
struct sendfile_args *args = data;
|
159
159
|
int rv;
|
160
|
-
off_t written;
|
161
|
-
size_t w = count_max(args->count);
|
160
|
+
off_t written = args->count;
|
162
161
|
|
163
|
-
rv = sendfile(args->in, args->out, args->off,
|
162
|
+
rv = sendfile(args->in, args->out, args->off, &written,
|
164
163
|
NULL, 0);
|
165
|
-
if (rv == 0)
|
164
|
+
if (written == 0 && rv == 0) {
|
166
165
|
args->eof = 1;
|
167
|
-
|
168
|
-
args->
|
166
|
+
} else {
|
167
|
+
args->off += written;
|
168
|
+
args->count -= written;
|
169
|
+
}
|
169
170
|
|
170
171
|
return (VALUE)rv;
|
171
172
|
}
|
data/sendfile.gemspec
CHANGED
data/test/test_sendfile.rb
CHANGED
@@ -2,253 +2,251 @@
|
|
2
2
|
# vim:set ts=4 sw=4 ai:
|
3
3
|
require 'io/nonblock'
|
4
4
|
begin
|
5
|
-
|
5
|
+
require 'rubygems'
|
6
6
|
rescue
|
7
|
-
|
7
|
+
nil
|
8
8
|
end
|
9
9
|
require 'sendfile'
|
10
10
|
require 'socket'
|
11
11
|
require 'tempfile'
|
12
|
-
require
|
12
|
+
require "minitest/autorun"
|
13
|
+
require 'minitest'
|
13
14
|
require 'zlib'
|
14
15
|
|
15
|
-
class TestSendfile < Test
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
end
|
253
|
-
end # class TestSendfile
|
254
|
-
|
16
|
+
class TestSendfile < MiniTest::Test
|
17
|
+
def __fork_server
|
18
|
+
# open pipe for backchannel
|
19
|
+
@rd, @wr = IO.pipe
|
20
|
+
# fork server child
|
21
|
+
@pid = fork do
|
22
|
+
# close read end in child
|
23
|
+
@rd.close
|
24
|
+
|
25
|
+
# start listening and send port back to parent
|
26
|
+
ss = TCPServer.new @host, 0
|
27
|
+
@wr.write( [ ss.addr[1] ].pack( "S"))
|
28
|
+
@wr.flush
|
29
|
+
|
30
|
+
# read what they send and push it back up the pipe
|
31
|
+
while s = ss.accept
|
32
|
+
data = s.read
|
33
|
+
s.close
|
34
|
+
@wr.write( [data.length].pack( "N"))
|
35
|
+
@wr.write data
|
36
|
+
@wr.flush
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# close write end in parent and get server port
|
41
|
+
@wr.close
|
42
|
+
@port = @rd.read( 2).unpack( "S")[0]
|
43
|
+
end
|
44
|
+
|
45
|
+
def setup
|
46
|
+
@dir = File.dirname __FILE__
|
47
|
+
@host = '127.0.0.1'
|
48
|
+
__fork_server
|
49
|
+
|
50
|
+
@smallfile = "#{@dir}/small"
|
51
|
+
@small = File.open @smallfile
|
52
|
+
@small_data = File.read @smallfile
|
53
|
+
|
54
|
+
File.open( "#{@dir}/large.gz") do |f|
|
55
|
+
gzipped = Zlib::GzipReader.new f
|
56
|
+
@large_data = gzipped.read
|
57
|
+
end
|
58
|
+
@largefile = "/tmp/sendfiletest"
|
59
|
+
@large = File.open @largefile, 'w+'
|
60
|
+
@large.write @large_data
|
61
|
+
@large.flush
|
62
|
+
end
|
63
|
+
|
64
|
+
def teardown
|
65
|
+
@small.close
|
66
|
+
@large.close
|
67
|
+
File.unlink @largefile
|
68
|
+
|
69
|
+
Process.kill 'KILL', @pid
|
70
|
+
Process.wait
|
71
|
+
end
|
72
|
+
|
73
|
+
def __do_sendfile file, off=nil, count=nil
|
74
|
+
s = TCPSocket.new @host, @port
|
75
|
+
yield s if block_given?
|
76
|
+
sent = s.sendfile file, off, count
|
77
|
+
s.close
|
78
|
+
len = @rd.read( 4).unpack( "N")[0]
|
79
|
+
read = @rd.read len
|
80
|
+
[ sent, read ]
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_blocking_full_small
|
84
|
+
sent, read = __do_sendfile( @small)
|
85
|
+
assert_equal @small_data.size, sent
|
86
|
+
assert_equal @small_data.size, read.size
|
87
|
+
assert_equal @small_data, read
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_nonblocking_full_small
|
91
|
+
sent, read = __do_sendfile( @small) { |s| s.nonblock = true }
|
92
|
+
assert_equal @small_data.size, sent
|
93
|
+
assert_equal @small_data.size, read.size
|
94
|
+
assert_equal @small_data, read
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_blocking_full_large
|
98
|
+
sent, read = __do_sendfile( @large)
|
99
|
+
assert_equal @large_data.size, sent
|
100
|
+
assert_equal @large_data.size, read.size
|
101
|
+
assert_equal @large_data, read
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_nonblocking_full_large
|
105
|
+
sent, read = __do_sendfile( @large) { |s| s.nonblock = true }
|
106
|
+
assert_equal @large_data.size, sent
|
107
|
+
assert_equal @large_data.size, read.size
|
108
|
+
assert_equal @large_data, read
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_blocking_from_offset
|
112
|
+
data = @large_data[4096..-1]
|
113
|
+
sent, read = __do_sendfile( @large, 4096)
|
114
|
+
assert_equal data.size, sent
|
115
|
+
assert_equal data.size, read.size
|
116
|
+
assert_equal data, read
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_blocking_partial_from_beginning
|
120
|
+
data = @large_data[0, 1048576]
|
121
|
+
sent, read = __do_sendfile( @large, 0, 1048576)
|
122
|
+
assert_equal data.size, sent
|
123
|
+
assert_equal data.size, read.size
|
124
|
+
assert_equal data, read
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_blocking_partial_from_middle
|
128
|
+
data = @large_data[2048, 1048576]
|
129
|
+
sent, read = __do_sendfile( @large, 2048, 1048576)
|
130
|
+
assert_equal data.size, sent
|
131
|
+
assert_equal data.size, read.size
|
132
|
+
assert_equal data, read
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_blocking_partial_to_end
|
136
|
+
data = @large_data[-1048576, 1048576]
|
137
|
+
sent, read = __do_sendfile( @large, @large_data.size - 1048576, 1048576)
|
138
|
+
assert_equal data.size, sent
|
139
|
+
assert_equal data.size, read.size
|
140
|
+
assert_equal data, read
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_nonblocking_from_offset
|
144
|
+
data = @large_data[4096..-1]
|
145
|
+
sent, read = __do_sendfile( @large, 4096) { |s| s.nonblock = true }
|
146
|
+
assert_equal data.size, sent
|
147
|
+
assert_equal data.size, read.size
|
148
|
+
assert_equal data, read
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_nonblocking_partial_from_beginning
|
152
|
+
data = @large_data[0, 1048576]
|
153
|
+
sent, read = __do_sendfile( @large, 0, 1048576) { |s| s.nonblock = true }
|
154
|
+
assert_equal data.size, sent
|
155
|
+
assert_equal data.size, read.size
|
156
|
+
assert_equal data, read
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_nonblocking_partial_from_middle
|
160
|
+
data = @large_data[2048, 1048576]
|
161
|
+
sent, read = __do_sendfile( @large, 2048, 1048576) { |s| s.nonblock = true }
|
162
|
+
assert_equal data.size, sent
|
163
|
+
assert_equal data.size, read.size
|
164
|
+
assert_equal data, read
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_nonblocking_partial_to_end
|
168
|
+
data = @large_data[-1048576, 1048576]
|
169
|
+
sent, read = __do_sendfile( @large, @large_data.size - 1048576, 1048576) { |s| s.nonblock = true }
|
170
|
+
assert_equal data.size, sent
|
171
|
+
assert_equal data.size, read.size
|
172
|
+
assert_equal data, read
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_sendfile_nonblock
|
176
|
+
c, s = UNIXSocket.pair
|
177
|
+
nr_sent = 0
|
178
|
+
assert_raises(Errno::EAGAIN) do
|
179
|
+
loop do
|
180
|
+
nr_sent += c.sendfile_nonblock @small
|
181
|
+
end
|
182
|
+
end
|
183
|
+
c.close
|
184
|
+
nr_read = s.read.size
|
185
|
+
s.close
|
186
|
+
assert_equal nr_read, nr_sent
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_trysendfile
|
190
|
+
c, s = UNIXSocket.pair
|
191
|
+
nr_sent = 0
|
192
|
+
case rv = c.trysendfile(@small)
|
193
|
+
when :wait_writable
|
194
|
+
break
|
195
|
+
when Integer
|
196
|
+
nr_sent += rv
|
197
|
+
else
|
198
|
+
raise "Unexpected return: #{rv.inspect}"
|
199
|
+
end while true
|
200
|
+
assert nr_sent > 0, "nr_sent: #{nr_sent} <= 0"
|
201
|
+
c.close
|
202
|
+
nr_read = s.read.size
|
203
|
+
s.close
|
204
|
+
assert_equal nr_read, nr_sent
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_tempfile
|
208
|
+
tmp = Tempfile.new ''
|
209
|
+
tmp.write @small_data
|
210
|
+
tmp.rewind
|
211
|
+
sent, read = __do_sendfile(tmp)
|
212
|
+
assert_equal @small_data.size, sent
|
213
|
+
assert_equal @small_data.size, read.size
|
214
|
+
assert_equal @small_data, read
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_invalid_file
|
218
|
+
assert_raises(TypeError) { __do_sendfile(:hello) }
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_sendfile_too_big_eof
|
222
|
+
sent = read = nil
|
223
|
+
count = @small_data.size * 2
|
224
|
+
s = TCPSocket.new @host, @port
|
225
|
+
sent = s.sendfile @small, nil, count
|
226
|
+
assert_raises(EOFError) do
|
227
|
+
s.sendfile @small, sent, 1
|
228
|
+
end
|
229
|
+
s.close
|
230
|
+
len = @rd.read( 4).unpack( "N")[0]
|
231
|
+
read = @rd.read len
|
232
|
+
assert_equal @small_data.size, sent
|
233
|
+
assert_equal @small_data.size, read.size
|
234
|
+
assert_equal @small_data, read
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_sendfile_nonblock_eof
|
238
|
+
s = TCPSocket.new @host, @port
|
239
|
+
off = @small_data.size
|
240
|
+
assert_raises(EOFError) do
|
241
|
+
s.sendfile_nonblock @small, off, 1
|
242
|
+
end
|
243
|
+
s.close
|
244
|
+
end
|
245
|
+
|
246
|
+
def test_trysendfile_eof
|
247
|
+
s = TCPSocket.new @host, @port
|
248
|
+
off = @small_data.size
|
249
|
+
assert_nil s.trysendfile(@small, off, 1)
|
250
|
+
s.close
|
251
|
+
end
|
252
|
+
end # class TestSendfile
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sendfile
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-07-01 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! "Allows Ruby programs to access sendfile(2) functionality on \nany
|
15
15
|
IO object. Works on Linux, Solaris, FreeBSD and Darwin with\nblocking and non-blocking
|