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