rack-archive-zip-extract 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []