1 # -*- coding: utf-8 -*-
2 # Copyright 2012 Google Inc. All Rights Reserved.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 """Implementation of cors configuration command for GCS buckets."""
17 from __future__
import absolute_import
21 from gslib
.command
import Command
22 from gslib
.command_argument
import CommandArgument
23 from gslib
.cs_api_map
import ApiSelector
24 from gslib
.exception
import CommandException
25 from gslib
.help_provider
import CreateHelpText
26 from gslib
.storage_url
import StorageUrlFromString
27 from gslib
.third_party
.storage_apitools
import storage_v1_messages
as apitools_messages
28 from gslib
.translation_helper
import CorsTranslation
29 from gslib
.translation_helper
import REMOVE_CORS_CONFIG
30 from gslib
.util
import NO_MAX
31 from gslib
.util
import UrlsAreForSingleProvider
39 gsutil cors set cors-json-file url...
42 _GET_DESCRIPTION
= """
44 Gets the CORS configuration for a single bucket. The output from
45 "cors get" can be redirected into a file, edited and then updated using
49 _SET_DESCRIPTION
= """
51 Sets the CORS configuration for one or more buckets. The
52 cors-json-file specified on the command line should be a path to a local
53 file containing a JSON document as described above.
56 _SYNOPSIS
= _SET_SYNOPSIS
+ _GET_SYNOPSIS
.lstrip('\n') + '\n\n'
59 Gets or sets the Cross-Origin Resource Sharing (CORS) configuration on one or
60 more buckets. This command is supported for buckets only, not objects. An
61 example CORS JSON document looks like the folllowing:
65 "origin": ["http://origin1.example.com"],
66 "responseHeader": ["Content-Type"],
72 The above JSON document explicitly allows cross-origin GET requests from
73 http://origin1.example.com and may include the Content-Type response header.
74 The preflight request may be cached for 1 hour.
76 The following (empty) CORS JSON document removes all CORS configuration for
81 The cors command has two sub-commands:
82 """ + '\n'.join([_GET_DESCRIPTION
, _SET_DESCRIPTION
]) + """
83 For more info about CORS, see http://www.w3.org/TR/cors/.
86 _DETAILED_HELP_TEXT
= CreateHelpText(_SYNOPSIS
, _DESCRIPTION
)
88 _get_help_text
= CreateHelpText(_GET_SYNOPSIS
, _GET_DESCRIPTION
)
89 _set_help_text
= CreateHelpText(_SET_SYNOPSIS
, _SET_DESCRIPTION
)
92 class CorsCommand(Command
):
93 """Implementation of gsutil cors command."""
95 # Command specification. See base class for documentation.
96 command_spec
= Command
.CreateCommandSpec(
98 command_name_aliases
=['getcors', 'setcors'],
99 usage_synopsis
=_SYNOPSIS
,
102 supported_sub_args
='',
104 provider_url_ok
=False,
106 gs_api_support
=[ApiSelector
.XML
, ApiSelector
.JSON
],
107 gs_default_api
=ApiSelector
.JSON
,
110 CommandArgument
.MakeNFileURLsArgument(1),
111 CommandArgument
.MakeZeroOrMoreCloudBucketURLsArgument()
114 CommandArgument
.MakeNCloudBucketURLsArgument(1)
118 # Help specification. See help_provider.py for documentation.
119 help_spec
= Command
.HelpSpec(
121 help_name_aliases
=['getcors', 'setcors', 'cross-origin'],
122 help_type
='command_help',
123 help_one_line_summary
=(
124 'Set a CORS JSON document for one or more buckets'),
125 help_text
=_DETAILED_HELP_TEXT
,
126 subcommand_help_text
={'get': _get_help_text
, 'set': _set_help_text
},
129 def _CalculateUrlsStartArg(self
):
131 self
.RaiseWrongNumberOfArgumentsException()
132 if self
.args
[0].lower() == 'set':
138 """Sets CORS configuration on a Google Cloud Storage bucket."""
139 cors_arg
= self
.args
[0]
140 url_args
= self
.args
[1:]
141 # Disallow multi-provider 'cors set' requests.
142 if not UrlsAreForSingleProvider(url_args
):
143 raise CommandException('"%s" command spanning providers not allowed.' %
146 # Open, read and parse file containing JSON document.
147 cors_file
= open(cors_arg
, 'r')
148 cors_txt
= cors_file
.read()
151 self
.api
= self
.gsutil_api
.GetApiSelector(
152 StorageUrlFromString(url_args
[0]).scheme
)
154 # Iterate over URLs, expanding wildcards and setting the CORS on each.
156 for url_str
in url_args
:
157 bucket_iter
= self
.GetBucketUrlIterFromArg(url_str
, bucket_fields
=['id'])
158 for blr
in bucket_iter
:
159 url
= blr
.storage_url
161 self
.logger
.info('Setting CORS on %s...', blr
)
162 if url
.scheme
== 's3':
163 self
.gsutil_api
.XmlPassThroughSetCors(
164 cors_txt
, url
, provider
=url
.scheme
)
166 cors
= CorsTranslation
.JsonCorsToMessageEntries(cors_txt
)
168 cors
= REMOVE_CORS_CONFIG
169 bucket_metadata
= apitools_messages
.Bucket(cors
=cors
)
170 self
.gsutil_api
.PatchBucket(url
.bucket_name
, bucket_metadata
,
171 provider
=url
.scheme
, fields
=['id'])
173 raise CommandException('No URLs matched')
177 """Gets CORS configuration for a Google Cloud Storage bucket."""
178 bucket_url
, bucket_metadata
= self
.GetSingleBucketUrlFromArg(
179 self
.args
[0], bucket_fields
=['cors'])
181 if bucket_url
.scheme
== 's3':
182 sys
.stdout
.write(self
.gsutil_api
.XmlPassThroughGetCors(
183 bucket_url
, provider
=bucket_url
.scheme
))
185 if bucket_metadata
.cors
:
187 CorsTranslation
.MessageEntriesToJson(bucket_metadata
.cors
))
189 sys
.stdout
.write('%s has no CORS configuration.\n' % bucket_url
)
192 def RunCommand(self
):
193 """Command entry point for the cors command."""
194 action_subcommand
= self
.args
.pop(0)
195 if action_subcommand
== 'get':
197 elif action_subcommand
== 'set':
200 raise CommandException(('Invalid subcommand "%s" for the %s command.\n'
201 'See "gsutil help cors".') %
202 (action_subcommand
, self
.command_name
))