mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
Support AWS S3 cors configuration for buckets
This commit is contained in:
parent
bcfb5fe1df
commit
c0e80549d9
7 changed files with 345 additions and 0 deletions
41
lib/fog/aws/parsers/storage/cors_configuration.rb
Normal file
41
lib/fog/aws/parsers/storage/cors_configuration.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
module Fog
|
||||
module Parsers
|
||||
module Storage
|
||||
module AWS
|
||||
|
||||
class CorsConfiguration < Fog::Parsers::Base
|
||||
def reset
|
||||
@in_cors_configuration_list = false
|
||||
@cors_rule = {}
|
||||
@response = { 'CORSConfiguration' => [] }
|
||||
end
|
||||
|
||||
def start_element(name, attrs = [])
|
||||
super
|
||||
if name == 'CORSConfiguration'
|
||||
@in_cors_configuration_list = true
|
||||
end
|
||||
end
|
||||
|
||||
def end_element(name)
|
||||
case name
|
||||
when 'CORSConfiguration'
|
||||
@in_cors_configuration_list = false
|
||||
when 'CORSRule'
|
||||
@response['CORSConfiguration'] << @cors_rule
|
||||
@cors_rule = {}
|
||||
when 'MaxAgeSeconds'
|
||||
@cors_rule[name] = value.to_i
|
||||
when 'ID'
|
||||
@cors_rule[name] = value
|
||||
when 'AllowedOrigin', 'AllowedMethod', 'AllowedHeader', 'ExposeHeader'
|
||||
(@cors_rule[name] ||= []) << value
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
41
lib/fog/aws/requests/storage/cors_utils.rb
Normal file
41
lib/fog/aws/requests/storage/cors_utils.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
module Fog
|
||||
module Storage
|
||||
class AWS
|
||||
|
||||
require 'fog/aws/parsers/storage/cors_configuration'
|
||||
|
||||
private
|
||||
|
||||
def self.hash_to_cors(cors)
|
||||
data = "<CORSConfiguration>\n"
|
||||
|
||||
[cors['CORSConfiguration']].flatten.compact.each do |rule|
|
||||
data << " <CORSRule>\n"
|
||||
|
||||
['ID', 'MaxAgeSeconds'].each do |key|
|
||||
data << " <#{key}>#{rule[key]}</#{key}>\n" if rule[key]
|
||||
end
|
||||
|
||||
['AllowedOrigin', 'AllowedMethod', 'AllowedHeader', 'ExposeHeader'].each do |key|
|
||||
[rule[key]].flatten.compact.each do |value|
|
||||
data << " <#{key}>#{value}</#{key}>\n"
|
||||
end
|
||||
end
|
||||
|
||||
data << " </CORSRule>\n"
|
||||
end
|
||||
|
||||
data << "</CORSConfiguration>"
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
def self.cors_to_hash(cors_xml)
|
||||
parser = Fog::Parsers::Storage::AWS::CorsConfiguration.new
|
||||
Nokogiri::XML::SAX::Parser.new(parser).parse(cors_xml)
|
||||
parser.response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
32
lib/fog/aws/requests/storage/delete_bucket_cors.rb
Normal file
32
lib/fog/aws/requests/storage/delete_bucket_cors.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
module Fog
|
||||
module Storage
|
||||
class AWS
|
||||
class Real
|
||||
|
||||
# Deletes the cors configuration information set for the bucket.
|
||||
#
|
||||
# ==== Parameters
|
||||
# * bucket_name<~String> - name of bucket to delete cors rules from
|
||||
#
|
||||
# ==== Returns
|
||||
# * response<~Excon::Response>:
|
||||
# * status<~Integer> - 204
|
||||
#
|
||||
# ==== See Also
|
||||
# http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEcors.html
|
||||
|
||||
def delete_bucket_cors(bucket_name)
|
||||
request({
|
||||
:expects => 204,
|
||||
:headers => {},
|
||||
:host => "#{bucket_name}.#{@host}",
|
||||
:method => 'DELETE',
|
||||
:query => {'cors' => nil}
|
||||
})
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
68
lib/fog/aws/requests/storage/get_bucket_cors.rb
Normal file
68
lib/fog/aws/requests/storage/get_bucket_cors.rb
Normal file
|
@ -0,0 +1,68 @@
|
|||
module Fog
|
||||
module Storage
|
||||
class AWS
|
||||
class Real
|
||||
|
||||
require 'fog/aws/parsers/storage/cors_configuration'
|
||||
|
||||
# Gets the CORS configuration for an S3 bucket
|
||||
#
|
||||
# ==== Parameters
|
||||
# * bucket_name<~String> - name of bucket to get access control list for
|
||||
#
|
||||
# ==== Returns
|
||||
# * response<~Excon::Response>:
|
||||
# * body<~Hash>:
|
||||
# * 'CORSConfiguration'<~Array>:
|
||||
# * 'CORSRule'<~Hash>:
|
||||
# * 'AllowedHeader'<~String> - Which headers are allowed in a pre-flight OPTIONS request through the Access-Control-Request-Headers header.
|
||||
# * 'AllowedMethod'<~String> - Identifies an HTTP method that the domain/origin specified in the rule is allowed to execute.
|
||||
# * 'AllowedOrigin'<~String> - One or more response headers that you want customers to be able to access from their applications (for example, from a JavaScript XMLHttpRequest object).
|
||||
# * 'ExposeHeader'<~String> - One or more headers in the response that you want customers to be able to access from their applications (for example, from a JavaScript XMLHttpRequest object).
|
||||
# * 'ID'<~String> - An optional unique identifier for the rule. The ID value can be up to 255 characters long. The IDs help you find a rule in the configuration.
|
||||
# * 'MaxAgeSeconds'<~Integer> - The time in seconds that your browser is to cache the preflight response for the specified resource.
|
||||
#
|
||||
# ==== See Also
|
||||
# http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETcors.html
|
||||
|
||||
def get_bucket_cors(bucket_name)
|
||||
unless bucket_name
|
||||
raise ArgumentError.new('bucket_name is required')
|
||||
end
|
||||
request({
|
||||
:expects => 200,
|
||||
:headers => {},
|
||||
:host => "#{bucket_name}.#{@host}",
|
||||
:idempotent => true,
|
||||
:method => 'GET',
|
||||
:parser => Fog::Parsers::Storage::AWS::CorsConfiguration.new,
|
||||
:query => {'cors' => nil}
|
||||
})
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock # :nodoc:all
|
||||
|
||||
require 'fog/aws/requests/storage/cors_utils'
|
||||
|
||||
def get_bucket_cors(bucket_name)
|
||||
response = Excon::Response.new
|
||||
if cors = self.data[:cors][:bucket][bucket_name]
|
||||
response.status = 200
|
||||
if cors.is_a?(String)
|
||||
response.body = Fog::Storage::AWS.cors_to_hash(cors)
|
||||
else
|
||||
response.body = cors
|
||||
end
|
||||
else
|
||||
response.status = 404
|
||||
raise(Excon::Errors.status_error({:expects => 200}, response))
|
||||
end
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
51
lib/fog/aws/requests/storage/put_bucket_cors.rb
Normal file
51
lib/fog/aws/requests/storage/put_bucket_cors.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
module Fog
|
||||
module Storage
|
||||
class AWS
|
||||
class Real
|
||||
|
||||
require 'fog/aws/requests/storage/cors_utils'
|
||||
|
||||
# Sets the cors configuration for your bucket. If the configuration exists, Amazon S3 replaces it.
|
||||
#
|
||||
# ==== Parameters
|
||||
# * bucket_name<~String> - name of bucket to modify
|
||||
# * cors<~Hash>:
|
||||
# * CORSConfiguration<~Array>:
|
||||
# * ID<~String>: A unique identifier for the rule.
|
||||
# * AllowedMethod<~String>: An HTTP method that you want to allow the origin to execute.
|
||||
# * AllowedOrigin<~String>: An origin that you want to allow cross-domain requests from.
|
||||
# * AllowedHeader<~String>: Specifies which headers are allowed in a pre-flight OPTIONS request via the Access-Control-Request-Headers header.
|
||||
# * MaxAgeSeconds<~String>: The time in seconds that your browser is to cache the preflight response for the specified resource.
|
||||
# * ExposeHeader<~String>: One or more headers in the response that you want customers to be able to access from their applications.
|
||||
#
|
||||
# ==== See Also
|
||||
# http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTcors.html
|
||||
|
||||
def put_bucket_cors(bucket_name, cors)
|
||||
data = Fog::Storage::AWS.hash_to_cors(cors)
|
||||
|
||||
headers = {}
|
||||
headers['Content-MD5'] = Base64.encode64(Digest::MD5.digest(data)).strip
|
||||
headers['Content-Type'] = 'application/json'
|
||||
headers['Date'] = Fog::Time.now.to_date_header
|
||||
|
||||
request({
|
||||
:body => data,
|
||||
:expects => 200,
|
||||
:headers => headers,
|
||||
:host => "#{bucket_name}.#{@host}",
|
||||
:method => 'PUT',
|
||||
:query => {'cors' => nil}
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def put_bucket_cors(bucket_name, cors)
|
||||
self.data[:cors][:bucket][bucket_name] = Fog::Storage::AWS.hash_to_cors(cors)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -22,6 +22,7 @@ module Fog
|
|||
request :complete_multipart_upload
|
||||
request :copy_object
|
||||
request :delete_bucket
|
||||
request :delete_bucket_cors
|
||||
request :delete_bucket_lifecycle
|
||||
request :delete_bucket_policy
|
||||
request :delete_bucket_website
|
||||
|
@ -29,6 +30,7 @@ module Fog
|
|||
request :delete_multiple_objects
|
||||
request :get_bucket
|
||||
request :get_bucket_acl
|
||||
request :get_bucket_cors
|
||||
request :get_bucket_lifecycle
|
||||
request :get_bucket_location
|
||||
request :get_bucket_logging
|
||||
|
@ -51,6 +53,7 @@ module Fog
|
|||
request :post_object_hidden_fields
|
||||
request :put_bucket
|
||||
request :put_bucket_acl
|
||||
request :put_bucket_cors
|
||||
request :put_bucket_lifecycle
|
||||
request :put_bucket_logging
|
||||
request :put_bucket_policy
|
||||
|
@ -338,6 +341,7 @@ DATA
|
|||
for key in (params[:query] || {}).keys.sort
|
||||
if %w{
|
||||
acl
|
||||
cors
|
||||
delete
|
||||
lifecycle
|
||||
location
|
||||
|
|
108
tests/aws/requests/storage/cors_utils_tests.rb
Normal file
108
tests/aws/requests/storage/cors_utils_tests.rb
Normal file
|
@ -0,0 +1,108 @@
|
|||
require 'fog/aws/requests/storage/cors_utils'
|
||||
|
||||
Shindo.tests('Fog::Storage::AWS | CORS utils', ["aws"]) do
|
||||
tests(".hash_to_cors") do
|
||||
tests(".hash_to_cors({}) at xpath //CORSConfiguration").returns("", "has an empty CORSConfiguration") do
|
||||
xml = Fog::Storage::AWS.hash_to_cors({})
|
||||
Nokogiri::XML(xml).xpath("//CORSConfiguration").first.content.chomp
|
||||
end
|
||||
|
||||
tests(".hash_to_cors({}) at xpath //CORSConfiguration/CORSRule").returns(nil, "has no CORSRules") do
|
||||
xml = Fog::Storage::AWS.hash_to_cors({})
|
||||
Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule").first
|
||||
end
|
||||
|
||||
cors = {
|
||||
'CORSConfiguration' => [
|
||||
{
|
||||
'AllowedOrigin' => ['origin_123', 'origin_456'],
|
||||
'AllowedMethod' => ['GET', 'POST'],
|
||||
'AllowedHeader' => ['Accept', 'Content-Type'],
|
||||
'ID' => 'blah-888',
|
||||
'MaxAgeSeconds' => 2500,
|
||||
'ExposeHeader' => ['x-some-header', 'x-other-header']
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/AllowedOrigin").returns("origin_123", "returns the CORSRule AllowedOrigin") do
|
||||
xml = Fog::Storage::AWS.hash_to_cors(cors)
|
||||
Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/AllowedOrigin")[0].content
|
||||
end
|
||||
|
||||
tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/AllowedOrigin").returns("origin_456", "returns the CORSRule AllowedOrigin") do
|
||||
xml = Fog::Storage::AWS.hash_to_cors(cors)
|
||||
Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/AllowedOrigin")[1].content
|
||||
end
|
||||
|
||||
tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/AllowedMethod").returns("GET", "returns the CORSRule AllowedMethod") do
|
||||
xml = Fog::Storage::AWS.hash_to_cors(cors)
|
||||
Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/AllowedMethod")[0].content
|
||||
end
|
||||
|
||||
tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/AllowedMethod").returns("POST", "returns the CORSRule AllowedMethod") do
|
||||
xml = Fog::Storage::AWS.hash_to_cors(cors)
|
||||
Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/AllowedMethod")[1].content
|
||||
end
|
||||
|
||||
tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/AllowedHeader").returns("Accept", "returns the CORSRule AllowedHeader") do
|
||||
xml = Fog::Storage::AWS.hash_to_cors(cors)
|
||||
Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/AllowedHeader")[0].content
|
||||
end
|
||||
|
||||
tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/AllowedHeader").returns("Content-Type", "returns the CORSRule AllowedHeader") do
|
||||
xml = Fog::Storage::AWS.hash_to_cors(cors)
|
||||
Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/AllowedHeader")[1].content
|
||||
end
|
||||
|
||||
tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/ID").returns("blah-888", "returns the CORSRule ID") do
|
||||
xml = Fog::Storage::AWS.hash_to_cors(cors)
|
||||
Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/ID")[0].content
|
||||
end
|
||||
|
||||
tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/MaxAgeSeconds").returns("2500", "returns the CORSRule MaxAgeSeconds") do
|
||||
xml = Fog::Storage::AWS.hash_to_cors(cors)
|
||||
Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/MaxAgeSeconds")[0].content
|
||||
end
|
||||
|
||||
tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/ExposeHeader").returns("x-some-header", "returns the CORSRule ExposeHeader") do
|
||||
xml = Fog::Storage::AWS.hash_to_cors(cors)
|
||||
Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/ExposeHeader")[0].content
|
||||
end
|
||||
|
||||
tests(".hash_to_cors(#{cors.inspect}) at xpath //CORSConfiguration/CORSRule/ExposeHeader").returns("x-other-header", "returns the CORSRule ExposeHeader") do
|
||||
xml = Fog::Storage::AWS.hash_to_cors(cors)
|
||||
Nokogiri::XML(xml).xpath("//CORSConfiguration/CORSRule/ExposeHeader")[1].content
|
||||
end
|
||||
end
|
||||
|
||||
tests(".cors_to_hash") do
|
||||
cors_xml = <<-XML
|
||||
<CORSConfiguration>
|
||||
<CORSRule>
|
||||
<AllowedOrigin>http://www.example.com</AllowedOrigin>
|
||||
<AllowedOrigin>http://www.example2.com</AllowedOrigin>
|
||||
<AllowedHeader>Content-Length</AllowedHeader>
|
||||
<AllowedHeader>X-Foobar</AllowedHeader>
|
||||
<AllowedMethod>PUT</AllowedMethod>
|
||||
<AllowedMethod>GET</AllowedMethod>
|
||||
<MaxAgeSeconds>3000</MaxAgeSeconds>
|
||||
<ExposeHeader>x-amz-server-side-encryption</ExposeHeader>
|
||||
<ExposeHeader>x-amz-balls</ExposeHeader>
|
||||
</CORSRule>
|
||||
</CORSConfiguration>
|
||||
XML
|
||||
|
||||
tests(".cors_to_hash(#{cors_xml.inspect})").returns({
|
||||
"CORSConfiguration" => [{
|
||||
"AllowedOrigin" => ["http://www.example.com", "http://www.example2.com"],
|
||||
"AllowedHeader" => ["Content-Length", "X-Foobar"],
|
||||
"AllowedMethod" => ["PUT", "GET"],
|
||||
"MaxAgeSeconds" => 3000,
|
||||
"ExposeHeader" => ["x-amz-server-side-encryption", "x-amz-balls"]
|
||||
}]
|
||||
}, 'returns hash of CORS XML') do
|
||||
Fog::Storage::AWS.cors_to_hash(cors_xml)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue