fog 0.0.12 → 0.0.13

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.12
1
+ 0.0.13
data/bin/fog CHANGED
@@ -3,7 +3,9 @@ require File.join(File.dirname(__FILE__), '..', 'lib', 'fog')
3
3
  require 'irb'
4
4
  require 'yaml'
5
5
 
6
- if File.exists?(File.expand_path('~/.fog'))
6
+ if ARGV[0] && File.exists?(File.expand_path(ARGV[0]))
7
+ @credentials = YAML.load(File.open(File.expand_path(ARGV[0])).read)
8
+ elsif File.exists?(File.expand_path('~/.fog'))
7
9
  @credentials = YAML.load(File.open(File.expand_path('~/.fog')).read)
8
10
  end
9
11
 
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{fog}
8
- s.version = "0.0.12"
8
+ s.version = "0.0.13"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Wesley Beary"]
12
- s.date = %q{2009-10-01}
12
+ s.date = %q{2009-10-05}
13
13
  s.default_executable = %q{fog}
14
14
  s.description = %q{brings clouds to you}
15
15
  s.email = %q{me@geemus.com}
@@ -42,6 +42,10 @@ module Fog
42
42
  nil
43
43
  end
44
44
 
45
+ def get_url(key, expires)
46
+ connection.get_object_url(bucket.name, key, expires)
47
+ end
48
+
45
49
  def head(key, options = {})
46
50
  data = connection.head_object(bucket.name, key, options)
47
51
  object_data = {
@@ -33,7 +33,7 @@ unless Fog.mocking?
33
33
  :host => "#{target_bucket_name}.#{@host}",
34
34
  :method => 'PUT',
35
35
  :parser => Fog::Parsers::AWS::S3::CopyObject.new,
36
- :path => target_object_name
36
+ :path => CGI.escape(target_object_name)
37
37
  })
38
38
  end
39
39
 
@@ -19,7 +19,7 @@ unless Fog.mocking?
19
19
  :headers => {},
20
20
  :host => "#{bucket_name}.#{@host}",
21
21
  :method => 'DELETE',
22
- :path => object_name
22
+ :path => CGI.escape(object_name)
23
23
  })
24
24
  end
25
25
 
@@ -39,11 +39,26 @@ unless Fog.mocking?
39
39
  :headers => headers,
40
40
  :host => "#{bucket_name}.#{@host}",
41
41
  :method => 'GET',
42
- :path => object_name,
42
+ :path => CGI.escape(object_name),
43
43
  :block => block
44
44
  })
45
45
  end
46
46
 
47
+ def get_object_url(bucket_name, object_name, expires)
48
+ unless bucket_name
49
+ raise ArgumentError.new('bucket_name is required')
50
+ end
51
+ unless object_name
52
+ raise ArgumentError.new('object_name is required')
53
+ end
54
+ url({
55
+ :headers => {},
56
+ :host => "#{bucket_name}.#{@host}",
57
+ :method => 'GET',
58
+ :path => object_name
59
+ }, expires)
60
+ end
61
+
47
62
  end
48
63
  end
49
64
  end
@@ -34,7 +34,7 @@ unless Fog.mocking?
34
34
  :headers => headers,
35
35
  :host => "#{bucket_name}.#{@host}",
36
36
  :method => 'HEAD',
37
- :path => object_name
37
+ :path => CGI.escape(object_name)
38
38
  })
39
39
  end
40
40
 
@@ -33,7 +33,7 @@ unless Fog.mocking?
33
33
  :headers => headers,
34
34
  :host => "#{bucket_name}.#{@host}",
35
35
  :method => 'PUT',
36
- :path => object_name
36
+ :path => CGI.escape(object_name)
37
37
  })
38
38
  end
39
39
 
@@ -55,7 +55,7 @@ module Fog
55
55
  # :aws_secret_access_key in order to create a connection
56
56
  #
57
57
  # ==== Examples
58
- # sdb = S3.new(
58
+ # s3 = S3.new(
59
59
  # :aws_access_key_id => your_aws_access_key_id,
60
60
  # :aws_secret_access_key => your_aws_secret_access_key
61
61
  # )
@@ -100,7 +100,33 @@ module Fog
100
100
 
101
101
  def request(params)
102
102
  params[:headers]['Date'] = Time.now.utc.strftime("%a, %d %b %Y %H:%M:%S +0000")
103
+ params[:headers]['Authorization'] = "AWS #{@aws_access_key_id}:#{signature(params)}"
103
104
 
105
+ response = @connection.request({
106
+ :block => params[:block],
107
+ :body => params[:body],
108
+ :expects => params[:expects],
109
+ :headers => params[:headers],
110
+ :host => params[:host],
111
+ :method => params[:method],
112
+ :parser => params[:parser],
113
+ :path => params[:path],
114
+ :query => params[:query]
115
+ })
116
+
117
+ response
118
+ end
119
+
120
+ def url(params, expires)
121
+ params[:headers]['Date'] = expires.to_i
122
+ query = [params[:query]].compact
123
+ query << "AWSAccessKeyId=#{@aws_access_key_id}"
124
+ query << "Signature=#{CGI.escape(signature(params))}"
125
+ query << "Expires=#{params[:headers]['Date']}"
126
+ "http://#{params[:host]}/#{params[:path]}?#{query.join('&')}"
127
+ end
128
+
129
+ def signature(params)
104
130
  string_to_sign =
105
131
  <<-DATA
106
132
  #{params[:method]}
@@ -121,9 +147,20 @@ DATA
121
147
  end
122
148
  string_to_sign << "#{canonical_amz_headers}"
123
149
 
124
- canonical_resource = "/"
125
150
  subdomain = params[:host].split(".#{@host}").first
126
- unless subdomain == @host
151
+ unless subdomain =~ /^(?:[a-z]|\d(?!\d{0,2}(?:\.\d{1,3}){3}$))(?:[a-z0-9]|\.(?![\.\-])|\-(?![\.])){1,61}[a-z0-9]$/
152
+ puts("[WARN] fog: the specified s3 bucket name(#{subdomain}) is not a valid dns name. See: http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?Introduction.html")
153
+ params[:host] = params[:host].split("#{subdomain}.")[-1]
154
+ if params[:path]
155
+ params[:path] = "#{subdomain}/#{params[:path]}"
156
+ else
157
+ params[:path] = "#{subdomain}"
158
+ end
159
+ subdomain = nil
160
+ end
161
+
162
+ canonical_resource = "/"
163
+ unless subdomain.nil? || subdomain == @host
127
164
  canonical_resource << "#{CGI.escape(subdomain).downcase}/"
128
165
  end
129
166
  canonical_resource << "#{params[:path]}"
@@ -134,21 +171,6 @@ DATA
134
171
 
135
172
  hmac = @hmac.update(string_to_sign)
136
173
  signature = Base64.encode64(hmac.digest).chomp!
137
- params[:headers]['Authorization'] = "AWS #{@aws_access_key_id}:#{signature}"
138
-
139
- response = @connection.request({
140
- :block => params[:block],
141
- :body => params[:body],
142
- :expects => params[:expects],
143
- :headers => params[:headers],
144
- :host => params[:host],
145
- :method => params[:method],
146
- :parser => params[:parser],
147
- :path => params[:path],
148
- :query => params[:query]
149
- })
150
-
151
- response
152
174
  end
153
175
 
154
176
  end
@@ -17,13 +17,20 @@ unless Fog.mocking?
17
17
 
18
18
  def initialize(url)
19
19
  @uri = URI.parse(url)
20
- @connection = TCPSocket.open(@uri.host, @uri.port)
21
- if @uri.scheme == 'https'
22
- @ssl_context = OpenSSL::SSL::SSLContext.new
23
- @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
24
- @connection = OpenSSL::SSL::SSLSocket.new(@connection, @ssl_context)
25
- @connection.sync_close = true
26
- @connection.connect
20
+ end
21
+
22
+ def connection
23
+ if @connection && !@connection.closed?
24
+ @connection
25
+ else
26
+ @connection = TCPSocket.open(@uri.host, @uri.port)
27
+ if @uri.scheme == 'https'
28
+ @ssl_context = OpenSSL::SSL::SSLContext.new
29
+ @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
30
+ @connection = OpenSSL::SSL::SSLSocket.new(@connection, @ssl_context)
31
+ @connection.sync_close = true
32
+ @connection.connect
33
+ end
27
34
  end
28
35
  end
29
36
 
@@ -45,7 +52,7 @@ unless Fog.mocking?
45
52
  request << "#{key}: #{value}\r\n"
46
53
  end
47
54
  request << "\r\n"
48
- @connection.write(request)
55
+ connection.write(request)
49
56
 
50
57
  if params[:body]
51
58
  if params[:body].is_a?(String)
@@ -54,18 +61,18 @@ unless Fog.mocking?
54
61
  body = params[:body]
55
62
  end
56
63
  while chunk = body.read(CHUNK_SIZE)
57
- @connection.write(chunk)
64
+ connection.write(chunk)
58
65
  end
59
66
  end
60
67
 
61
68
  response = Fog::Response.new
62
69
  response.request = params
63
- response.status = @connection.readline[9..11].to_i
70
+ response.status = connection.readline[9..11].to_i
64
71
  if params[:expects] && params[:expects] != response.status
65
72
  error = true
66
73
  end
67
74
  while true
68
- data = @connection.readline.chomp!
75
+ data = connection.readline.chomp!
69
76
  if data == ""
70
77
  break
71
78
  end
@@ -73,35 +80,35 @@ unless Fog.mocking?
73
80
  response.headers[capitalize(header[0])] = header[1]
74
81
  end
75
82
 
