rack-archive-zip-extract 0.0.4 → 0.0.5

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: 8f335e345e79786674c599d49801cfab192613ec
4
- data.tar.gz: 05268821dfdf5582e97e7580accbcf2cbe9a187b
3
+ metadata.gz: 07bea84e8dd599718d60edf93979698acfa2ca84
4
+ data.tar.gz: 755f333cee8ead09814ef8d2253016ad5b9a4d0e
5
5
  SHA512:
6
- metadata.gz: 0d32ed10d8c653fbc13463163c94198af348cfdfcd43b9e916cf92762def4eafe2419a47e40e1a2a618ffcfdd41d9f078be5a98202d649e3b3ce3a56511e7f96
7
- data.tar.gz: 61a4b7dc23f899ce983976f0d334b8bca21459813a6aab5e43e3b69c7cf41789aefa9bda5f139640b7c455aa48174c7e343b05eb54d0ee016195dc7f99c75ae0
6
+ metadata.gz: 7d5e00114d0e8638ae5c7894ba507e5600c500d25be33f3f9528b5721996d7559501c7cca4983e1c0bbaed8e98e71150ba49a8104a7620c22fa80bbf66b85235
7
+ data.tar.gz: 661f0577924ef2c25f5199cfab991f4705f76b5d83dba65a0b243b02323ef762720a8c043571fdc9f2853521e7f655fbc8f056b4cb050aa81e6c40e3cca6f236
data/CHANGELOG.markdown CHANGED
@@ -1,6 +1,12 @@
1
1
  CHANGELOG
2
2
  =========
3
3
 
4
+ 0.0.5
5
+ -----
6
+
7
+ * [BUG FIX]Duplicate extensions before freezing
8
+ * Send ETag header
9
+
4
10
  0.0.4
5
11
  -----
6
12
 
@@ -15,52 +15,63 @@ module Rack::Archive
15
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
17
  include Rack::Utils
18
+ extend Rack::Utils
18
19
 
19
20
  SEPS = Rack::File::SEPS
20
21
  DOT = '.'.freeze
21
22
  DOUBLE_DOT = '..'.freeze
22
- ALLOWED_METHODS = Rack::File::ALLOWED_VERBS.join(', ').freeze
23
- ALLOW = 'Allow'.freeze
24
23
  CONTENT_TYPE = 'Content-Type'.freeze
25
24
  CONTENT_LENGTH = 'Content-Length'.freeze
26
25
  IF_MODIFIED_SINCE = 'HTTP_IF_MODIFIED_SINCE'.freeze
27
26
  LAST_MODIFIED = 'Last-Modified'.freeze
27
+ IF_NONE_MATCH = 'HTTP_IF_NONE_MATCH'.freeze
28
+ ETAG = 'ETag'.freeze
28
29
  REQUEST_METHOD = 'REQUEST_METHOD'.freeze
29
30
  PATH_INFO = 'PATH_INFO'.freeze
31
+ METHOD_NOT_ALLOWED = [status_code(:method_not_allowd), {'Allow'.freeze => Rack::File::ALLOWED_VERBS.join(', ').freeze}, []]
32
+ NOT_FOUND = [status_code(:not_found), {}, []]
33
+ NOT_MODIFIED = [status_code(:not_modified), {}, []]
30
34
 
31
35
  # @param root [Pathname, #to_path, String] path to document root
32
36
  # @param extensions [Array<String>] extensions which is recognized as a zip file
37
+ # @param buffer_size [Integer] buffer size to read content, in bytes
33
38
  # @raise [ArgumentError] if +root+ is not a directory
34
39
  def initialize(root, extensions: %w[.zip], buffer_size: ExtractedFile::BUFFER_SIZE)
35
40
  @root = root.kind_of?(Pathname) ? root : Pathname(root)
36
41
  @root = @root.expand_path
37
- @extensions = extensions.each {|extention| extention.freeze}.lazy
42
+ @extensions = extensions.map {|extention| extention.dup.freeze}.lazy
38
43
  @buffer_size = buffer_size
39
44
  raise ArgumentError, "Not a directory: #{@root}" unless @root.directory?
40
45
  end
41
46
 
42
47
  def call(env)
43
- return [status_code(:method_not_allowd), {ALLOW => ALLOWED_METHODS}, []] unless Rack::File::ALLOWED_VERBS.include? env[REQUEST_METHOD]
48
+ return METHOD_NOT_ALLOWED unless Rack::File::ALLOWED_VERBS.include? env[REQUEST_METHOD]
44
49
 
45
50
  path_info = unescape(env[PATH_INFO])
