s33r 0.4.2 → 0.5
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/examples/cli/instant_download_server.rb +88 -0
- data/examples/cli/s3cli.rb +31 -52
- data/examples/cli/simple.rb +16 -6
- data/examples/fores33r/app/controllers/browser_controller.rb +12 -10
- data/examples/fores33r/app/helpers/application_helper.rb +2 -1
- data/examples/fores33r/app/views/browser/_upload.rhtml +1 -1
- data/examples/fores33r/app/views/browser/index.rhtml +4 -4
- data/examples/fores33r/config/environment.rb +5 -3
- data/examples/fores33r/log/development.log +2259 -0
- data/examples/fores33r/log/mongrel.log +59 -0
- data/examples/s3.yaml +2 -6
- data/lib/s33r/bucket.rb +103 -0
- data/lib/s33r/bucket_listing.rb +33 -76
- data/lib/s33r/client.rb +305 -446
- data/lib/s33r/networking.rb +197 -0
- data/lib/s33r/s33r_exception.rb +29 -18
- data/lib/s33r/s33r_http.rb +36 -18
- data/lib/s33r/s3_acl.rb +32 -52
- data/lib/s33r/s3_logging.rb +117 -0
- data/lib/s33r/s3_obj.rb +124 -69
- data/lib/s33r/utility.rb +447 -0
- data/test/cases/spec_acl.rb +10 -40
- data/test/cases/spec_bucket_listing.rb +12 -32
- data/test/cases/spec_logging.rb +47 -0
- data/test/cases/spec_networking.rb +11 -0
- data/test/cases/spec_s3_object.rb +44 -5
- data/test/cases/spec_utility.rb +264 -0
- data/test/files/acl.xml +0 -6
- data/test/files/config.yaml +5 -0
- data/test/files/logging_status_disabled.xml +3 -0
- data/test/files/logging_status_enabled.xml +7 -0
- data/test/test_setup.rb +7 -2
- metadata +16 -94
- data/examples/cli/acl_x.rb +0 -41
- data/examples/cli/logging_x.rb +0 -20
- data/examples/fores33r/README +0 -183
- data/html/classes/MIME.html +0 -120
- data/html/classes/MIME/InvalidContentType.html +0 -119
- data/html/classes/MIME/Type.html +0 -1173
- data/html/classes/MIME/Types.html +0 -566
- data/html/classes/Net.html +0 -108
- data/html/classes/Net/HTTPGenericRequest.html +0 -233
- data/html/classes/Net/HTTPResponse.html +0 -271
- data/html/classes/S33r.html +0 -986
- data/html/classes/S33r/BucketListing.html +0 -434
- data/html/classes/S33r/Client.html +0 -1575
- data/html/classes/S33r/LoggingResource.html +0 -222
- data/html/classes/S33r/NamedBucket.html +0 -693
- data/html/classes/S33r/OrderlyXmlMarkup.html +0 -165
- data/html/classes/S33r/S33rException.html +0 -124
- data/html/classes/S33r/S33rException/BucketListingMaxKeysError.html +0 -111
- data/html/classes/S33r/S33rException/BucketNotLogTargetable.html +0 -119
- data/html/classes/S33r/S33rException/InvalidBucketListing.html +0 -111
- data/html/classes/S33r/S33rException/InvalidPermission.html +0 -111
- data/html/classes/S33r/S33rException/InvalidS3GroupType.html +0 -111
- data/html/classes/S33r/S33rException/MalformedBucketName.html +0 -111
- data/html/classes/S33r/S33rException/MethodNotAvailable.html +0 -111
- data/html/classes/S33r/S33rException/MissingBucketName.html +0 -111
- data/html/classes/S33r/S33rException/MissingRequiredHeaders.html +0 -111
- data/html/classes/S33r/S33rException/MissingResource.html +0 -111
- data/html/classes/S33r/S33rException/S3FallenOver.html +0 -111
- data/html/classes/S33r/S33rException/TryingToPutEmptyResource.html +0 -117
- data/html/classes/S33r/S33rException/UnsupportedCannedACL.html +0 -111
- data/html/classes/S33r/S33rException/UnsupportedHTTPMethod.html +0 -111
- data/html/classes/S33r/S3ACL.html +0 -125
- data/html/classes/S33r/S3ACL/ACLDoc.html +0 -521
- data/html/classes/S33r/S3ACL/AmazonCustomer.html +0 -168
- data/html/classes/S33r/S3ACL/CanonicalUser.html +0 -212
- data/html/classes/S33r/S3ACL/Grant.html +0 -403
- data/html/classes/S33r/S3ACL/Grantee.html +0 -239
- data/html/classes/S33r/S3ACL/Group.html +0 -178
- data/html/classes/S33r/S3Object.html +0 -618
- data/html/classes/S33r/Sync.html +0 -152
- data/html/classes/XML.html +0 -202
- data/html/classes/XML/Document.html +0 -125
- data/html/classes/XML/Node.html +0 -124
- data/html/created.rid +0 -1
- data/html/files/CHANGELOG.html +0 -107
- data/html/files/MIT-LICENSE.html +0 -129
- data/html/files/README_txt.html +0 -259
- data/html/files/lib/s33r/bucket_listing_rb.html +0 -101
- data/html/files/lib/s33r/builder_rb.html +0 -108
- data/html/files/lib/s33r/client_rb.html +0 -111
- data/html/files/lib/s33r/core_rb.html +0 -113
- data/html/files/lib/s33r/libxml_extensions_rb.html +0 -101
- data/html/files/lib/s33r/libxml_loader_rb.html +0 -109
- data/html/files/lib/s33r/logging_rb.html +0 -108
- data/html/files/lib/s33r/mimetypes_rb.html +0 -120
- data/html/files/lib/s33r/named_bucket_rb.html +0 -101
- data/html/files/lib/s33r/s33r_exception_rb.html +0 -101
- data/html/files/lib/s33r/s33r_http_rb.html +0 -108
- data/html/files/lib/s33r/s3_acl_rb.html +0 -108
- data/html/files/lib/s33r/s3_obj_rb.html +0 -108
- data/html/files/lib/s33r/sync_rb.html +0 -101
- data/html/files/lib/s33r_rb.html +0 -101
- data/html/fr_class_index.html +0 -66
- data/html/fr_file_index.html +0 -44
- data/html/fr_method_index.html +0 -183
- data/html/index.html +0 -24
- data/html/rdoc-style.css +0 -208
- data/lib/s33r/core.rb +0 -296
- data/lib/s33r/logging.rb +0 -43
- data/lib/s33r/named_bucket.rb +0 -148
- data/lib/s33r/sync.rb +0 -13
- data/test/cases/spec_all_buckets.rb +0 -28
- data/test/cases/spec_client.rb +0 -101
- data/test/cases/spec_core.rb +0 -128
- data/test/cases/spec_namedbucket.rb +0 -46
- data/test/cases/spec_sync.rb +0 -34
- data/test/files/all_buckets.xml +0 -21
- data/test/files/client_config.yml +0 -5
- data/test/files/namedbucket_config.yml +0 -8
- data/test/files/namedbucket_config2.yml +0 -8
- data/test/test_bucket_setup.rb +0 -41
data/lib/s33r/core.rb
DELETED
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
require 'base64'
|
|
2
|
-
require 'time'
|
|
3
|
-
require 'net/http'
|
|
4
|
-
require 'net/https'
|
|
5
|
-
require 'openssl'
|
|
6
|
-
require 'parsedate'
|
|
7
|
-
require File.join(File.dirname(__FILE__), 'libxml_loader')
|
|
8
|
-
|
|
9
|
-
# Module to handle S3 operations which don't require an internet connection,
|
|
10
|
-
# i.e. data validation and request-building operations;
|
|
11
|
-
# also holds all the constants relating to S3.
|
|
12
|
-
#
|
|
13
|
-
# Parts of this code are heavily based on Amazon's code. Here's their license:
|
|
14
|
-
#
|
|
15
|
-
# This software code is made available "AS IS" without warranties of any
|
|
16
|
-
# kind. You may copy, display, modify and redistribute the software
|
|
17
|
-
# code either by itself or as incorporated into your code; provided that
|
|
18
|
-
# you do not remove any proprietary notices. Your use of this software
|
|
19
|
-
# code is at your own risk and you waive any claim against Amazon
|
|
20
|
-
# Digital Services, Inc. or its affiliates with respect to your use of
|
|
21
|
-
# this software code. (c) 2006 Amazon Digital Services, Inc. or its
|
|
22
|
-
# affiliates.
|
|
23
|
-
module S33r
|
|
24
|
-
HOST = 's3.amazonaws.com'
|
|
25
|
-
PORT = 443
|
|
26
|
-
NON_SSL_PORT = 80
|
|
27
|
-
METADATA_PREFIX = 'x-amz-meta-'
|
|
28
|
-
# Size of each chunk (in bytes) to be sent per request when putting files (1Mb).
|
|
29
|
-
DEFAULT_CHUNK_SIZE = 1048576
|
|
30
|
-
AWS_HEADER_PREFIX = 'x-amz-'
|
|
31
|
-
AWS_AUTH_HEADER_VALUE = "AWS %s:%s"
|
|
32
|
-
INTERESTING_HEADERS = ['content-md5', 'content-type', 'date']
|
|
33
|
-
# Headers which must be included with every request to S3.
|
|
34
|
-
REQUIRED_HEADERS = ['Content-Type', 'Date']
|
|
35
|
-
# Canned ACLs made available by S3.
|
|
36
|
-
CANNED_ACLS = ['private', 'public-read', 'public-read-write', 'authenticated-read']
|
|
37
|
-
# HTTP methods which S3 will respond to.
|
|
38
|
-
METHOD_VERBS = ['GET', 'PUT', 'HEAD', 'POST', 'DELETE']
|
|
39
|
-
# Maximum number which can be passed in max-keys parameter when GETting bucket list.
|
|
40
|
-
BUCKET_LIST_MAX_MAX_KEYS = 1000
|
|
41
|
-
# Default number of seconds an authenticated URL will last for (15 minutes).
|
|
42
|
-
DEFAULT_EXPIRY_SECS = 60 * 15
|
|
43
|
-
# The namespace used for response body XML documents.
|
|
44
|
-
RESPONSE_NAMESPACE_URI = "http://s3.amazonaws.com/doc/2006-03-01/"
|
|
45
|
-
|
|
46
|
-
# Permissions which can be set within a <Grant>
|
|
47
|
-
# (see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingPermissions.html).
|
|
48
|
-
#
|
|
49
|
-
# NB I've missed out the WRITE_ACP permission as this is functionally
|
|
50
|
-
# equivalent to FULL_CONTROL.
|
|
51
|
-
PERMISSIONS = {
|
|
52
|
-
:read => 'READ', # permission to read
|
|
53
|
-
:write => 'WRITE', # permission to write
|
|
54
|
-
:read_acl => 'READ_ACP', # permission to read ACL settings
|
|
55
|
-
:all => 'FULL_CONTROL' # do anything
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
# Used for generating ACL XML documents.
|
|
59
|
-
NAMESPACE = 'xsi'
|
|
60
|
-
NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema-instance'
|
|
61
|
-
GRANTEE_TYPES = {
|
|
62
|
-
:amazon_customer => 'AmazonCustomerByEmail',
|
|
63
|
-
:canonical_user => 'CanonicalUser',
|
|
64
|
-
:group => 'Group'
|
|
65
|
-
}
|
|
66
|
-
S3_GROUP_TYPES = {
|
|
67
|
-
:all_users => 'global/AllUsers',
|
|
68
|
-
:authenticated_users => 'global/AuthenticatedUsers',
|
|
69
|
-
:log_delivery => 's3/LogDelivery'
|
|
70
|
-
}
|
|
71
|
-
GROUP_ACL_URI_BASE = 'http://acs.amazonaws.com/groups/'
|
|
72
|
-
|
|
73
|
-
# Build canonical string for signing;
|
|
74
|
-
# modified (slightly) from the Amazon sample code.
|
|
75
|
-
def generate_canonical_string(method, path, headers={}, expires=nil)
|
|
76
|
-
interesting_headers = {}
|
|
77
|
-
headers.each do |key, value|
|
|
78
|
-
lk = key.downcase
|
|
79
|
-
if (INTERESTING_HEADERS.include?(lk) or lk =~ /^#{AWS_HEADER_PREFIX}/o)
|
|
80
|
-
interesting_headers[lk] = value
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# These fields get empty strings if they don't exist.
|
|
85
|
-
interesting_headers['content-type'] ||= ''
|
|
86
|
-
interesting_headers['content-md5'] ||= ''
|
|
87
|
-
|
|
88
|
-
# If you're using expires for query string auth, then it trumps date.
|
|
89
|
-
if not expires.nil?
|
|
90
|
-
interesting_headers['date'] = expires
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
buf = "#{method}\n"
|
|
94
|
-
interesting_headers.sort { |a, b| a[0] <=> b[0] }.each do |key, value|
|
|
95
|
-
if key =~ /^#{AWS_HEADER_PREFIX}/o
|
|
96
|
-
buf << "#{key}:#{value}\n"
|
|
97
|
-
else
|
|
98
|
-
buf << "#{value}\n"
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
# Ignore everything after the question mark...
|
|
103
|
-
buf << path.gsub(/\?.*$/, '')
|
|
104
|
-
|
|
105
|
-
# ...unless there is an acl, logging or torrent parameter
|
|
106
|
-
if path =~ /[&?]acl($|&|=)/
|
|
107
|
-
buf << '?acl'
|
|
108
|
-
elsif path =~ /[&?]torrent($|&|=)/
|
|
109
|
-
buf << '?torrent'
|
|
110
|
-
elsif path =~ /[&?]logging($|&|=)/
|
|
111
|
-
buf << '?logging'
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
buf
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# Get the value for the AWS authentication header.
|
|
118
|
-
def generate_auth_header_value(method, path, headers, aws_access_key, aws_secret_access_key)
|
|
119
|
-
raise S33rException::MethodNotAvailable, "Method %s not available" % method if !METHOD_VERBS.include?(method)
|
|
120
|
-
|
|
121
|
-
# check the headers needed for authentication have been set
|
|
122
|
-
missing_headers = REQUIRED_HEADERS - headers.keys
|
|
123
|
-
if !(missing_headers.empty?)
|
|
124
|
-
raise S33rException::MissingRequiredHeaders,
|
|
125
|
-
"Headers required for AWS auth value are missing: " + missing_headers.join(', ')
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
# get the AWS header
|
|
129
|
-
canonical_string = generate_canonical_string(method, path, headers)
|
|
130
|
-
signature = generate_signature(aws_secret_access_key, canonical_string)
|
|
131
|
-
AWS_AUTH_HEADER_VALUE % [aws_access_key, signature]
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
# Encode the given string with the aws_secret_access_key, by taking the
|
|
135
|
-
# hmac sha1 sum, and then base64 encoding it.
|
|
136
|
-
def generate_signature(aws_secret_access_key, str)
|
|
137
|
-
digest = OpenSSL::HMAC::digest(OpenSSL::Digest::Digest.new("SHA1"), aws_secret_access_key, str)
|
|
138
|
-
Base64.encode64(digest).strip
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# Build the headers required with every S3 request (Date and Content-Type);
|
|
142
|
-
# options hash can contain extra header settings;
|
|
143
|
-
# +:date+ and +:content_type+ are required headers, and set to defaults if not supplied
|
|
144
|
-
def add_default_headers(headers, options={})
|
|
145
|
-
# set the default headers required by AWS
|
|
146
|
-
missing_headers = REQUIRED_HEADERS - headers.keys
|
|
147
|
-
|
|
148
|
-
if missing_headers.include?('Content-Type')
|
|
149
|
-
headers['Content-Type'] = options[:content_type] || ''
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
if missing_headers.include?('Date')
|
|
153
|
-
date = options[:date] || Time.now
|
|
154
|
-
headers['Date'] = date.httpdate
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
headers
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
# Add metadata headers, correctly prefixing them first,
|
|
161
|
-
# e.g. you might do metadata_headers({}, {'myname' => 'elliot', 'myage' => 36})
|
|
162
|
-
# to add two headers to the request:
|
|
163
|
-
#
|
|
164
|
-
# x-amz-meta-myname: elliot
|
|
165
|
-
# x-amz-meta-myage: 36
|
|
166
|
-
#
|
|
167
|
-
# Returns headers with the metadata headers appended.
|
|
168
|
-
def metadata_headers(headers, metadata={})
|
|
169
|
-
unless metadata.empty?
|
|
170
|
-
metadata.each { |key, value| headers[METADATA_PREFIX + key] = value.to_s }
|
|
171
|
-
end
|
|
172
|
-
headers
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
# Add a canned ACL setter header.
|
|
176
|
-
def canned_acl_header(canned_acl, headers={})
|
|
177
|
-
unless canned_acl.nil?
|
|
178
|
-
unless CANNED_ACLS.include?(canned_acl)
|
|
179
|
-
raise S33rException::UnsupportedCannedACL, "The canned ACL #{canned_acl} is not supported"
|
|
180
|
-
end
|
|
181
|
-
headers[AWS_HEADER_PREFIX + 'acl'] = canned_acl
|
|
182
|
-
end
|
|
183
|
-
headers
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
# Guess a file's mime type.
|
|
187
|
-
# If the mime_type for a file cannot be guessed, "text/plain" is used.
|
|
188
|
-
def guess_mime_type(file_name)
|
|
189
|
-
mime_type = MIME::Types.type_for(file_name)[0]
|
|
190
|
-
mime_type ||= MIME::Types['text/plain'][0]
|
|
191
|
-
mime_type
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
# Ensure that a bucket_name is well-formed (no leading or trailing slash).
|
|
195
|
-
def bucket_name_valid?(bucket_name)
|
|
196
|
-
if ('/' == bucket_name[0,1] || '/' == bucket_name[-1,1])
|
|
197
|
-
raise S33rException::MalformedBucketName, "Bucket name cannot have a leading or trailing slash"
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
# Convert a hash of name/value pairs to querystring variables.
|
|
202
|
-
# Name for a variable can be a string or symbol.
|
|
203
|
-
def generate_querystring(pairs={})
|
|
204
|
-
str = ''
|
|
205
|
-
if pairs.size > 0
|
|
206
|
-
str += "?" + pairs.map { |key, value| "#{key}=#{CGI::escape(value.to_s)}" }.join('&')
|
|
207
|
-
end
|
|
208
|
-
str
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
# Return the location of the ACL for a resource.
|
|
212
|
-
def s3_acl_path(bucket_name, resource_key)
|
|
213
|
-
s3_path(bucket_name, resource_key) + "?acl"
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
# Return the location of the logging definition for a resource.
|
|
217
|
-
def s3_logging_path(bucket_name, resource_key)
|
|
218
|
-
s3_path(bucket_name, resource_key) + "?logging"
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
# Prepend scheme and HOST to path.
|
|
222
|
-
def s3_url(path)
|
|
223
|
-
"http://" + HOST + path
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
# Public readable URL for a bucket and resource.
|
|
227
|
-
def s3_public_url(bucket_name, resource_key='')
|
|
228
|
-
path = s3_path(bucket_name, resource_key)
|
|
229
|
-
s3_url(path)
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
# Returns the path for this bucket and key.
|
|
233
|
-
def s3_path(bucket_name, resource_key)
|
|
234
|
-
path = '/' + bucket_name
|
|
235
|
-
path += '/' + resource_key unless '' == resource_key or resource_key.nil?
|
|
236
|
-
path
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
# Generate a get-able URL for an S3 resource key which passes authentication in querystring.
|
|
240
|
-
#
|
|
241
|
-
# int +expires+: when the URL expires (seconds since the epoch); NB you can use S33r.parse_expiry
|
|
242
|
-
# to generate a suitable value from a string.
|
|
243
|
-
def s3_authenticated_url(aws_access_key, aws_secret_access_key, bucket_name, resource_key,
|
|
244
|
-
expires=nil)
|
|
245
|
-
path = s3_path(bucket_name, resource_key)
|
|
246
|
-
expires = S33r.parse_expiry(expires)
|
|
247
|
-
|
|
248
|
-
canonical_string = generate_canonical_string('GET', path, {}, expires)
|
|
249
|
-
signature = generate_signature(aws_secret_access_key, canonical_string)
|
|
250
|
-
|
|
251
|
-
querystring = generate_querystring({ 'Signature' => signature, 'Expires' => expires,
|
|
252
|
-
'AWSAccessKeyId' => aws_access_key })
|
|
253
|
-
|
|
254
|
-
return s3_url(path) + querystring
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
# Turn keys in a hash +hsh+ into symbols.
|
|
258
|
-
#
|
|
259
|
-
# Returns a hash with 'symbolised' keys.
|
|
260
|
-
def S33r.keys_to_symbols(hsh)
|
|
261
|
-
symbolised = hsh.inject({}) do |symbolised, key_value|
|
|
262
|
-
symbolised.merge({key_value[0].to_sym => key_value[1]})
|
|
263
|
-
end
|
|
264
|
-
symbolised
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
# Parse an expiry date to seconds since the epoch.
|
|
268
|
-
#
|
|
269
|
-
# +expires+ can be set to 'forever' to get a time 20 years in the future;
|
|
270
|
-
# 'default' to use the current time + DEFAULT_EXPIRY_SECS;
|
|
271
|
-
# or to a specific date (parseable by ParseDate); or to an integer
|
|
272
|
-
# representing seconds since the epoch.
|
|
273
|
-
#
|
|
274
|
-
# TODO: testing for this
|
|
275
|
-
def S33r.parse_expiry(expires)
|
|
276
|
-
base_expires = Time.now.to_i
|
|
277
|
-
if 'forever' == expires
|
|
278
|
-
# 20 years (same as forever in computer terms)
|
|
279
|
-
expires = base_expires + (60 * 60 * 24 * 365.25 * 20).to_i
|
|
280
|
-
elsif 'default' == expires
|
|
281
|
-
# default to DEFAULT_EXPIRY_SECS seconds from now if expires not set
|
|
282
|
-
expires = base_expires + DEFAULT_EXPIRY_SECS
|
|
283
|
-
elsif expires.is_a?(String)
|
|
284
|
-
datetime_parts = ParseDate.parsedate(expires)
|
|
285
|
-
expires = Time.gm(*datetime_parts).to_i
|
|
286
|
-
end
|
|
287
|
-
expires
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
# Remove the namespace declaration from S3 XML response bodies (libxml
|
|
291
|
-
# isn't fond of it).
|
|
292
|
-
def S33r.remove_namespace(xml_in)
|
|
293
|
-
namespace = S33r::RESPONSE_NAMESPACE_URI.gsub('/', '\/')
|
|
294
|
-
xml_in.gsub(/ xmlns="#{namespace}"/, '')
|
|
295
|
-
end
|
|
296
|
-
end
|
data/lib/s33r/logging.rb
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
require 'rubygems'
|
|
2
|
-
require_gem 'builder'
|
|
3
|
-
require File.join(File.dirname(__FILE__), 'libxml_loader')
|
|
4
|
-
|
|
5
|
-
module S33r
|
|
6
|
-
# For manipulating logging directives on resources
|
|
7
|
-
# (see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/LoggingHowTo.html).
|
|
8
|
-
#
|
|
9
|
-
# Creating a LoggingResource instance using new and no arguments will generate a "blank" instance;
|
|
10
|
-
# this can be put to the ?logging URL for a resource to remove logging from it.
|
|
11
|
-
class LoggingResource
|
|
12
|
-
attr_reader :log_target, :log_prefix
|
|
13
|
-
|
|
14
|
-
def initialize(log_target=nil, log_prefix=nil)
|
|
15
|
-
@log_target = log_target
|
|
16
|
-
@log_prefix = log_prefix
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# Generate a BucketLoggingStatus XML document for putting to the ?logging
|
|
20
|
-
# URL for a resource.
|
|
21
|
-
#
|
|
22
|
-
#-- TODO: test generates correct XML
|
|
23
|
-
def to_xml
|
|
24
|
-
xml_str = ""
|
|
25
|
-
xml = Builder::XmlMarkup.new(:target => xml_str, :indent => 0)
|
|
26
|
-
|
|
27
|
-
xml.instruct!
|
|
28
|
-
|
|
29
|
-
# BucketLoggingStatus XML.
|
|
30
|
-
xml.BucketLoggingStatus({"xmlns" => RESPONSE_NAMESPACE_URI}) {
|
|
31
|
-
unless @log_target.nil? and @log_prefix.nil?
|
|
32
|
-
xml.LoggingEnabled {
|
|
33
|
-
xml.TargetBucket @log_target
|
|
34
|
-
xml.TargetPrefix @log_prefix
|
|
35
|
-
}
|
|
36
|
-
end
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
xml_str
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
end
|
|
43
|
-
end
|
data/lib/s33r/named_bucket.rb
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
#-- TODO: manipulation of bucket_listing through options hash, e.g. fetch particular page,
|
|
2
|
-
#-- specify a prefix and/or delimiter
|
|
3
|
-
|
|
4
|
-
require File.join(File.dirname(__FILE__), 'client')
|
|
5
|
-
require File.join(File.dirname(__FILE__), 's3_obj')
|
|
6
|
-
require File.join(File.dirname(__FILE__), 's33r_exception')
|
|
7
|
-
|
|
8
|
-
module S33r
|
|
9
|
-
# Wraps the S33r::Client class to make it more convenient for use with a single bucket.
|
|
10
|
-
class NamedBucket < Client
|
|
11
|
-
attr_accessor :name, :strict, :public_contents, :dump_requests
|
|
12
|
-
|
|
13
|
-
# Initialize an instance from a config_file. The config. file can include a separate
|
|
14
|
-
# +options+ section specifying options specific to NamedBucket instances (see the initialize method
|
|
15
|
-
# for more details).
|
|
16
|
-
# Other options are as for S33r::Client.init.
|
|
17
|
-
def NamedBucket.init(config_file)
|
|
18
|
-
aws_access_key, aws_secret_access_key, options = super.class.load_config(config_file)
|
|
19
|
-
NamedBucket.new(aws_access_key, aws_secret_access_key, options)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# Initialize a NamedBucket instance.
|
|
23
|
-
#
|
|
24
|
-
# +options+ is a hash of options for this instance:
|
|
25
|
-
# * <tt>:default_bucket => 'xxxx'</tt>: name of the bucket this client is attached to.
|
|
26
|
-
# * <tt>:public_contents => true</tt>: all items put into bucket are made public (can be overridden per request).
|
|
27
|
-
# * <tt>:strict => true</tt>: check whether the bucket exists before attempting to initialize; initialization \
|
|
28
|
-
# fails if the bucket does not exist
|
|
29
|
-
def initialize(aws_access_key, aws_secret_access_key, options={}, &block)
|
|
30
|
-
super(aws_access_key, aws_secret_access_key, options)
|
|
31
|
-
|
|
32
|
-
@name = options[:default_bucket]
|
|
33
|
-
if @name.nil?
|
|
34
|
-
raise S33rException::MissingBucketName, "NamedBucket cannot be initialised without specifying\
|
|
35
|
-
a :default_bucket option"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# all content inside the bucket should be created as public-read
|
|
39
|
-
@public_contents = (true == options[:public_contents])
|
|
40
|
-
@client_headers.merge!(canned_acl_header('public-read')) if @public_contents
|
|
41
|
-
|
|
42
|
-
@strict = (true == options[:strict])
|
|
43
|
-
if @strict && !bucket_exists?(@name)
|
|
44
|
-
raise S33rException::MissingResource, "Non-existent bucket #{@bucket_name} specified"
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
yield self if block_given?
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Are all objects added to this bucket made public by default?
|
|
51
|
-
def public_contents?
|
|
52
|
-
@public_contents
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Is this a strict bucket (i.e. the target bucket must exist on S3)?
|
|
56
|
-
def strict?
|
|
57
|
-
@strict
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# Get a single object from a bucket as an S3Object.
|
|
61
|
-
#
|
|
62
|
-
# To get a bare object (with no content):
|
|
63
|
-
#
|
|
64
|
-
# bucket['key']
|
|
65
|
-
#
|
|
66
|
-
# To get the object and load its content:
|
|
67
|
-
#
|
|
68
|
-
# bucket['key', :load]
|
|
69
|
-
def [](key, eager=false)
|
|
70
|
-
obj = listing.contents[key]
|
|
71
|
-
obj.named_bucket = self
|
|
72
|
-
obj.load if :load == eager
|
|
73
|
-
obj
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# Get a raw response for a key inside the bucket.
|
|
77
|
-
def get_raw(key, headers={})
|
|
78
|
-
get_resource(@name, key, headers)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# Get a BucketListing instance for the content of this bucket.
|
|
82
|
-
# Uses the Client.list_bucket method to get the listing.
|
|
83
|
-
def listing
|
|
84
|
-
list_bucket(@name)[1]
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# Does this bucket exist?
|
|
88
|
-
# Returns true if the bucket this NamedBucket is mapped to exists.
|
|
89
|
-
def exists?
|
|
90
|
-
bucket_exists?(@name)
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
# Delete the bucket.
|
|
94
|
-
def destroy(headers={}, options={})
|
|
95
|
-
delete_bucket(@name, headers, options)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# Get a pretty list of the keys in the bucket.
|
|
99
|
-
def keys
|
|
100
|
-
listing.pretty
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# List content of the bucket, and attach each item to this NamedBucket
|
|
104
|
-
# instance as it is yielded (to enable easier manipulation directly from the S3Object).
|
|
105
|
-
# Note that the objects are incomplete, as the data associated with them has not been
|
|
106
|
-
# "got" from S3 yet.
|
|
107
|
-
def each_object
|
|
108
|
-
listing.contents.each_value { |obj| obj.named_bucket = self; yield obj }
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
# Does the given key exist in the bucket?
|
|
112
|
-
# Returns boolean
|
|
113
|
-
def key_exists?(key)
|
|
114
|
-
resource_exists?(@name, key)
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# Put a string into a key inside the bucket.
|
|
118
|
-
def put_text(string, resource_key, headers={})
|
|
119
|
-
super(string, @name, resource_key, headers)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# Put a file into the bucket.
|
|
123
|
-
def put_file(filename, resource_key=nil, headers={}, options={})
|
|
124
|
-
super(filename, @name, resource_key, headers, options)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
# Put a generic stream (e.g. from a file handle) into the bucket.
|
|
128
|
-
def put_stream(data, resource_key, headers={})
|
|
129
|
-
put_resource(@name, resource_key, data, headers)
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
# Delete an object from the bucket.
|
|
133
|
-
# NB S3 doesn't discriminate between successfully deleting a key
|
|
134
|
-
# and trying to delete a non-existent key (both return a 204).
|
|
135
|
-
# If you want to test for existence first, use key_exists?.
|
|
136
|
-
def delete(key, headers={})
|
|
137
|
-
delete_resource(@name, key, headers)
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
# Generate an authenticated URL (see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/)
|
|
141
|
-
# for an object inside this bucket.
|
|
142
|
-
#
|
|
143
|
-
# +expires+: time in secs since the epoch when the link should become invalid.
|
|
144
|
-
def s3_authenticated_url(resource_key, expires=(Time.now.to_i + DEFAULT_EXPIRY_SECS))
|
|
145
|
-
super(@aws_access_key, @aws_secret_access_key, @name, resource_key, expires)
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
|
-
end
|