Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(348)

Side by Side Diff: gslib/commands/cors.py

Issue 698893003: Update checked in version of gsutil to version 4.6 (Closed) Base URL: http://dart.googlecode.com/svn/third_party/gsutil/
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « gslib/commands/config.py ('k') | gslib/commands/cp.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # -*- coding: utf-8 -*-
1 # Copyright 2012 Google Inc. All Rights Reserved. 2 # Copyright 2012 Google Inc. All Rights Reserved.
2 # 3 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License. 5 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at 6 # You may obtain a copy of the License at
6 # 7 #
7 # http://www.apache.org/licenses/LICENSE-2.0 8 # http://www.apache.org/licenses/LICENSE-2.0
8 # 9 #
9 # Unless required by applicable law or agreed to in writing, software 10 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and 13 # See the License for the specific language governing permissions and
13 # limitations under the License. 14 # limitations under the License.
15 """Implementation of cors configuration command for GCS buckets."""
16
17 from __future__ import absolute_import
14 18
15 import sys 19 import sys
16 import xml
17 20
18 from boto import handler
19 from boto.gs.cors import Cors
20 from gslib.command import Command 21 from gslib.command import Command
21 from gslib.command import COMMAND_NAME 22 from gslib.cs_api_map import ApiSelector
22 from gslib.command import COMMAND_NAME_ALIASES
23 from gslib.command import FILE_URIS_OK
24 from gslib.command import MAX_ARGS
25 from gslib.command import MIN_ARGS
26 from gslib.command import PROVIDER_URIS_OK
27 from gslib.command import SUPPORTED_SUB_ARGS
28 from gslib.command import URIS_START_ARG
29 from gslib.exception import CommandException 23 from gslib.exception import CommandException
30 from gslib.help_provider import CreateHelpText 24 from gslib.help_provider import CreateHelpText
31 from gslib.help_provider import HELP_NAME 25 from gslib.storage_url import StorageUrlFromString
32 from gslib.help_provider import HELP_NAME_ALIASES 26 from gslib.third_party.storage_apitools import storage_v1_messages as apitools_m essages
33 from gslib.help_provider import HELP_ONE_LINE_SUMMARY 27 from gslib.translation_helper import CorsTranslation
34 from gslib.help_provider import HELP_TEXT 28 from gslib.translation_helper import REMOVE_CORS_CONFIG
35 from gslib.help_provider import HelpType
36 from gslib.help_provider import HELP_TYPE
37 from gslib.help_provider import SUBCOMMAND_HELP_TEXT
38 from gslib.util import NO_MAX 29 from gslib.util import NO_MAX
30 from gslib.util import UrlsAreForSingleProvider
31
39 32
40 _GET_SYNOPSIS = """ 33 _GET_SYNOPSIS = """
41 gsutil cors get uri 34 gsutil cors get url
42 """ 35 """
43 36
44 _SET_SYNOPSIS = """ 37 _SET_SYNOPSIS = """
45 gsutil cors set cors-xml-file uri... 38 gsutil cors set cors-json-file url...
46 """ 39 """
47 40
48 _GET_DESCRIPTION = """ 41 _GET_DESCRIPTION = """
49 <B>GET</B> 42 <B>GET</B>
50 Gets the CORS configuration for a single bucket. The output from 43 Gets the CORS configuration for a single bucket. The output from
51 "cors get" can be redirected into a file, edited and then updated using 44 "cors get" can be redirected into a file, edited and then updated using
52 "cors set". 45 "cors set".
53 """ 46 """
54 47
55 _SET_DESCRIPTION = """ 48 _SET_DESCRIPTION = """
56 <B>SET</B> 49 <B>SET</B>
57 Sets the CORS configuration for one or more buckets. The 50 Sets the CORS configuration for one or more buckets. The
58 cors-xml-file specified on the command line should be a path to a local 51 cors-json-file specified on the command line should be a path to a local
59 file containing an XML document as described above. 52 file containing a JSON document as described above.
60 """ 53 """
61 54
62 _SYNOPSIS = _SET_SYNOPSIS + _GET_SYNOPSIS.lstrip('\n') + '\n\n' 55 _SYNOPSIS = _SET_SYNOPSIS + _GET_SYNOPSIS.lstrip('\n') + '\n\n'
63 56
64 _DESCRIPTION = (""" 57 _DESCRIPTION = ("""
65 Gets or sets the Cross-Origin Resource Sharing (CORS) configuration on one or 58 Gets or sets the Cross-Origin Resource Sharing (CORS) configuration on one or
66 more buckets. This command is supported for buckets only, not objects. A CORS 59 more buckets. This command is supported for buckets only, not objects. An
67 XML document should have the following structure: 60 example CORS JSON document looks like the folllowing:
68 61
69 <?xml version="1.0" ?> 62 [
70 <CorsConfig> 63 {
71 <Cors> 64 "origin": ["http://origin1.example.com"],
72 <Origins> 65 "responseHeader": ["Content-Type"],
73 <Origin>http://origin1.example.com</Origin> 66 "method": ["GET"],
74 </Origins> 67 "maxAgeSeconds": 3600
75 <Methods> 68 }
76 <Method>GET</Method> 69 ]
77 </Methods>
78 <ResponseHeaders>
79 <ResponseHeader>Content-Type</ResponseHeader>
80 </ResponseHeaders>
81 </Cors>
82 </CorsConfig>
83 70
84 The above XML document explicitly allows cross-origin GET requests from 71 The above JSON document explicitly allows cross-origin GET requests from
85 `http://origin1.example.com` and may include the Content-Type response header. 72 http://origin1.example.com and may include the Content-Type response header.
73 The preflight request may be cached for 1 hour.
74
75 The following (empty) CORS JSON document removes all CORS configuration for
76 a bucket:
77
78 []
86 79
87 The cors command has two sub-commands: 80 The cors command has two sub-commands:
88 """ + '\n'.join([_GET_DESCRIPTION, _SET_DESCRIPTION]) + """ 81 """ + '\n'.join([_GET_DESCRIPTION, _SET_DESCRIPTION]) + """
89 For more info about CORS, see http://www.w3.org/TR/cors/. 82 For more info about CORS, see http://www.w3.org/TR/cors/.
90 """) 83 """)
91 84
92 _detailed_help_text = CreateHelpText(_SYNOPSIS, _DESCRIPTION) 85 _DETAILED_HELP_TEXT = CreateHelpText(_SYNOPSIS, _DESCRIPTION)
93 86
94 _get_help_text = CreateHelpText(_GET_SYNOPSIS, _GET_DESCRIPTION) 87 _get_help_text = CreateHelpText(_GET_SYNOPSIS, _GET_DESCRIPTION)
95 _set_help_text = CreateHelpText(_SET_SYNOPSIS, _SET_DESCRIPTION) 88 _set_help_text = CreateHelpText(_SET_SYNOPSIS, _SET_DESCRIPTION)
96 89
90
97 class CorsCommand(Command): 91 class CorsCommand(Command):
98 """Implementation of gsutil cors command.""" 92 """Implementation of gsutil cors command."""
99 93
100 # Command specification (processed by parent class). 94 # Command specification. See base class for documentation.
101 command_spec = { 95 command_spec = Command.CreateCommandSpec(
102 # Name of command. 96 'cors',
103 COMMAND_NAME : 'cors', 97 command_name_aliases=['getcors', 'setcors'],
104 # List of command name aliases. 98 min_args=2,
105 COMMAND_NAME_ALIASES : ['getcors', 'setcors'], 99 max_args=NO_MAX,
106 # Min number of args required by this command. 100 supported_sub_args='',
107 MIN_ARGS : 2, 101 file_url_ok=False,
108 # Max number of args required by this command, or NO_MAX. 102 provider_url_ok=False,
109 MAX_ARGS : NO_MAX, 103 urls_start_arg=1,
110 # Getopt-style string specifying acceptable sub args. 104 gs_api_support=[ApiSelector.XML, ApiSelector.JSON],
111 SUPPORTED_SUB_ARGS : '', 105 gs_default_api=ApiSelector.JSON,
112 # True if file URIs acceptable for this command. 106 )
113 FILE_URIS_OK : False, 107 # Help specification. See help_provider.py for documentation.
114 # True if provider-only URIs acceptable for this command. 108 help_spec = Command.HelpSpec(
115 PROVIDER_URIS_OK : False, 109 help_name='cors',
116 # Index in args of first URI arg. 110 help_name_aliases=['getcors', 'setcors', 'cross-origin'],
117 URIS_START_ARG : 1, 111 help_type='command_help',
118 } 112 help_one_line_summary=(
119 help_spec = { 113 'Set a CORS JSON document for one or more buckets'),
120 # Name of command or auxiliary help info for which this help applies. 114 help_text=_DETAILED_HELP_TEXT,
121 HELP_NAME : 'cors', 115 subcommand_help_text={'get': _get_help_text, 'set': _set_help_text},
122 # List of help name aliases. 116 )
123 HELP_NAME_ALIASES : ['getcors', 'setcors', 'cross-origin'],
124 # Type of help)
125 HELP_TYPE : HelpType.COMMAND_HELP,
126 # One line summary of this help.
127 HELP_ONE_LINE_SUMMARY : 'Set a CORS XML document for one or more buckets',
128 # The full help text.
129 HELP_TEXT : _detailed_help_text,
130 # Help text for sub-commands.
131 SUBCOMMAND_HELP_TEXT : {'get' : _get_help_text,
132 'set' : _set_help_text},
133 }
134 117
135 def _CalculateUrisStartArg(self): 118 def _CalculateUrlsStartArg(self):
136 if not self.args: 119 if not self.args:
137 self._RaiseWrongNumberOfArgumentsException() 120 self._RaiseWrongNumberOfArgumentsException()
138 if (self.args[0].lower() == 'set'): 121 if self.args[0].lower() == 'set':
139 return 2 122 return 2
140 else: 123 else:
141 return 1 124 return 1
142 125
143 def _SetCors(self): 126 def _SetCors(self):
127 """Sets CORS configuration on a Google Cloud Storage bucket."""
144 cors_arg = self.args[0] 128 cors_arg = self.args[0]
145 uri_args = self.args[1:] 129 url_args = self.args[1:]
146 # Disallow multi-provider 'cors set' requests. 130 # Disallow multi-provider 'cors set' requests.
147 storage_uri = self.UrisAreForSingleProvider(uri_args) 131 if not UrlsAreForSingleProvider(url_args):
148 if not storage_uri:
149 raise CommandException('"%s" command spanning providers not allowed.' % 132 raise CommandException('"%s" command spanning providers not allowed.' %
150 self.command_name) 133 self.command_name)
151 134
152 # Open, read and parse file containing XML document. 135 # Open, read and parse file containing JSON document.
153 cors_file = open(cors_arg, 'r') 136 cors_file = open(cors_arg, 'r')
154 cors_txt = cors_file.read() 137 cors_txt = cors_file.read()
155 cors_file.close() 138 cors_file.close()
156 cors_obj = Cors()
157 139
158 # Parse XML document and convert into Cors object. 140 self.api = self.gsutil_api.GetApiSelector(
159 h = handler.XmlHandler(cors_obj, None) 141 StorageUrlFromString(url_args[0]).scheme)
160 try:
161 xml.sax.parseString(cors_txt, h)
162 except xml.sax._exceptions.SAXParseException, e:
163 raise CommandException('Requested CORS is invalid: %s at line %s, '
164 'column %s' % (e.getMessage(), e.getLineNumber(),
165 e.getColumnNumber()))
166 142
167 # Iterate over URIs, expanding wildcards, and setting the CORS on each. 143 cors = CorsTranslation.JsonCorsToMessageEntries(cors_txt)
144 if not cors:
145 cors = REMOVE_CORS_CONFIG
146
147 # Iterate over URLs, expanding wildcards and setting the CORS on each.
168 some_matched = False 148 some_matched = False
169 for uri_str in uri_args: 149 for url_str in url_args:
170 for blr in self.WildcardIterator(uri_str): 150 bucket_iter = self.GetBucketUrlIterFromArg(url_str, bucket_fields=['id'])
171 uri = blr.GetUri() 151 for blr in bucket_iter:
172 if not uri.names_bucket(): 152 url = blr.storage_url
173 raise CommandException('URI %s must name a bucket for the %s command'
174 % (str(uri), self.command_name))
175 some_matched = True 153 some_matched = True
176 self.logger.info('Setting CORS on %s...', uri) 154 self.logger.info('Setting CORS on %s...', blr)
177 uri.set_cors(cors_obj, False, self.headers) 155 if url.scheme == 's3':
156 self.gsutil_api.XmlPassThroughSetCors(
157 cors_txt, url, provider=url.scheme)
158 else:
159 bucket_metadata = apitools_messages.Bucket(cors=cors)
160 self.gsutil_api.PatchBucket(url.bucket_name, bucket_metadata,
161 provider=url.scheme, fields=['id'])
178 if not some_matched: 162 if not some_matched:
179 raise CommandException('No URIs matched') 163 raise CommandException('No URLs matched')
164 return 0
180 165
181 def _GetCors(self): 166 def _GetCors(self):
182 # Wildcarding is allowed but must resolve to just one bucket. 167 """Gets CORS configuration for a Google Cloud Storage bucket."""
183 uris = list(self.WildcardIterator(self.args[0]).IterUris()) 168 bucket_url, bucket_metadata = self.GetSingleBucketUrlFromArg(
184 if len(uris) == 0: 169 self.args[0], bucket_fields=['cors'])
185 raise CommandException('No URIs matched')
186 if len(uris) != 1:
187 raise CommandException('%s matched more than one URI, which is not\n'
188 'allowed by the %s command' % (self.args[0], self.command_name))
189 uri = uris[0]
190 if not uri.names_bucket():
191 raise CommandException('"%s" command must specify a bucket' %
192 self.command_name)
193 cors = uri.get_cors(False, self.headers)
194 # Pretty-print the XML to make it more easily human editable.
195 parsed_xml = xml.dom.minidom.parseString(cors.to_xml().encode('utf-8'))
196 sys.stdout.write(parsed_xml.toprettyxml(indent=' '))
197 170
198 # Command entry point. 171 if bucket_url.scheme == 's3':
172 sys.stdout.write(self.gsutil_api.XmlPassThroughGetCors(
173 bucket_url, provider=bucket_url.scheme))
174 else:
175 if bucket_metadata.cors:
176 sys.stdout.write(
177 CorsTranslation.MessageEntriesToJson(bucket_metadata.cors))
178 else:
179 sys.stdout.write('%s has no CORS configuration.\n' % bucket_url)
180 return 0
181
199 def RunCommand(self): 182 def RunCommand(self):
183 """Command entry point for the cors command."""
200 action_subcommand = self.args.pop(0) 184 action_subcommand = self.args.pop(0)
201 self.CheckArguments()
202 if action_subcommand == 'get': 185 if action_subcommand == 'get':
203 func = self._GetCors 186 func = self._GetCors
204 elif action_subcommand == 'set': 187 elif action_subcommand == 'set':
205 func = self._SetCors 188 func = self._SetCors
206 else: 189 else:
207 raise CommandException(('Invalid subcommand "%s" for the %s command.\n' 190 raise CommandException(('Invalid subcommand "%s" for the %s command.\n'
208 'See "gsutil help cors".') % 191 'See "gsutil help cors".') %
209 (action_subcommand, self.command_name)) 192 (action_subcommand, self.command_name))
210 func() 193 return func()
211 return 0
OLDNEW
« no previous file with comments | « gslib/commands/config.py ('k') | gslib/commands/cp.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698