down 4.0.1 → 4.1.0
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/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
|