down 2.4.3 → 2.5.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/README.md +34 -13
- data/down.gemspec +1 -1
- data/lib/down.rb +48 -13
- data/lib/down/chunked_io.rb +9 -7
- data/lib/down/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b36995e341763d157bd7dfc5e4de2aeee8f7d42e
|
|
4
|
+
data.tar.gz: f4f910e36886c4c64a1f6528a8f773716e28e940
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7c01afed653ed786903043d1b745afa99ec35d5e892d37df644171aad47d2d13a4bda3d98df5ebc890684180488fff62364537c78256e71d2a52c68fd2c69898
|
|
7
|
+
data.tar.gz: 1b61d561a3a0088c8df2e208cd71d15b8a4314de31a1f40d881eeda067396fbc5d0c80d6f78e6796f847717abbd0da3cf813b41cf7fb47dd10cd58e4a1f22454
|
data/README.md
CHANGED
|
@@ -113,18 +113,6 @@ Down.download "http://example.com/image.jpg",
|
|
|
113
113
|
read_timeout: 5
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
-
### Copying to tempfile
|
|
117
|
-
|
|
118
|
-
Down has another "hidden" utility method, `#copy_to_tempfile`, which creates
|
|
119
|
-
a Tempfile out of the given file. The `#download` method uses it internally,
|
|
120
|
-
but it's also publicly available for direct use:
|
|
121
|
-
|
|
122
|
-
```rb
|
|
123
|
-
io # IO object that you want to copy to tempfile
|
|
124
|
-
tempfile = Down.copy_to_tempfile "basename.jpg", io
|
|
125
|
-
tempfile.path #=> "/var/folders/k7/6zx6dx6x7ys3rv3srh0nyfj00000gn/T/down20151116-77262-jgcx65.jpg"
|
|
126
|
-
```
|
|
127
|
-
|
|
128
116
|
## Streaming
|
|
129
117
|
|
|
130
118
|
Down has the ability to access content of the remote file *as it is being
|
|
@@ -157,7 +145,18 @@ end
|
|
|
157
145
|
remote_file.close
|
|
158
146
|
```
|
|
159
147
|
|
|
160
|
-
|
|
148
|
+
You can access the response status and headers of the HTTP request that was made:
|
|
149
|
+
|
|
150
|
+
```rb
|
|
151
|
+
remote_file = Down.open("http://example.com/image.jpg")
|
|
152
|
+
remote_file.data[:status] #=> 200
|
|
153
|
+
remote_file.data[:headers] #=> { ... }
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Note that `Down::NotFound` error will automatically be raised if response
|
|
157
|
+
status was 4xx or 5xx.
|
|
158
|
+
|
|
159
|
+
`Down.open` accepts `:ssl_verify_mode` and `:ssl_ca_cert` options with the same
|
|
161
160
|
semantics as in `open-uri`, and any options with String keys will be
|
|
162
161
|
interpreted as request headers.
|
|
163
162
|
|
|
@@ -196,6 +195,28 @@ io = Down::ChunkedIO.new(
|
|
|
196
195
|
)
|
|
197
196
|
```
|
|
198
197
|
|
|
198
|
+
### Proxy
|
|
199
|
+
|
|
200
|
+
Both `Down.download` and `Down.open` support a `:proxy` option, where you can
|
|
201
|
+
specify a URL to an HTTP proxy which should be used when downloading.
|
|
202
|
+
|
|
203
|
+
```rb
|
|
204
|
+
Down.download("http://example.com/image.jpg", proxy: "http://proxy.org")
|
|
205
|
+
Down.open("http://example.com/image.jpg", proxy: "http://user:password@proxy.org")
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Copying to tempfile
|
|
209
|
+
|
|
210
|
+
Down has another "hidden" utility method, `#copy_to_tempfile`, which creates
|
|
211
|
+
a Tempfile out of the given file. The `#download` method uses it internally,
|
|
212
|
+
but it's also publicly available for direct use:
|
|
213
|
+
|
|
214
|
+
```rb
|
|
215
|
+
io # IO object that you want to copy to tempfile
|
|
216
|
+
tempfile = Down.copy_to_tempfile "basename.jpg", io
|
|
217
|
+
tempfile.path #=> "/var/folders/k7/6zx6dx6x7ys3rv3srh0nyfj00000gn/T/down20151116-77262-jgcx65.jpg"
|
|
218
|
+
```
|
|
219
|
+
|
|
199
220
|
## Supported Ruby versions
|
|
200
221
|
|
|
201
222
|
* MRI 1.9.3
|
data/down.gemspec
CHANGED
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
|
|
|
15
15
|
|
|
16
16
|
spec.add_development_dependency "rake"
|
|
17
17
|
spec.add_development_dependency "minitest", "~> 5.8"
|
|
18
|
-
spec.add_development_dependency "webmock"
|
|
18
|
+
spec.add_development_dependency "webmock", "~> 2.3"
|
|
19
19
|
spec.add_development_dependency "addressable", "< 2.5"
|
|
20
20
|
spec.add_development_dependency "mocha"
|
|
21
21
|
end
|
data/lib/down.rb
CHANGED
|
@@ -5,7 +5,7 @@ require "open-uri"
|
|
|
5
5
|
require "net/http"
|
|
6
6
|
require "tempfile"
|
|
7
7
|
require "fileutils"
|
|
8
|
-
require "cgi
|
|
8
|
+
require "cgi"
|
|
9
9
|
|
|
10
10
|
module Down
|
|
11
11
|
class Error < StandardError; end
|
|
@@ -14,7 +14,7 @@ module Down
|
|
|
14
14
|
|
|
15
15
|
module_function
|
|
16
16
|
|
|
17
|
-
def download(
|
|
17
|
+
def download(uri, options = {})
|
|
18
18
|
warn "Passing :timeout option to `Down.download` is deprecated and will be removed in Down 3. You should use open-uri's :open_timeout and/or :read_timeout." if options.key?(:timeout)
|
|
19
19
|
warn "Passing :progress option to `Down.download` is deprecated and will be removed in Down 3. You should use open-uri's :progress_proc." if options.key?(:progress)
|
|
20
20
|
|
|
@@ -24,10 +24,24 @@ module Down
|
|
|
24
24
|
content_length_proc = options.delete(:content_length_proc)
|
|
25
25
|
timeout = options.delete(:timeout)
|
|
26
26
|
|
|
27
|
+
if options[:proxy]
|
|
28
|
+
proxy = URI(options[:proxy])
|
|
29
|
+
user = proxy.user
|
|
30
|
+
password = proxy.password
|
|
31
|
+
|
|
32
|
+
if user || password
|
|
33
|
+
proxy.user = nil
|
|
34
|
+
proxy.password = nil
|
|
35
|
+
|
|
36
|
+
options[:proxy_http_basic_authentication] = [proxy.to_s, user, password]
|
|
37
|
+
options.delete(:proxy)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
27
41
|
tries = max_redirects + 1
|
|
28
42
|
|
|
29
43
|
begin
|
|
30
|
-
uri = URI
|
|
44
|
+
uri = URI(uri)
|
|
31
45
|
|
|
32
46
|
open_uri_options = {
|
|
33
47
|
"User-Agent" => "Down/#{VERSION}",
|
|
@@ -57,12 +71,12 @@ module Down
|
|
|
57
71
|
|
|
58
72
|
downloaded_file = uri.open(open_uri_options)
|
|
59
73
|
rescue OpenURI::HTTPRedirect => redirect
|
|
60
|
-
|
|
74
|
+
uri = redirect.uri
|
|
61
75
|
retry if (tries -= 1) > 0
|
|
62
|
-
raise Down::NotFound, "too many redirects: #{
|
|
76
|
+
raise Down::NotFound, "too many redirects: #{uri.to_s}"
|
|
63
77
|
rescue => error
|
|
64
78
|
raise if error.is_a?(Down::Error)
|
|
65
|
-
raise Down::NotFound, "file not found: #{
|
|
79
|
+
raise Down::NotFound, "file not found: #{uri.to_s}"
|
|
66
80
|
end
|
|
67
81
|
|
|
68
82
|
# open-uri will return a StringIO instead of a Tempfile if the filesize is
|
|
@@ -85,9 +99,16 @@ module Down
|
|
|
85
99
|
io.close
|
|
86
100
|
end
|
|
87
101
|
|
|
88
|
-
def open(
|
|
89
|
-
uri = URI
|
|
90
|
-
|
|
102
|
+
def open(uri, options = {})
|
|
103
|
+
uri = URI(uri)
|
|
104
|
+
http_class = Net::HTTP
|
|
105
|
+
|
|
106
|
+
if options[:proxy]
|
|
107
|
+
proxy = URI.parse(options[:proxy])
|
|
108
|
+
http_class = Net::HTTP::Proxy(proxy.hostname, proxy.port, proxy.user, proxy.password)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
http = http_class.new(uri.host, uri.port)
|
|
91
112
|
|
|
92
113
|
# taken from open-uri implementation
|
|
93
114
|
if uri.is_a?(URI::HTTPS)
|
|
@@ -109,7 +130,9 @@ module Down
|
|
|
109
130
|
|
|
110
131
|
request = Fiber.new do
|
|
111
132
|
http.start do
|
|
112
|
-
|
|
133
|
+
req = Net::HTTP::Get.new(uri.request_uri, request_headers)
|
|
134
|
+
req.basic_auth(uri.user, uri.password) if uri.user || uri.password
|
|
135
|
+
http.request(req) do |response|
|
|
113
136
|
Fiber.yield response
|
|
114
137
|
response.instance_variable_set("@read", true)
|
|
115
138
|
end
|
|
@@ -118,11 +141,13 @@ module Down
|
|
|
118
141
|
|
|
119
142
|
response = request.resume
|
|
120
143
|
|
|
144
|
+
raise Down::NotFound, "request to #{uri.to_s} returned status #{response.code} and body:\n#{response.body}" if response.code.to_i.between?(400, 599)
|
|
145
|
+
|
|
121
146
|
if response.chunked?
|
|
122
147
|
# Net::HTTP's implementation of reading "Transfer-Encoding: chunked"
|
|
123
148
|
# raises a Fiber error, so we work around it by downloading the whole
|
|
124
149
|
# response body without Enumerators (which internally use Fibers).
|
|
125
|
-
warn "Response from #{
|
|
150
|
+
warn "Response from #{uri.to_s} returned as \"Transfer-Encoding: chunked\", which Down cannot partially download, so the whole response body will be downloaded instead."
|
|
126
151
|
|
|
127
152
|
tempfile = Tempfile.new("down", binmode: true)
|
|
128
153
|
response.read_body { |chunk| tempfile << chunk }
|
|
@@ -130,18 +155,28 @@ module Down
|
|
|
130
155
|
|
|
131
156
|
request.resume # close HTTP connection
|
|
132
157
|
|
|
133
|
-
ChunkedIO.new(
|
|
158
|
+
chunked_io = ChunkedIO.new(
|
|
134
159
|
chunks: Enumerator.new { |y| y << tempfile.read(16*1024) until tempfile.eof? },
|
|
135
160
|
size: tempfile.size,
|
|
136
161
|
on_close: -> { tempfile.close! },
|
|
137
162
|
)
|
|
138
163
|
else
|
|
139
|
-
ChunkedIO.new(
|
|
164
|
+
chunked_io = ChunkedIO.new(
|
|
140
165
|
chunks: response.enum_for(:read_body),
|
|
141
166
|
size: response["Content-Length"] && response["Content-Length"].to_i,
|
|
142
167
|
on_close: -> { request.resume }, # close HTTP connnection
|
|
143
168
|
)
|
|
144
169
|
end
|
|
170
|
+
|
|
171
|
+
chunked_io.data[:status] = response.code.to_i
|
|
172
|
+
chunked_io.data[:headers] = {}
|
|
173
|
+
|
|
174
|
+
response.each_header do |downcased_name, value|
|
|
175
|
+
name = downcased_name.split("-").map(&:capitalize).join("-")
|
|
176
|
+
chunked_io.data[:headers].merge!(name => value)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
chunked_io
|
|
145
180
|
end
|
|
146
181
|
|
|
147
182
|
def copy_to_tempfile(basename, io)
|
data/lib/down/chunked_io.rb
CHANGED
|
@@ -2,12 +2,13 @@ require "tempfile"
|
|
|
2
2
|
|
|
3
3
|
module Down
|
|
4
4
|
class ChunkedIO
|
|
5
|
-
attr_reader :tempfile
|
|
5
|
+
attr_reader :tempfile, :data
|
|
6
6
|
|
|
7
7
|
def initialize(options)
|
|
8
8
|
@size = options.fetch(:size)
|
|
9
9
|
@chunks = options.fetch(:chunks)
|
|
10
10
|
@on_close = options.fetch(:on_close, ->{})
|
|
11
|
+
@data = options.fetch(:data, {})
|
|
11
12
|
@tempfile = Tempfile.new("down", binmode: true)
|
|
12
13
|
|
|
13
14
|
peek_chunk
|
|
@@ -24,7 +25,7 @@ module Down
|
|
|
24
25
|
|
|
25
26
|
def each_chunk
|
|
26
27
|
return enum_for(__method__) if !block_given?
|
|
27
|
-
yield
|
|
28
|
+
yield retrieve_chunk until download_finished?
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
def eof?
|
|
@@ -43,8 +44,11 @@ module Down
|
|
|
43
44
|
private
|
|
44
45
|
|
|
45
46
|
def download_chunk
|
|
47
|
+
write(retrieve_chunk)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def retrieve_chunk
|
|
46
51
|
chunk = @chunks.next
|
|
47
|
-
write(chunk)
|
|
48
52
|
peek_chunk
|
|
49
53
|
chunk
|
|
50
54
|
end
|
|
@@ -64,10 +68,8 @@ module Down
|
|
|
64
68
|
end
|
|
65
69
|
|
|
66
70
|
def terminate_download
|
|
67
|
-
if @on_close
|
|
68
|
-
|
|
69
|
-
@on_close = nil
|
|
70
|
-
end
|
|
71
|
+
@on_close.call if @on_close
|
|
72
|
+
@on_close = nil
|
|
71
73
|
end
|
|
72
74
|
|
|
73
75
|
def write(chunk)
|
data/lib/down/version.rb
CHANGED
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: 2.
|
|
4
|
+
version: 2.5.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-05-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -42,16 +42,16 @@ dependencies:
|
|
|
42
42
|
name: webmock
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - "
|
|
45
|
+
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
47
|
+
version: '2.3'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- - "
|
|
52
|
+
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
54
|
+
version: '2.3'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: addressable
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|