s3-restful 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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/s3-restful.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__) + '/S3-restful/utils')
9
+ require File.expand_path(File.dirname(__FILE__) + '/S3-restful/log')
10
+ require File.expand_path(File.dirname(__FILE__) + '/S3-restful/aws')
11
+ require File.expand_path(File.dirname(__FILE__) + '/S3-restful/s3')
12
+ require File.expand_path(File.dirname(__FILE__) + '/S3-restful/s3/request')
13
+ require File.expand_path(File.dirname(__FILE__) + '/S3-restful/s3/item')
14
+
15
+ module S3Restful
16
+ MAJOR = 0
17
+ MINOR = 2
18
+ PATCH = 5
19
+
20
+ VERSION = [MAJOR, MINOR, PATCH].compact.join('.')
21
+ class Error < RuntimeError; end
22
+ end
23
+ end
@@ -0,0 +1,70 @@
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 = "s3-restful"
8
+ s.version = "0.2.6"
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
+ "s3-restful.gemspec",
28
+ "lib/s3-restful.rb",
29
+ "lib/s3-restful/aws.rb",
30
+ "lib/s3-restful/log.rb",
31
+ "lib/s3-restful/s3.rb",
32
+ "lib/s3-restful/s3/item.rb",
33
+ "lib/s3-restful/s3/request.rb",
34
+ "lib/s3-restful/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.rubygems_version = "1.8.15"
45
+ s.summary = "An EventMachine based client for S3 compatible APIs"
46
+
47
+ if s.respond_to? :specification_version then
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<em-http-request>, ["~> 1.0.2"])
52
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
53
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
54
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
55
+ s.add_development_dependency(%q<mocha>, [">= 0"])
56
+ else
57
+ s.add_dependency(%q<em-http-request>, ["~> 1.0.2"])
58
+ s.add_dependency(%q<shoulda>, [">= 0"])
59
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
60
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
61
+ s.add_dependency(%q<mocha>, [">= 0"])
62
+ end
63
+ else
64
+ s.add_dependency(%q<em-http-request>, ["~> 1.0.2"])
65
+ s.add_dependency(%q<shoulda>, [">= 0"])
66
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
67
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
68
+ s.add_dependency(%q<mocha>, [">= 0"])
69
+ end
70
+ 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