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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 198002a2240137218bad98e7af9f0d336616ecc4
4
- data.tar.gz: 2db047e9147e441b586a01cf6a0dbbd95363f728
3
+ metadata.gz: '08443f7ebc7a853be6b2c24d0cff24795af18bdf'
4
+ data.tar.gz: c723068fcc5675755bb90f51ab8eab1fe21a3cef
5
5
  SHA512:
6
- metadata.gz: 224602303ca6a6bf32ab059bfca9c60974c28a14f4b2da12d10245254ace51a521f921ad7130c7bf5b72368f13a9f20309cae4ec0d2a5198d1bc0b6a1a8fc96d
7
- data.tar.gz: b79fb3b79c67dc6aa2fd2c1735a7d27befcb7fc5ff603ae0725e98207571bc4289f39e8961114229b92665ddc6d2c24c33faa6f62248d54b94065781b631770e
6
+ metadata.gz: 0b9b5ec3d60c3dc7d035bf79e29767d22e2de97b05e060fcc477da5ea3d9015b8f19c26b2414e94643268123fedaa427e2e3d69c47d614109874788315bc93dd
7
+ data.tar.gz: e98698c9fb10d4163b3ec33eb63b1ef38cb62b069835620c01ed93d7994d38b99c3b55a3f5eace5fe628b1f9c1fb6d93a17ea1e6cae75bb3d119bb5a484a391a
@@ -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
@@ -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
- begin
63
- response = get(url, **options, &block)
64
- response_error!(response) if !response.status.success?
65
- rescue => exception
66
- request_error!(exception)
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: response.body.enum_for(:each),
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
@@ -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
- if uri.class != URI::HTTP && uri.class != URI::HTTPS
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
- raise Down::TooManyRedirects, "too many redirects"
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
- begin
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
- begin
168
- response = request.resume
160
+ response = request.resume
169
161
 
170
- response_error!(response) unless (200..299).cover?(response.code.to_i)
171
- rescue => exception
172
- request_error!(exception)
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: response.enum_for(:read_body),
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
@@ -1,5 +1,5 @@
1
1
  # frozen-string-literal: true
2
2
 
3
3
  module Down
4
- VERSION = "4.0.1"
4
+ VERSION = "4.1.0"
5
5
  end
@@ -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 RUBY_ENGINE == "jruby"
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.1
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-07-08 00:00:00.000000000 Z
11
+ date: 2017-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest