s3_proxy 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dea44cf361b902f466809821fe30b411db50add3
4
- data.tar.gz: 8d929051a8382e50fad93796c980613c9e140f1d
3
+ metadata.gz: b87ae0701382cfcc91e7b233bd68ecef70546677
4
+ data.tar.gz: 5c6344cbac68b8b9b06b5a032aa9d0db5e4a1821
5
5
  SHA512:
6
- metadata.gz: cb0718bf8606acda33658d475862aff4482bdf59afb2fffb08a86da53ae421a266054de9c32e38c9d09c8bd71608c87294e08703e6df0c5d53e9e1372c94ce31
7
- data.tar.gz: 4cb738cac629cd46beec034f40286790f4c5cb738a6519f10586f50daba3d86f5e8d2667d474739fb93df127dd2ae885f061ec34f3e23b9b21630e5c6733b252
6
+ metadata.gz: 636b2f85af7915558cae9107de37cc2498e961909af4821ca2621bbaa531ad3b2711a01a33b7f00f6053f63faa0a352043807e7956279d6ad80174d3dcd9a79c
7
+ data.tar.gz: 3f42b9f14ac02405ca8489f76211f01f4e8a1c665f75dbe29463dbb122875f630f43aa0f182d5b4de4836caa4933d0f6dad11260dbd5768178517af80572cb45
@@ -8,28 +8,60 @@ module S3Proxy
8
8
  end
9
9
 
10
10
  def call(env)
11
- return Errors.method_not_allowed unless env['REQUEST_METHOD'] == 'GET'
11
+ return Errors.method_not_allowed unless %w(GET HEAD).include?(env['REQUEST_METHOD'])
12
12
  return Errors.not_found if env['PATH_INFO'].empty?
13
13
 
14
- _, bucket, key = env['PATH_INFO'].split('/', 3)
15
- path = {bucket: bucket, key: key}
14
+ # When used as a forward proxy
15
+ if env['HTTP_HOST'] =~ /(.+)\.s3\.amazonaws\.com/
16
+ bucket = $1
17
+ _, key = env['PATH_INFO'].split('/', 2)
18
+ else
19
+ _, bucket, key = env['PATH_INFO'].split('/', 3)
20
+ end
21
+
22
+ return Errors.not_found unless bucket && key
23
+
24
+ req = {bucket: bucket, key: key}
25
+
26
+ req[:if_match] = env['HTTP_IF_MATCH'] if env['HTTP_IF_MATCH']
27
+ req[:if_none_match] = env['HTTP_IF_NONE_MATCH'] if env['HTTP_IF_NONE_MATCH']
28
+ req[:if_modified_since] = env['HTTP_IF_MODIFIED_SINCE'] if env['HTTP_IF_MODIFIED_SINCE']
29
+ req[:if_unmodified_since] = env['HTTP_IF_UNMODIFIED_SINCE'] if env['HTTP_UNMODIFIED_SINCE']
30
+
31
+ head = s3.head_object(req)
16
32
 
17
- head = s3.head_object(path)
18
33
  return Errors.not_found unless head
19
34
 
20
- if env['rack.hijack?']
21
- hijack env, path, head
22
- else
23
- gentle env, path, head
35
+ case env['REQUEST_METHOD']
36
+ when 'HEAD'
37
+ gentle env, req, head
38
+ when 'GET'
39
+ if env['rack.hijack?']
40
+ hijack env, req, head
41
+ else
42
+ gentle env, req, head
43
+ end
24
44
  end
25
45
 
26
- rescue Aws::S3::Errors::NoSuchKey
46
+ rescue Aws::S3::Errors::NoSuchKey, Aws::S3::Errors::NotFound
27
47
  return Errors.not_found
48
+
49
+ rescue Aws::S3::Errors::NotModified
50
+ return Errors.not_modified
51
+
52
+ rescue Aws::S3::Errors::PreconditionFailed
53
+ return Errors.precondition_failed
54
+
55
+ rescue NameError => e
56
+ # https://github.com/aws/aws-sdk-core-ruby/pull/65
57
+ raise e unless e.message == "wrong constant name 412Error"
58
+
59
+ return Errors.precondition_failed
28
60
  end
29
61
 
30
62
  private
31
63
 
32
- def hijack(env, path, head)
64
+ def hijack(env, request, head)
33
65
  env['rack.hijack'].call
34
66
 
35
67
  io = env['rack.hijack_io']
@@ -39,31 +71,45 @@ module S3Proxy
39
71
  io.write "Connection: close\r\n"
40
72
  io.write "Content-Type: #{head.content_type}\r\n"
41
73
  io.write "Content-Length: #{head.content_length}\r\n"
74
+ io.write "ETag: #{head.etag}\r\n"
75
+ io.write "Last-Modified: #{head.last_modified}\r\n"
42
76
  io.write "\r\n"
43
77
  io.flush
44
78
 
45
- s3.get_object(path, target: io)
79
+ s3.get_object(request, target: io)
46
80
  ensure
47
81
  io.close
48
82
  end
49
83
  return [200, {}, ['']]
50
84
  end
51
85
 
52
- def gentle(env, path, head)
53
- fiber = Fiber.new do
54
- s3.get_object(path) do |chunk|
55
- Fiber.yield(chunk)
86
+ def gentle(env, request, head)
87
+ case env['REQUEST_METHOD']
88
+ when 'GET'
89
+ fiber = Fiber.new do
90
+ s3.get_object(request) do |chunk|
91
+ Fiber.yield(chunk)
92
+ end
93
+ Fiber.yield(nil)
56
94
  end
57
- Fiber.yield(nil)
58
- end
59
95
 
60
- body = Enumerator.new do |y|
61
- while n = fiber.resume
62
- y << n
96
+ body = Enumerator.new do |y|
97
+ while n = fiber.resume
98
+ y << n
99
+ end
63
100
  end
101
+ when 'HEAD'
102
+ body = ['']
64
103
  end
65
104
 
66
- [200, {'Content-Type' => head.content_type, 'Content-Length' => head.content_length.to_s}, body]
105
+ headers = {
106
+ 'Content-Type' => head.content_type,
107
+ 'Content-Length' => head.content_length.to_s,
108
+ 'Last-Modified' => head.last_modified,
109
+ 'ETag' => head.etag,
110
+ }
111
+
112
+ [200, headers, body]
67
113
  end
68
114
 
69
115
  def s3
@@ -84,6 +130,14 @@ module S3Proxy
84
130
  [403, {'Content-Type' => 'text/plain'}, ["forbidden"]]
85
131
  end
86
132
 
133
+ def precondition_failed
134
+ [412, {'Content-Type' => 'text/plain'}, ["precondition failed"]]
135
+ end
136
+
137
+ def not_modified
138
+ [304, {'Content-Type' => 'text/plain'}, ["not modified"]]
139
+ end
140
+
87
141
  def unknown(code)
88
142
  [code, {'Content-Type' => 'text/plain'}, ["Error: #{code}"]]
89
143
  end
@@ -1,3 +1,3 @@
1
1
  module S3Proxy
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: s3_proxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shota Fukumori (sora_h)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-10 00:00:00.000000000 Z
11
+ date: 2014-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -122,3 +122,4 @@ signing_key:
122
122
  specification_version: 4
123
123
  summary: S3 reverse proxy rack app that accepts multiple buckets
124
124
  test_files: []
125
+ has_rdoc: