rack-archive-zip-extract 0.0.1

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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/rack/archive/zip/extract.rb +98 -0
  3. metadata +128 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9d1d1fdef39fc5a5b020441ab5e3016d4ceb278e
4
+ data.tar.gz: 9c122a1f1cd9c251625211a264e49ec4779fddc7
5
+ SHA512:
6
+ metadata.gz: 281a9e3aabf364311f5600e8857e579fcd2ddcccbdbb622b9bf2ccb16564bf12ec01c057660e11e5d3bb83bbd126eeda9d1892ee0218db272ddf9598dde5b5e0
7
+ data.tar.gz: 57c7a6d86e25a58b13b23d3d6e16c1241f2094a23de109357443a7014d140934ba2e3d967bebd2abaa06e7313f443976900acd1ea9b32c5a0ff899a08513f75b
@@ -0,0 +1,98 @@
1
+ require 'pathname'
2
+ require 'rack/utils'
3
+ require 'rack/file'
4
+ require 'rack/mime'
5
+ require 'zipruby'
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
+ module Rack::Archive
15
+ module Zip
16
+ class Extract
17
+ SEPS = Rack::File::SEPS
18
+ ALLOWED_VERBS = Rack::File::ALLOWED_VERBS
19
+
20
+ attr_reader :root
21
+
22
+ # @param root [Pathname, #to_path, String] path to document root
23
+ # @param extensions [Array<String>] extensions which is recognized as a zip file
24
+ # @raise [ArgumentError] if +root+ is not a directory
25
+ def initialize(root, extensions: %w[.zip])
26
+ @root = root.kind_of?(Pathname) ? root : Pathname(root)
27
+ @root = @root.expand_path
28
+ @extensions = extensions
29
+ raise ArgumentError, "Not a directory: #{@root}" unless @root.directory?
30
+ end
31
+
32
+ def call(env)
33
+ return [405, {'Allow' => ALLOWED_VERBS.join(', ')}, []] unless ALLOWED_VERBS.include? env['REQUEST_METHOD']
34
+
35
+ path_info = Rack::Utils.unescape(env['PATH_INFO'])
36
+ zip_file = nil
37
+ body = nil
38
+ @extensions.each do |ext|
39
+ zip_file, inner_path = find_zip_file_and_inner_path(path_info, ext)
40
+ body = extract_content(zip_file, inner_path)
41
+ break if body
42
+ end
43
+ return [404, {}, []] if body.nil?
44
+
45
+ [
46
+ 200,
47
+ {
48
+ 'Content-Type' => Rack::Mime.mime_type(::File.extname(path_info)),
49
+ 'Content-Length' => body.bytesize.to_s,
50
+ 'Last-Modified' => zip_file.mtime.httpdate
51
+ },
52
+ [body]
53
+ ]
54
+ end
55
+
56
+ # @param path_info [String]
57
+ # @param extension [String]
58
+ # @return [Array] a pair of Pathname(zip file) and String(file path in zip archive)
59
+ def find_zip_file_and_inner_path(path_info, extension)
60
+ path_parts = path_info_to_clean_parts(path_info)
61
+ current = @root
62
+ zip_file = nil
63
+ while part = path_parts.shift
64
+ zip_file = current + "#{part}#{extension}"
65
+ return zip_file, ::File.join(path_parts) if zip_file.file?
66
+ current += part
67
+ end
68
+ end
69
+
70
+ # @param zip_file_path [Pathname] path to zip file
71
+ # @param inner_path [String] path to file in zip archive
72
+ # @return [String] content
73
+ # @return [nil] if +zip_file_path+ is nil or +inner_path+ is empty
74
+ # @return [nil] if +inner_path+ doesn't exist in zip archive
75
+ def extract_content(zip_file_path, inner_path)
76
+ return if zip_file_path.nil? or inner_path.empty?
77
+ ::Zip::Archive.open zip_file_path.to_path do |archive|
78
+ return if archive.locate_name(inner_path) < 0
79
+ archive.fopen inner_path do |file|
80
+ return file.read
81
+ end
82
+ end
83
+ end
84
+
85
+ # @param path_info [String]
86
+ # @return [Array<String>] parts of clean path
87
+ def path_info_to_clean_parts(path_info)
88
+ parts = path_info.split SEPS
89
+ clean = []
90
+ parts.each do |part|
91
+ next if part.empty? || part == '.'
92
+ part == '..' ? clean.pop : clean << part
93
+ end
94
+ clean
95
+ end
96
+ end
97
+ end
98
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-archive-zip-extract
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - KITAITI Makoto
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: zipruby
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: test-unit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit-notify
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubygems-tasks
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.2'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.2'
97
+ description: Rack::Archive::Zip::Extract serves files in zip archives.
98
+ email: KitaitiMakoto@gmail.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - lib/rack/archive/zip/extract.rb
104
+ homepage: https://github.com/KitaitiMakoto/rack-archive-zip-extract
105
+ licenses:
106
+ - MIT
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 2.0.0
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 2.2.0
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Zip file server
128
+ test_files: []