76
- if error || params[:parser]
77
- if error
78
- parser = Fog::Errors::Parser.new
79
- elsif params[:parser]
80
- parser = params[:parser]
83
+ unless params[:method] == 'HEAD'
84
+ if error || params[:parser]
85
+ if error
86
+ parser = Fog::Errors::Parser.new
87
+ elsif params[:parser]
88
+ parser = params[:parser]
89
+ end
90
+ body = Nokogiri::XML::SAX::PushParser.new(parser)
91
+ elsif params[:block]
92
+ body = nil
93
+ else
94
+ body = ''
81
95
  end
82
- body = Nokogiri::XML::SAX::PushParser.new(parser)
83
- elsif params[:block]
84
- body = nil
85
- else
86
- body = ''
87
- end
88
96
 
89
- unless params[:method] == 'HEAD'
90
97
  if response.headers['Content-Length']
91
98
  if error || !params[:block]
92
- body << @connection.read(response.headers['Content-Length'].to_i)
99
+ body << connection.read(response.headers['Content-Length'].to_i)
93
100
  else
94
101
  remaining = response.headers['Content-Length'].to_i
95
102
  while remaining > 0
96
- params[:block].call(@connection.read([CHUNK_SIZE, remaining].min))
103
+ params[:block].call(connection.read([CHUNK_SIZE, remaining].min))
97
104
  remaining -= CHUNK_SIZE;
98
105
  end
99
106
  end
100
107
  elsif response.headers['Transfer-Encoding'] == 'chunked'
101
108
  while true
102
109
  # 2 == "/r/n".length
103
- chunk_size = @connection.readline.chomp!.to_i(16) + 2
104
- chunk = @connection.read(chunk_size)[0...-2]
110
+ chunk_size = connection.readline.chomp!.to_i(16) + 2
111
+ chunk = connection.read(chunk_size)[0...-2]
105
112
  if error || !params[:block]
106
113
  body << chunk
107
114
  else
@@ -112,13 +119,13 @@ unless Fog.mocking?
112
119
  end
113
120
  end
114
121
  end
115
- end
116
122
 
117
- if parser
118
- body.finish
119
- response.body = parser.response
120
- else
121
- response.body = body
123
+ if parser
124
+ body.finish
125
+ response.body = parser.response
126
+ else
127
+ response.body = body
128
+ end
122
129
  end
123
130
 
124
131
  if error
@@ -90,6 +90,18 @@ describe 'Fog::AWS::S3::Objects' do
90
90
 
91
91
  end
92
92
 
93
+ describe "#get_url" do
94
+
95
+ it "should return a signed expiring url" do
96
+ file = File.open(File.dirname(__FILE__) + '/../../../lorem.txt', 'r')
97
+ object = @bucket.objects.create(:key => 'fogobjectname', :body => file)
98
+ url = @bucket.objects.get_url('fogobjectname', Time.now + 60 * 10)
99
+ open(url).read.should == File.open(File.dirname(__FILE__) + '/../../../lorem.txt', 'r').read
100
+ object.destroy
101
+ end
102
+
103
+ end
104
+
93
105
  describe "#head" do
94
106
 
95
107
  it "should return a Fog::AWS::S3::Object with metadata" do
@@ -106,5 +106,11 @@ describe 'S3.get_bucket' do
106
106
  }.should raise_error(Fog::Errors::NotFound)
107
107
  end
108
108
 
109
+ it 'should request non-subdomain buckets and raise a NotFound error' do
110
+ lambda {
111
+ s3.get_bucket('A-invalid--name')
112
+ }.should raise_error(Fog::Errors::NotFound)
113
+ end
114
+
109
115
  end
110
116
  end
@@ -35,6 +35,12 @@ describe 'S3.get_object' do
35
35
  data.should == file.read
36
36
  end
37
37
 
38
+ it 'should return a signed expiring url' do
39
+ url = s3.get_object_url('foggetobject', 'fog_get_object', Time.now + 60 * 10)
40
+ file = File.open(File.dirname(__FILE__) + '/../../../lorem.txt', 'r')
41
+ open(url).read.should == file.read
42
+ end
43
+
38
44
  end
39
45
  describe 'failure' do
40
46
 
@@ -1,4 +1,5 @@
1
1
  require 'spec'
2
+ require 'open-uri'
2
3
 
3
4
  current_directory = File.dirname(__FILE__)
4
5
  require "#{current_directory}/../lib/fog"
@@ -6,7 +7,7 @@ require "#{current_directory}/../lib/fog"
6
7
 
7
8
  def credentials
8
9
  @credentials ||= begin
9
- credentials_path = "#{File.dirname(__FILE__)}/credentials.yml"
10
+ credentials_path = File.expand_path('~/.fog')
10
11
  credentials_data = File.open(credentials_path).read
11
12
  YAML.load(credentials_data)
12
13
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wesley Beary
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-01 00:00:00 -07:00
12
+ date: 2009-10-05 00:00:00 -07:00
13
13
  default_executable: fog
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency