down 4.0.1 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/down/chunked_io.rb +45 -0
- data/lib/down/http.rb +15 -8
- data/lib/down/net_http.rb +21 -24
- data/lib/down/version.rb +1 -1
- data/lib/down/wget.rb +6 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '08443f7ebc7a853be6b2c24d0cff24795af18bdf'
|
4
|
+
data.tar.gz: c723068fcc5675755bb90f51ab8eab1fe21a3cef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b9b5ec3d60c3dc7d035bf79e29767d22e2de97b05e060fcc477da5ea3d9015b8f19c26b2414e94643268123fedaa427e2e3d69c47d614109874788315bc93dd
|
7
|
+
data.tar.gz: e98698c9fb10d4163b3ec33eb63b1ef38cb62b069835620c01ed93d7994d38b99c3b55a3f5eace5fe628b1f9c1fb6d93a17ea1e6cae75bb3d119bb5a484a391a
|
data/lib/down/chunked_io.rb
CHANGED
@@ -15,6 +15,7 @@ module Down
|
|
15
15
|
@encoding = find_encoding(encoding || Encoding::BINARY)
|
16
16
|
@rewindable = rewindable
|
17
17
|
@buffer = nil
|
18
|
+
@bytes_read = 0
|
18
19
|
|
19
20
|
retrieve_chunk
|
20
21
|
end
|
@@ -46,6 +47,43 @@ module Down
|
|
46
47
|
data.to_s unless length && (data.nil? || data.empty?)
|
47
48
|
end
|
48
49
|
|
50
|
+
def gets(separator_or_limit = $/, limit = nil)
|
51
|
+
raise IOError, "closed stream" if closed?
|
52
|
+
|
53
|
+
if separator_or_limit.is_a?(Integer)
|
54
|
+
separator = $/
|
55
|
+
limit = separator_or_limit
|
56
|
+
else
|
57
|
+
separator = separator_or_limit
|
58
|
+
end
|
59
|
+
|
60
|
+
return read if separator.nil?
|
61
|
+
|
62
|
+
separator = "\n\n" if separator.empty?
|
63
|
+
|
64
|
+
begin
|
65
|
+
data = readpartial(limit)
|
66
|
+
|
67
|
+
until data.include?(separator) || data.bytesize == limit || eof?
|
68
|
+
remaining_length = limit - data.bytesize if limit
|
69
|
+
data << readpartial(remaining_length, outbuf ||= String.new)
|
70
|
+
end
|
71
|
+
|
72
|
+
line, extra = data.split(separator, 2)
|
73
|
+
line << separator if data.include?(separator)
|
74
|
+
|
75
|
+
if cache
|
76
|
+
cache.pos -= extra.to_s.bytesize
|
77
|
+
else
|
78
|
+
@buffer = @buffer.to_s.prepend(extra.to_s)
|
79
|
+
end
|
80
|
+
rescue EOFError
|
81
|
+
line = nil
|
82
|
+
end
|
83
|
+
|
84
|
+
line
|
85
|
+
end
|
86
|
+
|
49
87
|
def readpartial(length = nil, outbuf = nil)
|
50
88
|
raise IOError, "closed stream" if closed?
|
51
89
|
|
@@ -85,9 +123,15 @@ module Down
|
|
85
123
|
end
|
86
124
|
end
|
87
125
|
|
126
|
+
@bytes_read += data.bytesize
|
127
|
+
|
88
128
|
data
|
89
129
|
end
|
90
130
|
|
131
|
+
def pos
|
132
|
+
@bytes_read
|
133
|
+
end
|
134
|
+
|
91
135
|
def eof?
|
92
136
|
raise IOError, "closed stream" if closed?
|
93
137
|
|
@@ -100,6 +144,7 @@ module Down
|
|
100
144
|
raise IOError, "this Down::ChunkedIO is not rewindable" if cache.nil?
|
101
145
|
|
102
146
|
cache.rewind
|
147
|
+
@bytes_read = 0
|
103
148
|
end
|
104
149
|
|
105
150
|
def close
|
data/lib/down/http.rb
CHANGED
@@ -18,7 +18,7 @@ module Down
|
|
18
18
|
options = client_or_options
|
19
19
|
options = client_or_options.default_options if client_or_options.is_a?(HTTP::Client)
|
20
20
|
|
21
|
-
@client = HTTP.headers("User-Agent" => "Down/#{VERSION}").follow(max_hops: 2)
|
21
|
+
@client = HTTP.headers("User-Agent" => "Down/#{Down::VERSION}").follow(max_hops: 2)
|
22
22
|
@client = HTTP::Client.new(@client.default_options.merge(options)) if options
|
23
23
|
end
|
24
24
|
|
@@ -46,7 +46,7 @@ module Down
|
|
46
46
|
|
47
47
|
tempfile.open # flush written content
|
48
48
|
|
49
|
-
tempfile.extend DownloadedFile
|
49
|
+
tempfile.extend Down::Http::DownloadedFile
|
50
50
|
tempfile.url = io.data[:response].uri.to_s
|
51
51
|
tempfile.headers = io.data[:headers]
|
52
52
|
|
@@ -59,21 +59,28 @@ module Down
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def open(url, rewindable: true, **options, &block)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
response = get(url, **options, &block)
|
63
|
+
|
64
|
+
response_error!(response) if !response.status.success?
|
65
|
+
|
66
|
+
body_chunks = Enumerator.new do |yielder|
|
67
|
+
begin
|
68
|
+
response.body.each { |chunk| yielder << chunk }
|
69
|
+
rescue => exception
|
70
|
+
request_error!(exception)
|
71
|
+
end
|
67
72
|
end
|
68
73
|
|
69
74
|
Down::ChunkedIO.new(
|
70
|
-
chunks:
|
75
|
+
chunks: body_chunks,
|
71
76
|
size: response.content_length,
|
72
77
|
encoding: response.content_type.charset,
|
73
78
|
rewindable: rewindable,
|
74
79
|
on_close: (-> { response.connection.close } unless @client.persistent?),
|
75
80
|
data: { status: response.code, headers: response.headers.to_h, response: response },
|
76
81
|
)
|
82
|
+
rescue => exception
|
83
|
+
request_error!(exception)
|
77
84
|
end
|
78
85
|
|
79
86
|
private
|
data/lib/down/net_http.rb
CHANGED
@@ -12,7 +12,7 @@ require "cgi"
|
|
12
12
|
module Down
|
13
13
|
class NetHttp < Backend
|
14
14
|
def initialize(options = {})
|
15
|
-
@options = options
|
15
|
+
@options = { "User-Agent" => "Down/#{Down::VERSION}" }.merge(options)
|
16
16
|
end
|
17
17
|
|
18
18
|
def download(uri, options = {})
|
@@ -24,7 +24,6 @@ module Down
|
|
24
24
|
content_length_proc = options.delete(:content_length_proc)
|
25
25
|
|
26
26
|
open_uri_options = {
|
27
|
-
"User-Agent" => "Down/#{VERSION}",
|
28
27
|
content_length_proc: proc { |size|
|
29
28
|
if size && max_size && size > max_size
|
30
29
|
raise Down::TooLarge, "file is too large (max is #{max_size/1024/1024}MB)"
|
@@ -62,9 +61,7 @@ module Down
|
|
62
61
|
begin
|
63
62
|
uri = URI(uri)
|
64
63
|
|
65
|
-
|
66
|
-
raise Down::InvalidUrl, "URL scheme needs to be http or https"
|
67
|
-
end
|
64
|
+
fail Down::InvalidUrl, "URL scheme needs to be http or https" unless uri.is_a?(URI::HTTP)
|
68
65
|
|
69
66
|
if uri.user || uri.password
|
70
67
|
open_uri_options[:http_basic_authentication] ||= [uri.user, uri.password]
|
@@ -83,7 +80,7 @@ module Down
|
|
83
80
|
|
84
81
|
retry
|
85
82
|
else
|
86
|
-
|
83
|
+
fail Down::TooManyRedirects, "too many redirects"
|
87
84
|
end
|
88
85
|
rescue OpenURI::HTTPError => exception
|
89
86
|
code, message = exception.io.status
|
@@ -107,21 +104,15 @@ module Down
|
|
107
104
|
downloaded_file = copy_to_tempfile(uri.path, open_uri_file)
|
108
105
|
OpenURI::Meta.init downloaded_file, open_uri_file
|
109
106
|
|
110
|
-
downloaded_file.extend DownloadedFile
|
107
|
+
downloaded_file.extend Down::NetHttp::DownloadedFile
|
111
108
|
downloaded_file
|
112
109
|
end
|
113
110
|
|
114
111
|
def open(uri, options = {})
|
115
112
|
options = @options.merge(options)
|
113
|
+
uri = URI(uri)
|
116
114
|
|
117
|
-
|
118
|
-
uri = URI(uri)
|
119
|
-
if uri.class != URI::HTTP && uri.class != URI::HTTPS
|
120
|
-
raise Down::InvalidUrl, "URL scheme needs to be http or https"
|
121
|
-
end
|
122
|
-
rescue URI::InvalidURIError
|
123
|
-
raise Down::InvalidUrl, "URL was invalid"
|
124
|
-
end
|
115
|
+
fail Down::InvalidUrl, "URL scheme needs to be http or https" unless uri.is_a?(URI::HTTP)
|
125
116
|
|
126
117
|
http_class = Net::HTTP
|
127
118
|
|
@@ -152,6 +143,8 @@ module Down
|
|
152
143
|
http.open_timeout = options[:open_timeout] if options.key?(:open_timeout)
|
153
144
|
|
154
145
|
request_headers = options.select { |key, value| key.is_a?(String) }
|
146
|
+
request_headers["Accept-Encoding"] = "" # otherwise FiberError can be raised
|
147
|
+
|
155
148
|
get = Net::HTTP::Get.new(uri.request_uri, request_headers)
|
156
149
|
get.basic_auth(uri.user, uri.password) if uri.user || uri.password
|
157
150
|
|
@@ -164,16 +157,20 @@ module Down
|
|
164
157
|
end
|
165
158
|
end
|
166
159
|
|
167
|
-
|
168
|
-
response = request.resume
|
160
|
+
response = request.resume
|
169
161
|
|
170
|
-
|
171
|
-
|
172
|
-
|
162
|
+
response_error!(response) unless (200..299).cover?(response.code.to_i)
|
163
|
+
|
164
|
+
body_chunks = Enumerator.new do |yielder|
|
165
|
+
begin
|
166
|
+
response.read_body { |chunk| yielder << chunk }
|
167
|
+
rescue => exception
|
168
|
+
request_error!(exception)
|
169
|
+
end
|
173
170
|
end
|
174
171
|
|
175
172
|
Down::ChunkedIO.new(
|
176
|
-
chunks:
|
173
|
+
chunks: body_chunks,
|
177
174
|
size: response["Content-Length"] && response["Content-Length"].to_i,
|
178
175
|
encoding: response.type_params["charset"],
|
179
176
|
rewindable: options.fetch(:rewindable, true),
|
@@ -187,6 +184,8 @@ module Down
|
|
187
184
|
response: response,
|
188
185
|
},
|
189
186
|
)
|
187
|
+
rescue => exception
|
188
|
+
request_error!(exception)
|
190
189
|
end
|
191
190
|
|
192
191
|
private
|
@@ -235,9 +234,7 @@ module Down
|
|
235
234
|
when SocketError
|
236
235
|
raise Down::ConnectionError, "domain name could not be resolved"
|
237
236
|
when Errno::ETIMEDOUT,
|
238
|
-
Timeout::Error
|
239
|
-
Net::OpenTimeout,
|
240
|
-
Net::ReadTimeout
|
237
|
+
Timeout::Error
|
241
238
|
raise Down::TimeoutError, "request timed out"
|
242
239
|
when defined?(OpenSSL) && OpenSSL::SSL::SSLError
|
243
240
|
raise Down::SSLError, exception.message
|
data/lib/down/version.rb
CHANGED
data/lib/down/wget.rb
CHANGED
@@ -16,7 +16,7 @@ require "cgi"
|
|
16
16
|
module Down
|
17
17
|
class Wget < Backend
|
18
18
|
def initialize(*arguments)
|
19
|
-
@arguments = [max_redirect: 2, user_agent: "Down/#{VERSION}"] + arguments
|
19
|
+
@arguments = [max_redirect: 2, user_agent: "Down/#{Down::VERSION}"] + arguments
|
20
20
|
end
|
21
21
|
|
22
22
|
def download(url, *args, max_size: nil, content_length_proc: nil, progress_proc: nil, **options)
|
@@ -43,7 +43,7 @@ module Down
|
|
43
43
|
|
44
44
|
tempfile.open # flush written content
|
45
45
|
|
46
|
-
tempfile.extend DownloadedFile
|
46
|
+
tempfile.extend Down::Wget::DownloadedFile
|
47
47
|
tempfile.url = url
|
48
48
|
tempfile.headers = io.data[:headers]
|
49
49
|
|
@@ -58,7 +58,7 @@ module Down
|
|
58
58
|
def open(url, *args, rewindable: true, **options)
|
59
59
|
arguments = generate_command(url, *args, **options)
|
60
60
|
|
61
|
-
command = Command.execute(arguments)
|
61
|
+
command = Down::Wget::Command.execute(arguments)
|
62
62
|
output = Down::ChunkedIO.new(
|
63
63
|
chunks: command.enum_for(:output),
|
64
64
|
on_close: command.method(:terminate),
|
@@ -125,11 +125,11 @@ module Down
|
|
125
125
|
PIPE_BUFFER_SIZE = 64*1024
|
126
126
|
|
127
127
|
def self.execute(arguments)
|
128
|
-
if
|
129
|
-
stdin_pipe, stdout_pipe, stderr_pipe, status_reaper = Open3.popen3(*arguments)
|
130
|
-
else
|
128
|
+
if defined?(POSIX::Spawn)
|
131
129
|
pid, stdin_pipe, stdout_pipe, stderr_pipe = POSIX::Spawn.popen4(*arguments)
|
132
130
|
status_reaper = Process.detach(pid)
|
131
|
+
else
|
132
|
+
stdin_pipe, stdout_pipe, stderr_pipe, status_reaper = Open3.popen3(*arguments)
|
133
133
|
end
|
134
134
|
|
135
135
|
stdin_pipe.close
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: down
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0
|
4
|
+
version: 4.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janko Marohnić
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|