simple_aws 0.0.1b → 0.0.1c

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.
data/README.md CHANGED
@@ -106,6 +106,7 @@ Implemented APIs
106
106
 
107
107
  These are the following Amazon APIs that SimpleAWS currently handles:
108
108
 
109
+ * S3
109
110
  * EC2
110
111
  * ELB
111
112
  * IAM
@@ -125,7 +126,6 @@ These are the following Amazon APIs that SimpleAWS currently handles:
125
126
  Yet to be Implemented
126
127
  ---------------------
127
128
 
128
- * S3
129
129
  * CloudFront
130
130
 
131
131
  Currently Out-Of-Scope
@@ -1,4 +1,5 @@
1
1
  require 'httparty'
2
+ require 'httmultiparty'
2
3
  require 'openssl'
3
4
 
4
5
  require 'aws/core/response'
@@ -6,7 +7,7 @@ require 'aws/core/response'
6
7
  module AWS
7
8
 
8
9
  class HTTP
9
- include HTTParty
10
+ include HTTMultiParty
10
11
  format :xml
11
12
  end
12
13
 
@@ -24,7 +25,8 @@ module AWS
24
25
  HTTP.send(request.method,
25
26
  request.uri,
26
27
  :query => request.params,
27
- :headers => request.headers
28
+ :headers => request.headers,
29
+ :body => request.body
28
30
  )
29
31
  )
30
32
  end
@@ -111,6 +111,13 @@ module AWS
111
111
  ##
112
112
  attr_reader :headers
113
113
 
114
+ ##
115
+ # Raw string data to be put in the body of the request.
116
+ # Body can also be an IO object (something that response to #read) and
117
+ # if so the request will stream the file to the server.
118
+ ##
119
+ attr_accessor :body
120
+
114
121
  ##
115
122
  # Set up a new Request for the given +host+ and +path+ using the given
116
123
  # http +method+ (:get, :post, :put, :delete).
@@ -146,8 +146,11 @@ module AWS
146
146
  end
147
147
 
148
148
  def value_or_proxy(value)
149
- if value.is_a?(Hash) || value.is_a?(Array)
149
+ case value
150
+ when Hash
150
151
  ResponseProxy.new value
152
+ when Array
153
+ value.map {|v| ResponseProxy.new v }
151
154
  else
152
155
  value
153
156
  end
@@ -159,27 +162,36 @@ module AWS
159
162
  ##
160
163
  attr_reader :body
161
164
 
165
+ ##
166
+ # HTTP Status code of the response
167
+ ##
168
+ attr_reader :code
169
+
170
+ ##
171
+ # Hash of headers found in the response
172
+ ##
173
+ attr_reader :headers
174
+
162
175
  def initialize(http_response)
163
176
  if !http_response.success?
164
- error = parse_error_from http_response.parsed_response
165
- raise UnsuccessfulResponse.new(
166
- http_response.code,
167
- error["Code"],
168
- error["Message"]
169
- )
177
+ parse_and_throw_error_from http_response
170
178
  end
171
179
 
180
+ @code = http_response.code
172
181
  @body = http_response.parsed_response
182
+ @headers = http_response.headers
173
183
 
174
- inner = @body[@body.keys.first]
175
- response_root =
176
- if result_key = inner.keys.find {|k| k =~ /Result$/}
177
- inner[result_key]
178
- else
179
- inner
180
- end
184
+ if @body
185
+ inner = @body[@body.keys.first]
186
+ response_root =
187
+ if result_key = inner.keys.find {|k| k =~ /Result$/}
188
+ inner[result_key]
189
+ else
190
+ inner
191
+ end
181
192
 
182
- @request_root = ResponseProxy.new response_root
193
+ @request_root = ResponseProxy.new response_root
194
+ end
183
195
  end
184
196
 
185
197
  ##
@@ -216,9 +228,29 @@ module AWS
216
228
 
217
229
  protected
218
230
 
231
+ def parse_and_throw_error_from(http_response)
232
+ if http_response.parsed_response
233
+ error = parse_error_from http_response.parsed_response
234
+ else
235
+ error = { "Message" => http_response.response }
236
+ end
237
+
238
+ raise UnsuccessfulResponse.new(
239
+ http_response.code,
240
+ error["Code"],
241
+ error["Message"]
242
+ )
243
+ end
244
+
219
245
  def parse_error_from(body)
220
246
  if body.has_key? "ErrorResponse"
221
247
  body["ErrorResponse"]["Error"]
248
+ elsif body.has_key? "Error"
249
+ if body["Error"]["StringToSign"]
250
+ body["Error"]["Message"] += " String to Sign: #{body["Error"]["StringToSign"].inspect}"
251
+ end
252
+
253
+ body["Error"]
222
254
  elsif body.has_key? "Response"
223
255
  body["Response"]["Errors"]["Error"]
224
256
  else
data/lib/aws/s3.rb ADDED
@@ -0,0 +1,127 @@
1
+ require 'aws/api'
2
+ require 'aws/signing/authorization_header'
3
+
4
+ module AWS
5
+
6
+ ##
7
+ # Amazon's Simple Storage Service
8
+ #
9
+ # http://docs.amazonwebservices.com/AmazonS3/latest/API/Welcome.html
10
+ #
11
+ # As S3 is much closer to a RESTful service than the other AWS APIs, all
12
+ # calls through this API are done through the four handled HTTP METHODS:
13
+ # GET, PUT, DELETE, POST and HEAD. When sending a request, follow exactly what
14
+ # is described in the AWS API docs in the link above.
15
+ #
16
+ # So "GET Service" is
17
+ #
18
+ # s3.get "/"
19
+ #
20
+ # When working with a specific bucket, pass in :bucket after the path:
21
+ #
22
+ # s3.get "/", :bucket => "bucket_name"
23
+ #
24
+ # s3.get "/?policy", :bucket => "bucket_name"
25
+ #
26
+ # For requests that need extra parameters, use the :params option:
27
+ #
28
+ # s3.get "/object/name", :bucket => "bucket_name", :params => {
29
+ # "response-content-disposition" => "attachment"
30
+ # }
31
+ #
32
+ # Also use params in the cases that AWS asks for form fields, such as
33
+ # "POST Object".
34
+ #
35
+ # A lot of S3 communication happens through request and response headers.
36
+ # To specify a certian set of headers on the request, use :headers:
37
+ #
38
+ # s3.get "/", :bucket => "bucket_name", :headers => {
39
+ # "x-amz-security-token" => "security string"
40
+ # }
41
+ #
42
+ # Many of the PUT requests require a body of some sort, sometimes XML,
43
+ # sometimes JSON, and other times the raw file data. Use :body for this
44
+ # information. :body is expected to be either a String containing the XML or
45
+ # JSON information, or an object that otherwise response to #read for file
46
+ # uploads. This API does not build XML or JSON for you right now.
47
+ #
48
+ # s3.put "/object/name.txt", :bucket => "bucket_name", :body => {:file => File.open()}
49
+ #
50
+ # As this is a common use case, if you don't have any more parameters to send
51
+ # with the file being uploaded, just use :file.
52
+ #
53
+ # s3.put "/object/name.txt", :bucket => "bucket_name", :file => File.open()
54
+ #
55
+ # This API does ensure that file data is uploaded as efficiently as possible,
56
+ # streaming file data from disc to AWS without blowing up memory. All files are
57
+ # uploading using multipart/form-data.
58
+ #
59
+ # NOTE: Like the other parts of SimpleAWS, this API does NOT try to make the
60
+ # AWS API better, but simply provides a cleaner, easy to use API for Ruby.
61
+ # As such, this API does not offer streaming downloads of file data from S3.
62
+ # That is up to you to implement at this time, by running a HEAD to get
63
+ # Content-Length then repeated GETs using the "Range:bytes" header to specify
64
+ # which parts to download next.
65
+ #
66
+ # Raw file data in a response will be available in the #body method on the Response
67
+ # returned by the method call.
68
+ ##
69
+ class S3 < API
70
+ endpoint "s3"
71
+ use_https true
72
+ version "2006-03-01"
73
+
74
+ [:get, :post, :put, :delete, :head].each do |method|
75
+ define_method(method) do |*args|
76
+ self.call method, *args
77
+ end
78
+ end
79
+
80
+ def call(method, path, options = {})
81
+ if options[:bucket]
82
+ path = path.gsub(/^\//, "/#{options[:bucket]}/")
83
+ end
84
+
85
+ request = AWS::Request.new method, self.uri, path
86
+
87
+ (options[:params] || {}).each do |k, v|
88
+ request.params[k] = v
89
+ end
90
+
91
+ (options[:headers] || {}).each do |k, v|
92
+ request.headers[k] = v
93
+ end
94
+
95
+ if options[:file]
96
+ options[:body] = {:file => options[:file]}
97
+ end
98
+
99
+ request.body = options[:body]
100
+
101
+ if request.body.is_a?(Hash) && request.body[:file]
102
+ request.headers["Content-Type"] =
103
+ "multipart/form-data; boundary=-----------RubyMultipartPost"
104
+ end
105
+
106
+ connection = AWS::Connection.new
107
+ connection.call finish_and_sign_request(request)
108
+ end
109
+
110
+ include Signing::AuthorizationHeader
111
+
112
+ ##
113
+ # S3 handles region endpoints a little differently
114
+ ##
115
+ def uri
116
+ return @uri if @uri
117
+
118
+ @uri = @use_https ? "https" : "http"
119
+ @uri += "://#{@endpoint}"
120
+ @uri += "-#{@region}" if @region
121
+ @uri += ".amazonaws.com"
122
+ @uri
123
+ end
124
+
125
+ end
126
+
127
+ end
@@ -0,0 +1,43 @@
1
+ require 'openssl'
2
+
3
+ module AWS
4
+ module Signing
5
+ ##
6
+ # Implementation of signing using the Authorization header, as used by S3 and CloudFront
7
+ ##
8
+ module AuthorizationHeader
9
+
10
+ ##
11
+ # Build and sign the final request, as per the rules here:
12
+ # http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html
13
+ ##
14
+ def finish_and_sign_request(request)
15
+ request.headers["Date"] = Time.now.utc.httpdate
16
+ request.headers["Authorization"] =
17
+ "AWS #{self.access_key}:#{Base64.encode64(build_signature_for(request)).chomp}"
18
+
19
+ request
20
+ end
21
+
22
+ def build_signature_for(request)
23
+ amazon_headers = request.headers.select {|k, v|
24
+ k =~ /^x-amz/i
25
+ }.map {|k, v|
26
+ "#{k.downcase}:#{v}".chomp
27
+ }
28
+
29
+ to_sign = [
30
+ request.method.to_s.upcase,
31
+ request.headers["Content-Md5"] || "",
32
+ request.headers["Content-Type"] || "",
33
+ request.headers["Date"],
34
+ amazon_headers,
35
+ request.path
36
+ ].flatten.join("\n")
37
+
38
+ OpenSSL::HMAC.digest("sha1", self.secret_key, to_sign)
39
+ end
40
+
41
+ end
42
+ end
43
+ end
data/samples/s3.rb ADDED
@@ -0,0 +1,64 @@
1
+ $: << File.expand_path("../../lib", __FILE__)
2
+
3
+ require 'aws/s3'
4
+
5
+ ##
6
+ # Expects your Amazon keys to be in the environment, something like
7
+ #
8
+ # export AWS_KEY="KEY"
9
+ # export AWS_SECRET="SECRET"
10
+ #
11
+ # Usage:
12
+ # ruby sample/s3.rb [bucket name] [file to use]
13
+ #
14
+ # This script will upload the file, show that the file is up, then remove the file
15
+ ##
16
+
17
+ def bad_usage
18
+ puts ""
19
+ puts "Usage:"
20
+ puts " ruby sample/s3.rb [bucket name] [file to use]"
21
+ exit 1
22
+ end
23
+
24
+ s3 = AWS::S3.new ENV["AWS_KEY"], ENV["AWS_SECRET"]
25
+
26
+ bucket_name = ARGV[0]
27
+ file_name = ARGV[1]
28
+
29
+ puts "All buckets in this account:", ""
30
+
31
+ s3.get("/").buckets.bucket.each do |bucket|
32
+ puts bucket.name
33
+ end
34
+
35
+ puts "", "First 10 files in #{bucket_name}:", ""
36
+
37
+ bad_usage unless bucket_name
38
+
39
+ s3.get("/", :bucket => bucket_name, :params => {"max-keys" => 10}).contents.each do |entry|
40
+ puts entry.key
41
+ end
42
+
43
+ puts "", "Uploading #{file_name} to #{bucket_name}:", ""
44
+
45
+ bad_usage unless file_name
46
+ uploaded_file_name = File.basename file_name
47
+
48
+ p s3.put("/#{uploaded_file_name}", :bucket => bucket_name, :file => File.open(file_name))
49
+
50
+ puts "", "Checking that the file now exists...", ""
51
+
52
+ p s3.head("/#{uploaded_file_name}", :bucket => bucket_name)
53
+
54
+ puts "", "Deleting the file from S3", ""
55
+
56
+ p s3.delete("/#{uploaded_file_name}", :bucket => bucket_name)
57
+
58
+ puts "", "Checking that file is no longer in S3...", ""
59
+
60
+ begin
61
+ p s3.head("/#{uploaded_file_name}", :bucket => bucket_name)
62
+ rescue => ex
63
+ puts "Not found: #{ex.message}"
64
+ end
data/simple_aws.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "simple_aws"
3
- s.version = "0.0.1b"
3
+ s.version = "0.0.1c"
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.authors = ["Jason Roelofs"]
6
6
  s.email = ["jameskilton@gmail.com"]
@@ -12,6 +12,7 @@ Gem::Specification.new do |s|
12
12
 
13
13
  s.add_dependency "ox"
14
14
  s.add_dependency "httparty"
15
+ s.add_dependency "httmultiparty"
15
16
 
16
17
  s.add_dependency "jruby-openssl" if RUBY_PLATFORM == 'java'
17
18
 
@@ -56,5 +56,17 @@ describe AWS::Connection do
56
56
  @connection.call request
57
57
  end
58
58
 
59
+ it "passes through any body on the Request" do
60
+ request = AWS::Request.new(:get, "host.com", "/")
61
+ request.body = "This is some body text"
62
+
63
+ AWS::HTTP.expects(:get).with {|uri, options|
64
+ options[:query].wont_be_nil
65
+ options[:body].must_equal "This is some body text"
66
+ }.returns(@http_response)
67
+
68
+ @connection.call request
69
+ end
70
+
59
71
  end
60
72
  end
@@ -19,13 +19,6 @@ describe AWS::Request do
19
19
  @request.method.must_equal :get
20
20
  end
21
21
 
22
- it "can be given parameters to pass in" do
23
- @request.params["Param1"] = "Value1"
24
- @request.params["Param2"] = "Value2"
25
-
26
- @request.params.must_equal "Param1" => "Value1", "Param2" => "Value2"
27
- end
28
-
29
22
  it "ensures path is never an empty string" do
30
23
  @request.path = ""
31
24
  @request.path.must_equal "/"
@@ -38,6 +31,22 @@ describe AWS::Request do
38
31
  end
39
32
  end
40
33
 
34
+ describe "parameters" do
35
+ it "can be given parameters to pass in" do
36
+ @request.params["Param1"] = "Value1"
37
+ @request.params["Param2"] = "Value2"
38
+
39
+ @request.params.must_equal "Param1" => "Value1", "Param2" => "Value2"
40
+ end
41
+ end
42
+
43
+ describe "body" do
44
+ it "can be given raw body text" do
45
+ @request.body = "BODY!"
46
+ @request.body.must_equal "BODY!"
47
+ end
48
+ end
49
+
41
50
  describe "hashes" do
42
51
  it "converts hash params to AWS param names" do
43
52
  @request.params["Filter"] = [
@@ -8,6 +8,7 @@ describe AWS::Response do
8
8
  before do
9
9
  @error_response = {}
10
10
  @http_response = stub
11
+ @http_response.stubs(:headers).returns(nil)
11
12
  @http_response.stubs(:success?).returns(false)
12
13
  @http_response.stubs(:code).returns(401)
13
14
  end
@@ -55,6 +56,25 @@ describe AWS::Response do
55
56
  error.message.must_equal "AuthFailure (401): Message about failing to authenticate"
56
57
  end
57
58
 
59
+ it "handles S3 errors" do
60
+ @error_response = { "Error" => {
61
+ "Code" => "AuthFailure", "Message" => "OH snap!",
62
+ "StringToSign" => "SOME STRING"
63
+ } }
64
+ @http_response.stubs(:parsed_response).returns(@error_response)
65
+
66
+ error =
67
+ lambda {
68
+ AWS::Response.new @http_response
69
+ }.must_raise AWS::UnsuccessfulResponse
70
+
71
+ error.code.must_equal 401
72
+ error.error_type.must_equal "AuthFailure"
73
+ error.error_message.must_equal "OH snap! String to Sign: \"SOME STRING\""
74
+
75
+ error.message.must_equal "AuthFailure (401): OH snap! String to Sign: \"SOME STRING\""
76
+ end
77
+
58
78
  it "raises if it can't parse the error message" do
59
79
  @error_response = { "Erroring" => "This is an error message" }
60
80
  @http_response.stubs(:parsed_response).returns(@error_response)
@@ -66,6 +86,19 @@ describe AWS::Response do
66
86
 
67
87
  error.message.must_match /Unable to parse error code from/
68
88
  end
89
+
90
+ it "handles errors that have no body to parse" do
91
+ @http_response.stubs(:code).returns(404)
92
+ @http_response.stubs(:parsed_response).returns(nil)
93
+ @http_response.stubs(:response).returns("This is a response ok?")
94
+
95
+ error = lambda {
96
+ response = AWS::Response.new @http_response
97
+ }.must_raise AWS::UnsuccessfulResponse
98
+
99
+ error.code.must_equal 404
100
+ error.message.must_equal " (404): This is a response ok?"
101
+ end
69
102
  end
70
103
 
71
104
  describe "successful response parsing and mapping" do
@@ -79,6 +112,8 @@ describe AWS::Response do
79
112
  }
80
113
 
81
114
  @http_response = stub
115
+ @http_response.stubs(:headers).returns(nil)
116
+ @http_response.stubs(:code).returns(200)
82
117
  @http_response.stubs(:success?).returns(true)
83
118
  @http_response.stubs(:parsed_response).returns(@response_hash)
84
119
 
@@ -104,6 +139,23 @@ describe AWS::Response do
104
139
  @response["unknownKey"].must_be_nil
105
140
  end
106
141
 
142
+ it "handles responses with no body" do
143
+ @http_response.stubs(:parsed_response).returns(nil)
144
+ response = AWS::Response.new @http_response
145
+ response.body.must_be_nil
146
+ end
147
+
148
+ it "knows the status code of the response" do
149
+ @response.code.must_equal 200
150
+ end
151
+
152
+ it "pulls out any response headers" do
153
+ @http_response.stubs(:headers).returns({"Header1" => "Value2"})
154
+ response = AWS::Response.new @http_response
155
+
156
+ response.headers.must_equal "Header1" => "Value2"
157
+ end
158
+
107
159
  end
108
160
 
109
161
  describe "deeply nested response/results objects" do
@@ -119,6 +171,8 @@ describe AWS::Response do
119
171
  }
