s3restful 0.2.7

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.
@@ -0,0 +1,111 @@
1
+ module S3restful
2
+ module S3
3
+ class Request
4
+ include Utils
5
+
6
+ VALID_HTTP_METHODS = [:head, :get, :aget, :put, :delete]
7
+
8
+ attr_accessor :http_method, :url, :options, :response
9
+
10
+ def initialize(http_method, url, options = {})
11
+ @options = {
12
+ :timeout => 10,
13
+ :retry_count => 4,
14
+ :headers => {},
15
+ :on_error => nil,
16
+ :on_success => nil,
17
+ :data => nil,
18
+ :ssl => {
19
+ :cert_chain_file => nil,
20
+ :verify_peer => false
21
+ }
22
+ }.update(options)
23
+ assert_valid_keys(options, :timeout, :on_success, :on_error, :retry_count, :headers, :data, :ssl, :file)
24
+ @http_method = http_method
25
+ @url = url
26
+
27
+ validate
28
+ end
29
+
30
+ def execute
31
+ S3restful::Log.debug "Request: #{http_method.to_s.upcase} #{url}"
32
+ @response = http_class.new(url).send(http_method, :timeout => options[:timeout], :head => options[:headers], :body => options[:data], :ssl => options[:ssl], :file => options[:file])
33
+
34
+ @response.errback { error_callback }
35
+ @response.callback { success_callback }
36
+ @response
37
+ end
38
+
39
+ def http_class
40
+ EventMachine::HttpRequest
41
+ end
42
+
43
+ protected
44
+
45
+ def validate
46
+ raise ArgumentError, "#{http_method} is not a valid HTTP method that #{self.class.name} understands." unless VALID_HTTP_METHODS.include?(http_method)
47
+ end
48
+
49
+ def error_callback
50
+ S3restful::Log.error "Response error: #{http_method.to_s.upcase} #{url}: #{response.response_header.status rescue ''}"
51
+ if should_retry?
52
+ S3restful::Log.info "#{http_method.to_s.upcase} #{url}: retrying after error: status #{response.response_header.status rescue ''}"
53
+ handle_retry
54
+ elsif options[:on_error].respond_to?(:call)
55
+ call_user_error_handler
56
+ else
57
+ raise S3restful::Error.new("#{http_method.to_s.upcase} #{url}: Failed reponse! Status code was #{response.response_header.status rescue ''}")
58
+ end
59
+ end
60
+
61
+ def success_callback
62
+ S3restful::Log.debug "Response success: #{http_method.to_s.upcase} #{url}: #{response.response_header.status rescue ''}"
63
+ case response.response_header.status
64
+ when 0, 400, 401, 404, 403, 409, 411, 412, 416, 500, 503
65
+ if should_retry?
66
+ S3restful::Log.info "#{http_method.to_s.upcase} #{url}: retrying after: status #{response.response_header.status rescue ''}"
67
+ handle_retry
68
+ else
69
+ S3restful::Log.error "#{http_method.to_s.upcase} #{url}: Re-tried too often - giving up"
70
+ error_callback
71
+ end
72
+ when 300, 301, 303, 304, 307
73
+ S3restful::Log.info "#{http_method.to_s.upcase} #{url}: being redirected_to: #{response.response_header['LOCATION'] rescue ''}"
74
+ handle_redirect
75
+ else
76
+ call_user_success_handler
77
+ end
78
+ end
79
+
80
+ def call_user_success_handler
81
+ options[:on_success].call(response) if options[:on_success].respond_to?(:call)
82
+ end
83
+
84
+ def call_user_error_handler
85
+ options[:on_error].call(response) if options[:on_error].respond_to?(:call)
86
+ end
87
+
88
+ def should_retry?
89
+ options[:retry_count] > 0
90
+ end
91
+
92
+ def handle_retry
93
+ if should_retry?
94
+ new_request = self.class.new(http_method, url, options.update(:retry_count => options[:retry_count] - 1 ))
95
+ new_request.execute
96
+ else
97
+ S3restful::Log.error "#{http_method.to_s.upcase} #{url}: Re-tried too often - giving up"
98
+ end
99
+ end
100
+
101
+ def handle_redirect
102
+ new_location = response.response_header['LOCATION'] rescue ''
103
+ raise "Could not find the location to redirect to, empty location header?" if blank?(new_location)
104
+
105
+ new_request = self.class.new(http_method, new_location, options)
106
+ new_request.execute
107
+ end
108
+
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,16 @@
1
+ module S3restful
2
+ module S3
3
+
4
+ def self.ssl_options
5
+ @_ssl_options ||= {
6
+ :cert_chain_file => nil,
7
+ :verify_peer => false
8
+ }
9
+ end
10
+
11
+ def self.ssl_options=(val)
12
+ @_ssl_options = val
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ module S3restful
2
+ module Utils
3
+ protected
4
+
5
+ def symbolize_keys(hash)
6
+ hash.inject({}) do |h, kv|
7
+ h[kv[0].to_sym] = kv[1]
8
+ h
9
+ end
10
+ end
11
+
12
+ def assert_valid_keys(hash, *valid_keys)
13
+ unknown_keys = hash.keys - [valid_keys].flatten
14
+ raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
15
+ end
16
+
17
+ def present?(obj)
18
+ !blank?(obj)
19
+ end
20
+
21
+ def blank?(obj)
22
+ obj.respond_to?(:empty?) ? obj.empty? : !obj
23
+ end
24
+
25
+ end
26
+ end
data/lib/s3restful.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'em-http'
3
+ require 'openssl'
4
+ require 'logger'
5
+
6
+ unless defined?(S3restful)
7
+ $:<<(File.expand_path(File.dirname(__FILE__) + "/lib"))
8
+ require File.expand_path(File.dirname(__FILE__) + '/s3restful/utils')
9
+ require File.expand_path(File.dirname(__FILE__) + '/s3restful/log')
10
+ require File.expand_path(File.dirname(__FILE__) + '/s3restful/aws')
11
+ require File.expand_path(File.dirname(__FILE__) + '/s3restful/s3')
12
+ require File.expand_path(File.dirname(__FILE__) + '/s3restful/s3/request')
13
+ require File.expand_path(File.dirname(__FILE__) + '/s3restful/s3/item')
14
+
15
+ module S3restful
16
+ MAJOR = 0
17
+ MINOR = 2
18
+ PATCH = 7
19
+
20
+ VERSION = [MAJOR, MINOR, PATCH].compact.join('.')
21
+ class Error < RuntimeError; end
22
+ end
23
+ end
data/s3restful.gemspec ADDED
@@ -0,0 +1,69 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "s3restful"
8
+ s.version = "0.2.7"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["João Pereira"]
12
+ s.date = "2012-06-08"
13
+ s.description = "An EventMachine based client for S3 compatible APIs"
14
+ s.email = "joaodrp@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ "CHANGELOG.md",
21
+ "Gemfile",
22
+ "LICENSE.txt",
23
+ "README.md",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "benchmark/right_aws.rb",
27
+ "s3restful.gemspec",
28
+ "lib/s3restful.rb",
29
+ "lib/s3restful/aws.rb",
30
+ "lib/s3restful/log.rb",
31
+ "lib/s3restful/s3.rb",
32
+ "lib/s3restful/s3/item.rb",
33
+ "lib/s3restful/s3/request.rb",
34
+ "lib/s3restful/utils.rb",
35
+ "test/aws_test.rb",
36
+ "test/s3/item_test.rb",
37
+ "test/s3/request_test.rb",
38
+ "test/s3_test.rb",
39
+ "test/test_helper.rb"
40
+ ]
41
+ s.homepage = "http://github.com/joaodrp/s3-restful"
42
+ s.licenses = ["BSD"]
43
+ s.require_paths = ["lib"]
44
+ s.summary = "An EventMachine based client for S3 compatible APIs"
45
+
46
+ if s.respond_to? :specification_version then
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ s.add_runtime_dependency(%q<em-http-request>, ["~> 1.0.2"])
51
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
52
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
53
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
54
+ s.add_development_dependency(%q<mocha>, [">= 0"])
55
+ else
56
+ s.add_dependency(%q<em-http-request>, ["~> 1.0.2"])
57
+ s.add_dependency(%q<shoulda>, [">= 0"])
58
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
59
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
60
+ s.add_dependency(%q<mocha>, [">= 0"])
61
+ end
62
+ else
63
+ s.add_dependency(%q<em-http-request>, ["~> 1.0.2"])
64
+ s.add_dependency(%q<shoulda>, [">= 0"])
65
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
66
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
67
+ s.add_dependency(%q<mocha>, [">= 0"])
68
+ end
69
+ end
data/test/aws_test.rb ADDED
@@ -0,0 +1,41 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ class ItemTest < Test::Unit::TestCase
4
+ context "An S3restful::AWS instance" do
5
+
6
+ setup do
7
+ @aws = S3restful::AWS.new('the-aws-access-key', 'the-aws-secret-key')
8
+ end
9
+
10
+ context "when constructing" do
11
+ should "require Access Key and Secret Key" do
12
+ assert_raise(ArgumentError) do
13
+ S3restful::AWS.new(nil, nil)
14
+ end
15
+
16
+ assert_raise(ArgumentError) do
17
+ S3restful::AWS.new('', '')
18
+ end
19
+
20
+ assert_nothing_raised do
21
+ S3restful::AWS.new('abc', 'abc')
22
+ end
23
+ end
24
+ end
25
+
26
+ context "when signing parameters" do
27
+ should "return a header hash" do
28
+ assert_not_nil @aws.sign("GET", '/')['Authorization']
29
+ end
30
+
31
+ should "include the current date" do
32
+ assert_not_nil @aws.sign("GET", '/')['date']
33
+ end
34
+
35
+ should "keep given headers" do
36
+ assert_equal 'bar', @aws.sign("GET", '/', {'foo' => 'bar'})['foo']
37
+ end
38
+ end
39
+
40
+ end
41
+ end