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 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