http_zip 1.0.0 → 2.0.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/CHANGELOG.md +8 -0
- data/README.md +1 -5
- data/http_zip.gemspec +1 -3
- data/lib/http_zip/compression/deflate.rb +20 -0
- data/lib/http_zip/compression/stored.rb +13 -0
- data/lib/http_zip/entry.rb +12 -28
- data/lib/http_zip/errors.rb +2 -1
- data/lib/http_zip/file.rb +0 -1
- data/lib/http_zip/range_request.rb +28 -37
- data/lib/http_zip/version.rb +1 -1
- data/lib/http_zip.rb +2 -0
- metadata +13 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e045495a2ce12199f65be5bf20671418ad350c81ae91fa59c574229ed20eaa22
|
4
|
+
data.tar.gz: fed79c7c440c3323204e105ba449c92bb26d8a1a8b47b258ef1215865a30d7c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39861993eeb2e36bbbb0e96cf620afcc94935dc11160a676ec9c65657cfca840ab98d0c57ab51fd8272ca10ac1d46c37be6f6d866598410bd13012cba3c0e262
|
7
|
+
data.tar.gz: 348b335d82a78a8b37c075981370996723b977ce3ce68c18db72a1e68f64c6ec100ac922ff7303bbafd885fc6360e7d676a980407e65048d51415bcedd26f6d2
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
# 2.0.0
|
2
|
+
* Drop dependency on HTTParty
|
3
|
+
* Remove `RangeRequest.server_supports_content_range?` and `RangeRequest.check_server_supports_content_range!`
|
4
|
+
* Instead of pre-checking for Range request support, we just attempt the request and abort it early if the server doesn't support Range requests. This should make it more reliable for servers that e.g. don't announce support with the Accept-Ranges header or don't support HEAD requests.
|
5
|
+
* Better separation of server error responses: When the server responds with an error, HttpZip now raises `HttpZip::RequestError`. Only when the response is successful, but not `206 Partial Content`, do we raise `HttpZip::ContentRangeError`.
|
6
|
+
|
7
|
+
# 1.0.0
|
8
|
+
* Initial release
|
data/README.md
CHANGED
@@ -42,11 +42,7 @@ content = entry.read
|
|
42
42
|
entry.write_to_file('/path/extracted.txt')
|
43
43
|
```
|
44
44
|
|
45
|
-
If the server that the zip file is hosted on doesn't support Range requests, HttpZip will throw `HttpZip::ContentRangeError`.
|
46
|
-
|
47
|
-
```ruby
|
48
|
-
HttpZip::RangeRequest.server_supports_content_range?(url)
|
49
|
-
```
|
45
|
+
If the server that the zip file is hosted on doesn't support Range requests, HttpZip will throw `HttpZip::ContentRangeError`.
|
50
46
|
|
51
47
|
## Contributing
|
52
48
|
|
data/http_zip.gemspec
CHANGED
@@ -26,11 +26,9 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
27
|
spec.require_paths = ['lib']
|
28
28
|
|
29
|
-
spec.add_runtime_dependency 'httparty', '~> 0.20'
|
30
|
-
|
31
29
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
32
30
|
spec.add_development_dependency 'minitest', '~> 5.15'
|
33
|
-
spec.add_development_dependency 'rake', '~>
|
31
|
+
spec.add_development_dependency 'rake', '~> 12.3', '>= 12.3.3'
|
34
32
|
spec.add_development_dependency 'simplecov', '~> 0.21'
|
35
33
|
spec.add_development_dependency 'webmock', '~> 3.14'
|
36
34
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HttpZip
|
4
|
+
module Compression
|
5
|
+
class Deflate
|
6
|
+
def initialize
|
7
|
+
@inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
8
|
+
end
|
9
|
+
|
10
|
+
def decompress(input)
|
11
|
+
@inflater.inflate(input)
|
12
|
+
end
|
13
|
+
|
14
|
+
def finish
|
15
|
+
@inflater.finish
|
16
|
+
@inflater.close
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/http_zip/entry.rb
CHANGED
@@ -4,7 +4,7 @@ module HttpZip
|
|
4
4
|
# Describes one entry in an HTTP zip archive
|
5
5
|
# @attr_reader [String] name filename of the entry
|
6
6
|
class Entry
|
7
|
-
attr_reader :name
|
7
|
+
attr_reader :name, :compressed_size
|
8
8
|
|
9
9
|
def initialize(url, name, header_offset, central_directory_file_compressed_size)
|
10
10
|
@range_request = HttpZip::RangeRequest.new(url)
|
@@ -20,10 +20,9 @@ module HttpZip
|
|
20
20
|
from = @header_offset + header_size
|
21
21
|
to = @header_offset + header_size + @compressed_size
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
decompressor = compression_method
|
25
24
|
compressed_contents = @range_request.get(from, to)
|
26
|
-
decompress
|
25
|
+
decompressor.decompress(compressed_contents)
|
27
26
|
end
|
28
27
|
|
29
28
|
# Get the decompressed content of the file entry
|
@@ -32,14 +31,13 @@ module HttpZip
|
|
32
31
|
from = @header_offset + header_size
|
33
32
|
to = @header_offset + header_size + @compressed_size
|
34
33
|
|
35
|
-
|
36
|
-
|
34
|
+
decompressor = compression_method
|
37
35
|
::File.open(filename, 'wb') do |out_file|
|
38
36
|
@range_request.get(from, to) do |chunk|
|
39
|
-
decompressed = decompress
|
37
|
+
decompressed = decompressor.decompress(chunk)
|
40
38
|
out_file.write(decompressed)
|
41
39
|
end
|
42
|
-
finish
|
40
|
+
decompressor.finish
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
@@ -57,33 +55,19 @@ module HttpZip
|
|
57
55
|
30 + file_name_length + extra_field_length
|
58
56
|
end
|
59
57
|
|
60
|
-
def
|
58
|
+
def compression_method
|
61
59
|
# which compression method is used?
|
62
|
-
|
60
|
+
algorithm = header[8...10].unpack1('v')
|
63
61
|
|
64
|
-
case
|
62
|
+
case algorithm
|
65
63
|
when 0
|
66
|
-
|
67
|
-
decompress = lambda { |input|
|
68
|
-
input
|
69
|
-
}
|
70
|
-
finish = -> {}
|
64
|
+
HttpZip::Compression::Stored.new
|
71
65
|
when 8
|
72
|
-
|
73
|
-
# DEFLATED content, inflate it
|
74
|
-
decompress = lambda { |input|
|
75
|
-
inflater.inflate(input)
|
76
|
-
}
|
77
|
-
finish = lambda do
|
78
|
-
inflater.finish
|
79
|
-
inflater.close
|
80
|
-
end
|
66
|
+
HttpZip::Compression::Deflate.new
|
81
67
|
else
|
82
68
|
raise HttpZip::ZipError,
|
83
|
-
"Unsupported compression method #{
|
69
|
+
"Unsupported compression method #{algorithm}. HttpZip only supports compression methods 0 (STORED) and 8 (DEFLATE)."
|
84
70
|
end
|
85
|
-
|
86
|
-
[decompress, finish]
|
87
71
|
end
|
88
72
|
end
|
89
73
|
end
|
data/lib/http_zip/errors.rb
CHANGED
data/lib/http_zip/file.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'net/http'
|
4
4
|
|
5
5
|
module HttpZip
|
6
6
|
# Class to make Range requests to a HTTP server
|
@@ -9,7 +9,9 @@ module HttpZip
|
|
9
9
|
#
|
10
10
|
# @param [String] url remote file URL
|
11
11
|
def initialize(url)
|
12
|
-
@
|
12
|
+
@uri = URI(url)
|
13
|
+
@connection = Net::HTTP.new(@uri.host, @uri.port)
|
14
|
+
@connection.use_ssl = true if @uri.scheme == 'https'
|
13
15
|
end
|
14
16
|
|
15
17
|
# Request a partial object via HTTP. If a block is given, yields the response body in chunks.
|
@@ -18,20 +20,10 @@ module HttpZip
|
|
18
20
|
# @param [Integer] to end byte of the range to request. Exclusive.
|
19
21
|
# @yield [chunk] yields a chunk of data to the block
|
20
22
|
# @raise [ContentRangeError] if the server responds with anything other than 206 Partial Content
|
21
|
-
def get(from, to)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
response = HTTParty.get(@url, options) do |chunk|
|
26
|
-
yield chunk if block_given?
|
27
|
-
end
|
28
|
-
|
29
|
-
if response.code != 206
|
30
|
-
# oops, we downloaded the whole file
|
31
|
-
raise ContentRangeError, 'Server does not support the Range header'
|
32
|
-
end
|
33
|
-
|
34
|
-
response.body
|
23
|
+
def get(from, to, &block)
|
24
|
+
request = Net::HTTP::Get.new(@uri)
|
25
|
+
request['Range'] = "bytes=#{from}-#{to - 1}"
|
26
|
+
make_request(request, &block)
|
35
27
|
end
|
36
28
|
|
37
29
|
# Request the last `num_bytes` bytes of the remote file via HTTP.
|
@@ -39,32 +31,31 @@ module HttpZip
|
|
39
31
|
# @param [Integer] num_bytes number of bytes to request
|
40
32
|
# @raise [ContentRangeError] if the server responds with anything other than 206 Partial Content
|
41
33
|
def last(num_bytes)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
raise ContentRangeError, 'Server does not support the Range header'
|
46
|
-
end
|
47
|
-
|
48
|
-
response.body
|
34
|
+
request = Net::HTTP::Get.new(@uri)
|
35
|
+
request['Range'] = "bytes=-#{num_bytes}"
|
36
|
+
make_request(request)
|
49
37
|
end
|
50
38
|
|
51
|
-
|
52
|
-
# otherwise raises an exception.
|
53
|
-
#
|
54
|
-
# @raise [ContentRangeError] if the server does not support the Range header
|
55
|
-
def check_server_supports_content_range!
|
56
|
-
return if self.class.server_supports_content_range?(@url)
|
39
|
+
private
|
57
40
|
|
58
|
-
|
41
|
+
def make_request(request, &block)
|
42
|
+
@connection.start do |http|
|
43
|
+
response = http.request(request) do |res|
|
44
|
+
handle_response_code!(res)
|
45
|
+
res.read_body(&block)
|
46
|
+
end
|
47
|
+
|
48
|
+
response.body unless block_given?
|
49
|
+
end
|
59
50
|
end
|
60
51
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
52
|
+
def handle_response_code!(response)
|
53
|
+
unless response.is_a?(Net::HTTPSuccess)
|
54
|
+
raise RequestError, "Server responded with #{response.code} #{response.message}"
|
55
|
+
end
|
56
|
+
return if response.is_a?(Net::HTTPPartialContent)
|
57
|
+
|
58
|
+
raise ContentRangeError, 'Server does not support the Range header'
|
68
59
|
end
|
69
60
|
end
|
70
61
|
end
|
data/lib/http_zip/version.rb
CHANGED
data/lib/http_zip.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: http_zip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marvin Killing
|
@@ -9,22 +9,8 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-04-
|
12
|
+
date: 2022-04-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: httparty
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
requirements:
|
18
|
-
- - "~>"
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: '0.20'
|
21
|
-
type: :runtime
|
22
|
-
prerelease: false
|
23
|
-
version_requirements: !ruby/object:Gem::Requirement
|
24
|
-
requirements:
|
25
|
-
- - "~>"
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
version: '0.20'
|
28
14
|
- !ruby/object:Gem::Dependency
|
29
15
|
name: bundler
|
30
16
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,14 +45,20 @@ dependencies:
|
|
59
45
|
requirements:
|
60
46
|
- - "~>"
|
61
47
|
- !ruby/object:Gem::Version
|
62
|
-
version: '
|
48
|
+
version: '12.3'
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: 12.3.3
|
63
52
|
type: :development
|
64
53
|
prerelease: false
|
65
54
|
version_requirements: !ruby/object:Gem::Requirement
|
66
55
|
requirements:
|
67
56
|
- - "~>"
|
68
57
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
58
|
+
version: '12.3'
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 12.3.3
|
70
62
|
- !ruby/object:Gem::Dependency
|
71
63
|
name: simplecov
|
72
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,6 +96,7 @@ extra_rdoc_files: []
|
|
104
96
|
files:
|
105
97
|
- ".gitignore"
|
106
98
|
- ".travis.yml"
|
99
|
+
- CHANGELOG.md
|
107
100
|
- Gemfile
|
108
101
|
- LICENSE.txt
|
109
102
|
- README.md
|
@@ -112,6 +105,8 @@ files:
|
|
112
105
|
- bin/setup
|
113
106
|
- http_zip.gemspec
|
114
107
|
- lib/http_zip.rb
|
108
|
+
- lib/http_zip/compression/deflate.rb
|
109
|
+
- lib/http_zip/compression/stored.rb
|
115
110
|
- lib/http_zip/entry.rb
|
116
111
|
- lib/http_zip/errors.rb
|
117
112
|
- lib/http_zip/file.rb
|