46
51
  file = @extensions.map {|ext|
47
52
  zip_file, inner_path = find_zip_file_and_inner_path(path_info, ext)
48
53
  extract_file(zip_file, inner_path)
49
54
  }.select {|file| file}.first
50
- return [status_code(:not_found), {}, []] if file.nil?
55
+ return NOT_FOUND if file.nil?
51
56
 
52
57
  if_modified_since = env[IF_MODIFIED_SINCE]
53
58
  if_modified_since = Time.parse(if_modified_since) if if_modified_since
54
- if if_modified_since and file.mtime <= if_modified_since
59
+
60
+ if_none_match = env[IF_NONE_MATCH]
61
+ etag = file.name.hash.to_s(16) + file.mtime.hash.to_s(16)
62
+
63
+ if if_modified_since && file.mtime <= if_modified_since or
64
+ if_none_match && if_none_match == etag
55
65
  file.close
56
- [status_code(:not_modified), {}, []]
66
+ NOT_MODIFIED
57
67
  else
58
68
  [
59
69
  status_code(:ok),
60
70
  {
61
71
  CONTENT_TYPE => Rack::Mime.mime_type(::File.extname(path_info)),
62
72
  CONTENT_LENGTH => file.size.to_s,
63
- LAST_MODIFIED => file.mtime.httpdate
73
+ LAST_MODIFIED => file.mtime.httpdate,
74
+ ETAG => etag
64
75
  },
65
76
  file
66
77
  ]
@@ -83,7 +94,7 @@ module Rack::Archive
83
94
 
84
95
  # @param zip_file_path [Pathname] path to zip file
85
96
  # @param inner_path [String] path to file in zip archive
86
- # @return [Zip::File]
97
+ # @return [ExtractedFile]
87
98
  # @return [nil] if +zip_file_path+ is nil or +inner_path+ is empty
88
99
  # @return [nil] if +inner_path+ doesn't exist in zip archive
89
100
  def extract_file(zip_file_path, inner_path)
@@ -115,6 +126,7 @@ module Rack::Archive
115
126
 
116
127
  # @param archive [Zip::Archive]
117
128
  # @param path [String]
129
+ # @param buffer_size [Integer]
118
130
  # @raise ArgumentError when +archive+ already closed
119
131
  def initialize(archive, path, buffer_size=BUFFER_SIZE)
120
132
  raise ArgumentError, 'archive already closed' unless archive.open?
@@ -129,6 +141,10 @@ module Rack::Archive
129
141
  end
130
142
  end
131
143
 
144
+ def name
145
+ @file.name
146
+ end
147
+
132
148
  def mtime
133
149
  @file.mtime
134
150
  end
@@ -43,6 +43,29 @@ class TestRackArchiveZipExtract < Test::Unit::TestCase
43
43
  assert_empty response.body
44
44
  end
45
45
 
46
+ def test_request_to_file_in_zip_returns_etag
47
+ response = request('/sample/sample.txt')
48
+
49
+ assert_not_nil response['ETag']
50
+ end
51
+
52
+ def test_request_to_old_file_with_etag_returns_not_modified
53
+ path = '/sample/sample.txt'
54
+ etag = request(path)['ETag']
55
+
56
+ response = request(path, @zip, {'HTTP_IF_NONE_MATCH' => etag})
57
+
58
+ assert_equal 304, response.status
59
+ end
60
+
61
+ def test_request_to_old_file_with_etag_returns_no_content
62
+ path = '/sample/sample.txt'
63
+ etag = request(path)['ETag']
64
+ response = request(path, @zip, {'HTTP_IF_NONE_MATCH' => etag})
65
+
66
+ assert_empty response.body
67
+ end
68
+
46
69
  class TestStatusCode < self
47
70
  data(
48
71
  'file in zip' => [200, '/sample/sample.txt'],
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
4
+ version: 0.0.5
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-26 00:00:00.000000000 Z
11
+ date: 2014-05-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1'
47
+ version: '2'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1'
54
+ version: '2'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: test-unit-notify
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -114,7 +114,7 @@ files:
114
114
  - test/fixtures/sample-zip/sample.xml
115
115
  - test/fixtures/sample-zip/subdir/sample.txt
116
116
  - test/test_rack-archive-zip-extract.rb
117
- homepage: https://github.com/KitaitiMakoto/rack-archive-zip-extract
117
+ homepage: http://rubydoc.info/gems/rack-archive-zip-extract/
118
118
  licenses:
119
119
  - MIT
120
120
  metadata: {}
@@ -134,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
134
  version: '0'
135
135
  requirements: []
136
136
  rubyforge_project:
137
- rubygems_version: 2.2.0
137
+ rubygems_version: 2.2.2
138
138
  signing_key:
139
139
  specification_version: 4
140
140
  summary: Zip file server