120
172
 
121
173
  @http_response = stub
174
+ @http_response.stubs(:headers).returns(nil)
175
+ @http_response.stubs(:code).returns(202)
122
176
  @http_response.stubs(:success?).returns(true)
123
177
  @http_response.stubs(:parsed_response).returns(@response_hash)
124
178
 
@@ -167,11 +221,20 @@ describe AWS::Response do
167
221
  "withMemberSet" => {
168
222
  "member" => {"keyId" => "4567"}
169
223
  },
170
- "UpperCamelKey" => "purple dog"
224
+ "UpperCamelKey" => "purple dog",
225
+ "Buckets" => {
226
+ "Bucket" => [
227
+ {"Name" => "bucket1"},
228
+ {"Name" => "bucket2"},
229
+ {"Name" => "bucket3"}
230
+ ]
231
+ }
171
232
  }
172
233
  }
173
234
 
174
235
  @http_response = stub
236
+ @http_response.stubs(:code).returns(202)
237
+ @http_response.stubs(:headers).returns(nil)
175
238
  @http_response.stubs(:success?).returns(true)
176
239
  @http_response.stubs(:parsed_response).returns(@response_hash)
177
240
 
@@ -226,6 +289,12 @@ describe AWS::Response do
226
289
  @response.upper_camel_key.must_equal "purple dog"
