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 :complete_multipart_upload
|
||||||
request :copy_object
|
request :copy_object
|
||||||
request :delete_bucket
|
request :delete_bucket
|
||||||
|
request :delete_bucket_cors
|
||||||
request :delete_bucket_lifecycle
|
request :delete_bucket_lifecycle
|
||||||
request :delete_bucket_policy
|
request :delete_bucket_policy
|
||||||
request :delete_bucket_website
|
request :delete_bucket_website
|
||||||
|
@ -29,6 +30,7 @@ module Fog
|
||||||
request :delete_multiple_objects
|
request :delete_multiple_objects
|
||||||
request :get_bucket
|
request :get_bucket
|
||||||
request :get_bucket_acl
|
request :get_bucket_acl
|
||||||
|
request :get_bucket_cors
|
||||||
request :get_bucket_lifecycle
|
request :get_bucket_lifecycle
|
||||||
request :get_bucket_location
|
request :get_bucket_location
|
||||||
request :get_bucket_logging
|
request :get_bucket_logging
|
||||||
|
@ -51,6 +53,7 @@ module Fog
|
||||||
request :post_object_hidden_fields
|
request :post_object_hidden_fields
|
||||||
request :put_bucket
|
request :put_bucket
|
||||||
request :put_bucket_acl
|
request :put_bucket_acl
|
||||||
|
request :put_bucket_cors
|
||||||
request :put_bucket_lifecycle
|
request :put_bucket_lifecycle
|
||||||
request :put_bucket_logging
|
request :put_bucket_logging
|
||||||
request :put_bucket_policy
|
request :put_bucket_policy
|
||||||
|
@ -338,6 +341,7 @@ DATA
|
||||||
for key in (params[:query] || {}).keys.sort
|
for key in (params[:query] || {}).keys.sort
|
||||||
if %w{
|
if %w{
|
||||||
acl
|
acl
|
||||||
|
cors
|
||||||
delete
|
delete
|
||||||
lifecycle
|
lifecycle
|
||||||
location
|
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