miasma 0.2.0 → 0.2.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/CHANGELOG.md +7 -0
- data/lib/miasma/contrib/aws.rb +40 -4
- data/lib/miasma/contrib/aws/storage.rb +25 -3
- data/lib/miasma/contrib/open_stack.rb +1 -0
- data/lib/miasma/error.rb +3 -0
- data/lib/miasma/models/storage.rb +5 -0
- data/lib/miasma/models/storage/file.rb +31 -2
- data/lib/miasma/types/api.rb +2 -2
- data/lib/miasma/version.rb +1 -1
- 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: 2d96b86dbb247d22f846177758907886638e4eec
|
4
|
+
data.tar.gz: 5c052aae2f76878d06868e1c60daa01b38921fd2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13d34cdd67c7bfea1470f25ffcd0a37a225a9900c59d1c49fa69a61e302e5dfa733f51c4d85ddd04e402b43e261f847bd2ba83c8b0899302a6cae25b933df57e
|
7
|
+
data.tar.gz: e7e9a45b0ea4380ba9474b2ba6cdf26f3265bdcff1ce2ebe68a4a193bf4f931b83f347668a8e8ddd6f6d02660d7c04ba3a6813bc8f4579df5b32405c6279c854
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# v0.2.2
|
2
|
+
* Add support for pre-signed AWS URLs
|
3
|
+
* Add `#url` method to `Storage::File` model
|
4
|
+
* Relax content-type checks on response for more reliable auto-parse (#2)
|
5
|
+
* Basic abstract spec coverage on storage
|
6
|
+
* Fix response body result by adding streaming detection
|
7
|
+
|
1
8
|
# v0.2.0
|
2
9
|
* Add initial OpenStack provider support
|
3
10
|
* Refactor of Rackspace provider support (build off OpenStack)
|
data/lib/miasma/contrib/aws.rb
CHANGED
@@ -156,23 +156,52 @@ module Miasma
|
|
156
156
|
@service = service
|
157
157
|
end
|
158
158
|
|
159
|
-
# Generate the signature
|
159
|
+
# Generate the signature string for AUTH
|
160
160
|
#
|
161
161
|
# @param http_method [Symbol] HTTP request method
|
162
162
|
# @param path [String] request path
|
163
163
|
# @param opts [Hash] request options
|
164
164
|
# @return [String] signature
|
165
165
|
def generate(http_method, path, opts)
|
166
|
+
signature = generate_signature(http_method, path, opts)
|
167
|
+
"#{algorithm} Credential=#{access_key}/#{credential_scope}, SignedHeaders=#{signed_headers(opts[:headers])}, Signature=#{signature}"
|
168
|
+
end
|
169
|
+
|
170
|
+
# Generate URL with signed params
|
171
|
+
#
|
172
|
+
# @param http_method [Symbol] HTTP request method
|
173
|
+
# @param path [String] request path
|
174
|
+
# @param opts [Hash] request options
|
175
|
+
# @return [String] signature
|
176
|
+
def generate_url(http_method, path, opts)
|
177
|
+
opts[:params].merge!(
|
178
|
+
Smash.new(
|
179
|
+
'X-Amz-SignedHeaders' => signed_headers(opts[:headers]),
|
180
|
+
'X-Amz-Algorithm' => algorithm,
|
181
|
+
'X-Amz-Credential' => "#{access_key}/#{credential_scope}"
|
182
|
+
)
|
183
|
+
)
|
184
|
+
signature = generate_signature(http_method, path, opts.merge(:body => 'UNSIGNED-PAYLOAD'))
|
185
|
+
params = opts[:params].merge('X-Amz-Signature' => signature)
|
186
|
+
"https://#{opts[:headers]['Host']}/#{path}?#{canonical_query(params)}"
|
187
|
+
end
|
188
|
+
|
189
|
+
# Generate the signature
|
190
|
+
#
|
191
|
+
# @param http_method [Symbol] HTTP request method
|
192
|
+
# @param path [String] request path
|
193
|
+
# @param opts [Hash] request options
|
194
|
+
# @return [String] signature
|
195
|
+
def generate_signature(http_method, path, opts)
|
166
196
|
to_sign = [
|
167
197
|
algorithm,
|
168
198
|
AwsApiCore.time_iso8601,
|
169
199
|
credential_scope,
|
170
200
|
hashed_canonical_request(
|
171
|
-
build_canonical_request(http_method, path, opts)
|
201
|
+
can_req = build_canonical_request(http_method, path, opts)
|
172
202
|
)
|
173
203
|
].join("\n")
|
174
204
|
signature = sign_request(to_sign)
|
175
|
-
"#{algorithm} Credential=#{access_key}/#{credential_scope}, SignedHeaders=#{signed_headers(opts[:headers])}, Signature=#{signature}"
|
176
205
|
end
|
177
206
|
|
178
207
|
# Sign the request
|
@@ -226,6 +255,9 @@ module Miasma
|
|
226
255
|
# @param opts [Hash] request options
|
227
256
|
# @return [String] canonical request string
|
228
257
|
def build_canonical_request(http_method, path, opts)
|
258
|
+
unless(path.start_with?('/'))
|
259
|
+
path = "/#{path}"
|
260
|
+
end
|
229
261
|
[
|
230
262
|
http_method.to_s.upcase,
|
231
263
|
path,
|
@@ -281,7 +313,11 @@ module Miasma
|
|
281
313
|
elsif(options[:form])
|
282
314
|
body = URI.encode_www_form(options[:form])
|
283
315
|
end
|
284
|
-
|
316
|
+
if(body == 'UNSIGNED-PAYLOAD')
|
317
|
+
body
|
318
|
+
else
|
319
|
+
hmac.hexdigest_of(body)
|
320
|
+
end
|
285
321
|
end
|
286
322
|
|
287
323
|
end
|
@@ -167,7 +167,7 @@ module Miasma
|
|
167
167
|
end
|
168
168
|
end.compact
|
169
169
|
]
|
170
|
-
if(file.attributes[:body].is_a?(IO) && file.body.length >=
|
170
|
+
if(file.attributes[:body].is_a?(IO) && file.body.length >= Storage::MAX_BODY_SIZE_FOR_STRINGIFY)
|
171
171
|
upload_id = request(
|
172
172
|
args.merge(
|
173
173
|
Smash.new(
|
@@ -182,7 +182,7 @@ module Miasma
|
|
182
182
|
count = 1
|
183
183
|
parts = []
|
184
184
|
file.body.rewind
|
185
|
-
while(content = file.body.read(
|
185
|
+
while(content = file.body.read(Storage::READ_BODY_CHUNK_SIZE))
|
186
186
|
parts << [
|
187
187
|
count,
|
188
188
|
request(
|
@@ -260,7 +260,7 @@ module Miasma
|
|
260
260
|
:method => :delete,
|
261
261
|
:path => file.name,
|
262
262
|
:endpoint => bucket_endpoint(file.bucket),
|
263
|
-
:
|
263
|
+
:expects => 204
|
264
264
|
)
|
265
265
|
true
|
266
266
|
else
|
@@ -293,6 +293,28 @@ module Miasma
|
|
293
293
|
file
|
294
294
|
end
|
295
295
|
|
296
|
+
# Create publicly accessible URL
|
297
|
+
#
|
298
|
+
# @param timeout_secs [Integer] seconds available
|
299
|
+
# @return [String] URL
|
300
|
+
def file_url(file, timeout_secs)
|
301
|
+
if(file.persisted?)
|
302
|
+
signer.generate_url(
|
303
|
+
:get, ::File.join(uri_escape(file.bucket.name), uri_escape(file.name)),
|
304
|
+
:headers => Smash.new(
|
305
|
+
'Host' => aws_host
|
306
|
+
),
|
307
|
+
:params => Smash.new(
|
308
|
+
'X-Amz-Date' => Contrib::AwsApiCore.time_iso8601,
|
309
|
+
'X-Amz-Expires' => timeout_secs
|
310
|
+
)
|
311
|
+
|
312
|
+
)
|
313
|
+
else
|
314
|
+
raise Error::ModelPersistError.new "#{file} has not been saved!"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
296
318
|
# Fetch the contents of the file
|
297
319
|
#
|
298
320
|
# @param file [Models::Storage::File]
|
data/lib/miasma/error.rb
CHANGED
@@ -5,6 +5,11 @@ module Miasma
|
|
5
5
|
# Abstract storage API
|
6
6
|
class Storage < Types::Api
|
7
7
|
|
8
|
+
# @return [Integer] max bytes allowed for storing body in string
|
9
|
+
MAX_BODY_SIZE_FOR_STRINGIFY = 102400
|
10
|
+
# @return [Integer] chunking size for reading IO
|
11
|
+
READ_BODY_CHUNK_SIZE = 102400
|
12
|
+
|
8
13
|
autoload :Buckets, 'miasma/models/storage/buckets'
|
9
14
|
autoload :Bucket, 'miasma/models/storage/bucket'
|
10
15
|
autoload :Files, 'miasma/models/storage/files'
|
@@ -45,7 +45,13 @@ module Miasma
|
|
45
45
|
# @note object returned will provide #readpartial
|
46
46
|
def body
|
47
47
|
unless(attributes[:body])
|
48
|
-
|
48
|
+
begin
|
49
|
+
_body = api.file_body(self)
|
50
|
+
_body.stream!
|
51
|
+
data[:body] = api.file_body(self)
|
52
|
+
rescue HTTP::StateError
|
53
|
+
data[:body] = StringIO.new(_body.to_s)
|
54
|
+
end
|
49
55
|
end
|
50
56
|
attributes[:body]
|
51
57
|
end
|
@@ -55,14 +61,37 @@ module Miasma
|
|
55
61
|
# @param io [IO, String]
|
56
62
|
# @return [IO]
|
57
63
|
def body=(io)
|
58
|
-
unless(io.
|
64
|
+
unless(io.respond_to?(:readpartial))
|
59
65
|
io = StringIO.new(io)
|
60
66
|
end
|
61
67
|
dirty[:body] = io
|
62
68
|
end
|
63
69
|
|
70
|
+
# Create accessible URL
|
71
|
+
#
|
72
|
+
# @param timeout_in_seconds [Integer] optional if private (default: 60)
|
73
|
+
# @return [String] URL
|
74
|
+
def url(timeout_in_seconds=60)
|
75
|
+
perform_file_url(timeout_in_seconds)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Destroy file
|
79
|
+
#
|
80
|
+
# @return [self]
|
81
|
+
def destroy
|
82
|
+
perform_destroy
|
83
|
+
data.clear
|
84
|
+
dirty.clear
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
64
88
|
protected
|
65
89
|
|
90
|
+
# Proxy URL action up to the API
|
91
|
+
def perform_file_url(secs)
|
92
|
+
api.file_url(self, secs)
|
93
|
+
end
|
94
|
+
|
66
95
|
# Proxy reload action up to the API
|
67
96
|
def perform_reload
|
68
97
|
api.file_reload(self)
|
data/lib/miasma/types/api.rb
CHANGED
@@ -118,13 +118,13 @@ module Miasma
|
|
118
118
|
# @return [Smash]
|
119
119
|
def format_response(result)
|
120
120
|
extracted_headers = Smash[result.headers.map{|k,v| [Utils.snake(k), v]}]
|
121
|
-
if(extracted_headers[:content_type].to_s.
|
121
|
+
if(extracted_headers[:content_type].to_s.include?('json'))
|
122
122
|
begin
|
123
123
|
extracted_body = MultiJson.load(result.body.to_s).to_smash
|
124
124
|
rescue MultiJson::ParseError
|
125
125
|
extracted_body = result.body.to_s
|
126
126
|
end
|
127
|
-
elsif(extracted_headers[:content_type].to_s.
|
127
|
+
elsif(extracted_headers[:content_type].to_s.include?('xml'))
|
128
128
|
begin
|
129
129
|
extracted_body = MultiXml.parse(result.body.to_s).to_smash
|
130
130
|
rescue MultiXml::ParseError
|
data/lib/miasma/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: miasma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Roberts
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hashie
|