227
290
  end
228
291
 
292
+ it "works with straight array responses" do
293
+ @response.buckets.bucket[0].name.must_equal "bucket1"
294
+ @response.buckets.bucket[1].name.must_equal "bucket2"
295
+ @response.buckets.bucket[2].name.must_equal "bucket3"
296
+ end
297
+
229
298
  end
230
299
 
231
300
  describe "hash keys" do
@@ -259,6 +328,12 @@ describe AWS::Response do
259
328
  it "also squashes the 'member' tag" do
260
329
  @response["withMemberSet"][0]["keyId"].must_equal "4567"
261
330
  end
331
+
332
+ it "works with straight array responses" do
333
+ @response["Buckets"]["Bucket"][0]["Name"].must_equal "bucket1"
334
+ @response["Buckets"]["Bucket"][1]["Name"].must_equal "bucket2"
335
+ @response["Buckets"]["Bucket"][2]["Name"].must_equal "bucket3"
336
+ end
262
337
  end
263
338
 
264
339
  end
@@ -266,6 +341,8 @@ describe AWS::Response do
266
341
  describe "#request_id" do
267
342
  before do
268
343
  @http_response = stub
344
+ @http_response.stubs(:headers).returns(nil)
345
+ @http_response.stubs(:code).returns(200)
269
346
  @http_response.stubs(:success?).returns(true)
270
347
  end
271
348
 
@@ -0,0 +1,108 @@
1
+ require 'test_helper'
2
+ require 'aws/s3'
3
+
4
+ describe AWS::S3 do
5
+
6
+ before do
7
+ @api = AWS::S3.new "key", "secret"
8
+ end
9
+
10
+ it "points to the endpoint" do
11
+ @api.uri.must_equal "https://s3.amazonaws.com"
12
+ end
13
+
14
+ it "properly builds region endpoints" do
15
+ api = AWS::S3.new "key", "secret", "us-west-1"
16
+ api.uri.must_equal "https://s3-us-west-1.amazonaws.com"
17
+ end
18
+
19
+ it "works with the current version" do
20
+ @api.version.must_equal "2006-03-01"
21
+ end
22
+
23
+ describe "API calls" do
24
+
25
+ [:get, :post, :put, :delete, :head].each do |method|
26
+ it "supports the #{method} HTTP method" do
27
+ AWS::Connection.any_instance.expects(:call).with do |request|
28
+ request.method.must_equal method
29
+ request.host.must_equal "https://s3.amazonaws.com"
30
+ request.path.must_equal "/"
31
+ true
32
+ end
33
+
34
+ @api.send method, "/"
35
+ end
36
+ end
37
+
38
+ it "rebuilds the host if :bucket given" do
39
+ AWS::Connection.any_instance.expects(:call).with do |request|
40
+ request.path.must_equal "/bucket-name/"
41
+ request.host.must_equal "https://s3.amazonaws.com"
42
+ true
43
+ end
44
+
45
+ @api.get "/", :bucket => "bucket-name"
46
+ end
47
+
48
+ it "takes parameters" do
49
+ AWS::Connection.any_instance.expects(:call).with do |request|
50
+ request.params["Parameter1"].must_equal "Value2"
51
+ true
52
+ end
53
+
54
+ @api.get "/", :params => { "Parameter1" => "Value2" }
55
+ end
56
+
57
+ it "takes extra headers" do
58
+ AWS::Connection.any_instance.expects(:call).with do |request|
59
+ request.headers["Header14"].must_equal "Out to Lunch"
60
+ true
61
+ end
62
+
63
+ @api.get "/", :headers => { "Header14" => "Out to Lunch" }
64
+ end
65
+
66
+ it "takes a raw body" do
67
+ AWS::Connection.any_instance.expects(:call).with do |request|
68
+ request.body.must_equal "This is a body of text"
69
+ true
70
+ end
71
+
72
+ @api.get "/", :body => "This is a body of text"
73
+ end
74
+
75
+ it "adds the form-data header if the body has a file in it" do
76
+ AWS::Connection.any_instance.expects(:call).with do |request|
77
+ request.body.must_equal :file => "This is a body of text"
78
+ request.headers["Content-Type"].must_equal(
79
+ "multipart/form-data; boundary=-----------RubyMultipartPost"
80
+ )
81
+ true
82
+ end
83
+
84
+ @api.get "/", :body => {:file => "This is a body of text"}
85
+ end
86
+
87
+ it "allows use of :file if :body only contains a file" do
88
+ AWS::Connection.any_instance.expects(:call).with do |request|
89
+ request.body.must_equal :file => "This is a body of text"
90
+ request.headers["Content-Type"].must_equal(
91
+ "multipart/form-data; boundary=-----------RubyMultipartPost"
92
+ )
93
+ true
94
+ end
95
+
96
+ @api.get "/", :file => "This is a body of text"
97
+ end
98
+
99
+ it "signs the request using the Authorization header" do
100
+ AWS::Connection.any_instance.expects(:call).with do |request|
101
+ request.headers["Authorization"].wont_be_nil
102
+ true
103
+ end
104
+
105
+ @api.get "/"
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+ require 'aws/api'
3
+ require 'aws/call_types/action_param'
4
+ require 'aws/signing/authorization_header'
5
+
6
+ describe AWS::Signing::AuthorizationHeader do
7
+
8
+ class SigningAuthHeaderTestAPI < AWS::API
9
+ endpoint "aptest"
10
+ version "2011-01-01"
11
+ use_https true
12
+
13
+ include AWS::CallTypes::ActionParam
14
+ include AWS::Signing::AuthorizationHeader
15
+ end
16
+
17
+ it "signs the given request according to Version 3 rules" do
18
+ AWS::Connection.any_instance.expects(:call).with do |request|
19
+ header = request.headers["Authorization"]
20
+ parts = header.split(":")
21
+
22
+ parts[0].must_equal "AWS key"
23
+ parts[1].wont_be_nil
24
+
25
+ Time.parse(request.headers["Date"]).wont_be_nil
26
+ true
27
+ end.returns
28
+
29
+ obj = SigningAuthHeaderTestAPI.new "key", "secret"
30
+ obj.describe_instances
31
+ end
32
+
33
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_aws
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1b
4
+ version: 0.0.1c
5
5
  prerelease: 5
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-03 00:00:00.000000000 Z
12
+ date: 2012-01-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ox
16
- requirement: &70137915318080 !ruby/object:Gem::Requirement
16
+ requirement: &70146086124160 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70137915318080
24
+ version_requirements: *70146086124160
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: httparty
27
- requirement: &70137915317640 !ruby/object:Gem::Requirement
27
+ requirement: &70146086123740 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,18 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70137915317640
35
+ version_requirements: *70146086123740
36
+ - !ruby/object:Gem::Dependency
37
+ name: httmultiparty
38
+ requirement: &70146086123280 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70146086123280
36
47
  description: The simplest and easiest to use and maintain AWS communication library
