rack-archive-zip-extract 0.0.1 → 0.0.2
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/rack/archive/zip/extract.rb +59 -34
- 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: 367946e3ae493b7beb2c8a894a737861d8819a44
|
4
|
+
data.tar.gz: 1b2509141f86cde9c02afb4ce3174136db6d57fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0200cd1fa15c0182d6597d21dd25796c5c928753d252060a44d1255a0c10d1aa5a91ad910387321b8073e2b12773066322b06bf43dc49f705cf27e4e3ec1364d
|
7
|
+
data.tar.gz: 36807535e98a5b0947fef9066be63b5d47ad09a951854b211ea894960ddc92c61f92a1d57448a4141412e73170122a04750aa38ee4a4ce065201f874ee9e1d42
|
@@ -4,18 +4,30 @@ require 'rack/file'
|
|
4
4
|
require 'rack/mime'
|
5
5
|
require 'zipruby'
|
6
6
|
|
7
|
-
# {Rack::Archive::Zip::Extract Rack::Archive::Zip::Extract} is a Rack application which serves files in zip archives.
|
8
|
-
# @example
|
9
|
-
# run Rack::Archive::Zip::Extract.new('path/to/docroot')
|
10
|
-
# @example
|
11
|
-
# run Rack::Archive::Zip::Extract.new('path/to/docroot', extensions: %w[.epub .zip .jar .odt .docx])
|
12
|
-
# @note
|
13
|
-
# {Rack::Archive::Zip::Extract Rack::Archive::Zip::Extract} does not serve a zip file itself. Use Rack::File or so to do so.
|
14
7
|
module Rack::Archive
|
15
8
|
module Zip
|
9
|
+
# {Rack::Archive::Zip::Extract Rack::Archive::Zip::Extract} is a Rack application which serves files in zip archives.
|
10
|
+
# @example
|
11
|
+
# run Rack::Archive::Zip::Extract.new('path/to/docroot')
|
12
|
+
# @example
|
13
|
+
# run Rack::Archive::Zip::Extract.new('path/to/docroot', extensions: %w[.epub .zip .jar .odt .docx])
|
14
|
+
# @note
|
15
|
+
# {Rack::Archive::Zip::Extract Rack::Archive::Zip::Extract} does not serve a zip file itself. Use Rack::File or so to do so.
|
16
16
|
class Extract
|
17
|
+
include Rack::Utils
|
18
|
+
|
17
19
|
SEPS = Rack::File::SEPS
|
20
|
+
DOT = '.'.freeze
|
21
|
+
DOUBLE_DOT = '..'.freeze
|
22
|
+
COMMA = ','.freeze
|
18
23
|
ALLOWED_VERBS = Rack::File::ALLOWED_VERBS
|
24
|
+
ALLOW = 'Allow'.freeze
|
25
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
26
|
+
CONTENT_LENGTH = 'Content-Length'.freeze
|
27
|
+
IF_MODIFIED_SINCE = 'HTTP_IF_MODIFIED_SINCE'.freeze
|
28
|
+
LAST_MODIFIED = 'Last-Modified'.freeze
|
29
|
+
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
|
30
|
+
PATH_INFO = 'PATH_INFO'.freeze
|
19
31
|
|
20
32
|
attr_reader :root
|
21
33
|
|
@@ -30,40 +42,48 @@ module Rack::Archive
|
|
30
42
|
end
|
31
43
|
|
32
44
|
def call(env)
|
33
|
-
return [
|
45
|
+
return [status_code(:method_not_allowd), {ALLOW => ALLOWED_VERBS.join(COMMA)}, []] unless ALLOWED_VERBS.include? env[REQUEST_METHOD]
|
34
46
|
|
35
|
-
path_info =
|
47
|
+
path_info = unescape(env[PATH_INFO])
|
48
|
+
if_modified_since = env[IF_MODIFIED_SINCE]
|
49
|
+
if_modified_since = Time.parse(if_modified_since) if if_modified_since
|
36
50
|
zip_file = nil
|
37
51
|
body = nil
|
52
|
+
file_size = nil
|
53
|
+
mtime = nil
|
38
54
|
@extensions.each do |ext|
|
39
55
|
zip_file, inner_path = find_zip_file_and_inner_path(path_info, ext)
|
40
|
-
body = extract_content(zip_file, inner_path)
|
41
|
-
break if
|
56
|
+
body, file_size, mtime = extract_content(zip_file, inner_path, if_modified_since)
|
57
|
+
break if mtime
|
42
58
|
end
|
43
|
-
return [
|
59
|
+
return [status_code(:not_found), {}, []] if mtime.nil?
|
44
60
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
61
|
+
if if_modified_since and mtime <= if_modified_since
|
62
|
+
[status_code(:not_modified), {}, []]
|
63
|
+
else
|
64
|
+
[
|
65
|
+
status_code(:ok),
|
66
|
+
{
|
67
|
+
CONTENT_TYPE => Rack::Mime.mime_type(::File.extname(path_info)),
|
68
|
+
CONTENT_LENGTH => file_size.to_s,
|
69
|
+
LAST_MODIFIED => mtime.httpdate
|
70
|
+
},
|
71
|
+
[body]
|
72
|
+
]
|
73
|
+
end
|
54
74
|
end
|
55
75
|
|
56
76
|
# @param path_info [String]
|
57
77
|
# @param extension [String]
|
58
78
|
# @return [Array] a pair of Pathname(zip file) and String(file path in zip archive)
|
59
79
|
def find_zip_file_and_inner_path(path_info, extension)
|
60
|
-
|
80
|
+
segments = path_info_to_clean_segments(path_info)
|
61
81
|
current = @root
|
62
82
|
zip_file = nil
|
63
|
-
while
|
64
|
-
zip_file = current + "#{
|
65
|
-
return zip_file, ::File.join(
|
66
|
-
current +=
|
83
|
+
while segment = segments.shift
|
84
|
+
zip_file = current + "#{segment}#{extension}"
|
85
|
+
return zip_file, ::File.join(segments) if zip_file.file?
|
86
|
+
current += segment
|
67
87
|
end
|
68
88
|
end
|
69
89
|
|
@@ -72,24 +92,29 @@ module Rack::Archive
|
|
72
92
|
# @return [String] content
|
73
93
|
# @return [nil] if +zip_file_path+ is nil or +inner_path+ is empty
|
74
94
|
# @return [nil] if +inner_path+ doesn't exist in zip archive
|
75
|
-
def extract_content(zip_file_path, inner_path)
|
95
|
+
def extract_content(zip_file_path, inner_path, if_modified_since)
|
76
96
|
return if zip_file_path.nil? or inner_path.empty?
|
77
97
|
::Zip::Archive.open zip_file_path.to_path do |archive|
|
78
98
|
return if archive.locate_name(inner_path) < 0
|
79
99
|
archive.fopen inner_path do |file|
|
80
|
-
|
100
|
+
if if_modified_since and file.mtime <= if_modified_since
|
101
|
+
return nil, nil, file.mtime
|
102
|
+
else
|
103
|
+
return file.read, file.size, file.mtime
|
104
|
+
end
|
81
105
|
end
|
82
106
|
end
|
83
107
|
end
|
84
108
|
|
85
109
|
# @param path_info [String]
|
86
|
-
# @return [Array<String>]
|
87
|
-
|
88
|
-
|
110
|
+
# @return [Array<String>] segments of clean path
|
111
|
+
# @see http://rubydoc.info/gems/rack/Rack/File#_call-instance_method Algorithm stolen from Rack::File#_call
|
112
|
+
def path_info_to_clean_segments(path_info)
|
113
|
+
segments = path_info.split SEPS
|
89
114
|
clean = []
|
90
|
-
|
91
|
-
next if
|
92
|
-
|
115
|
+
segments.each do |segment|
|
116
|
+
next if segment.empty? || segment == DOT
|
117
|
+
segment == DOUBLE_DOT ? clean.pop : clean << segment
|
93
118
|
end
|
94
119
|
clean
|
95
120
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-archive-zip-extract
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- KITAITI Makoto
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|