37
48
  email:
38
49
  - jameskilton@gmail.com
@@ -63,7 +74,9 @@ files:
63
74
  - lib/aws/map_reduce.rb
64
75
  - lib/aws/mechanical_turk.rb
65
76
  - lib/aws/rds.rb
77
+ - lib/aws/s3.rb
66
78
  - lib/aws/ses.rb
79
+ - lib/aws/signing/authorization_header.rb
67
80
  - lib/aws/signing/version2.rb
68
81
  - lib/aws/signing/version3.rb
69
82
  - lib/aws/sns.rb
@@ -71,6 +84,7 @@ files:
71
84
  - samples/ec2.rb
72
85
  - samples/elb.rb
73
86
  - samples/iam.rb
87
+ - samples/s3.rb
74
88
  - samples/sqs.rb
75
89
  - samples/turk.rb
76
90
  - simple_aws.gemspec
@@ -91,7 +105,9 @@ files:
91
105
  - test/aws/map_reduce_test.rb
92
106
  - test/aws/mechanical_turk_test.rb
93
107
  - test/aws/rds_test.rb
108
+ - test/aws/s3_test.rb
94
109
  - test/aws/ses.rb
110
+ - test/aws/signing/authorization_header_test.rb
95
111
  - test/aws/signing/version2_test.rb
96
112
  - test/aws/signing/version3.rb
97
113
  - test/aws/sns_test.rb
@@ -139,7 +155,9 @@ test_files:
139
155
  - test/aws/map_reduce_test.rb
140
156
  - test/aws/mechanical_turk_test.rb
141
157
  - test/aws/rds_test.rb
158
+ - test/aws/s3_test.rb
142
159
  - test/aws/ses.rb
160
+ - test/aws/signing/authorization_header_test.rb
143
161
  - test/aws/signing/version2_test.rb
144
162
  - test/aws/signing/version3.rb
145
163
  - test/aws/sns_test.rb