def GETorHEAD(self, env, start_response): if env['REQUEST_METHOD'] == 'HEAD': head = True env['REQUEST_METHOD'] = 'GET' else: head = False if 'QUERY_STRING' in env: args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1)) else: args = {} # Let s3multi handle it. if 'uploadId' in args: return self.app(env, start_response) env['QUERY_STRING'] = '' if 'acl' in args: env['QUERY_STRING'] += 'acl' env['REQUEST_METHOD'] = 'HEAD' if 'versionId' in args: env['QUERY_STRING'] += 'versionId=%s' % args['versionId'] app_iter = self._app_call(env) if head: app_iter = None if 'acl' in args and not head: env['REQUEST_METHOD'] = 'GET' # recover HTTP method status = self._get_status_int() headers = dict(self._response_headers) if is_success(status): if 'QUERY_STRING' in env: args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1)) else: args = {} if 'acl' in args: resp = get_s3_acl(headers, obj_server.ACL_HEADERS, 'object') return resp new_hdrs = {} for key, val in headers.iteritems(): _key = key.lower() if _key.startswith('x-object-meta-'): new_hdrs['x-amz-meta-' + key[14:]] = val elif _key in ('content-length', 'content-type', 'content-range', 'content-encoding', 'etag', 'last-modified'): new_hdrs[key] = val return Response(status=status, headers=new_hdrs, app_iter=app_iter) elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN): return get_err_response('AccessDenied') elif status == HTTP_NOT_FOUND: return get_err_response('NoSuchKey') else: return get_err_response('InvalidURI')
def GET(self, env, start_response): """ Handle GET Bucket (List Objects) request """ if 'QUERY_STRING' in env: args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1)) else: args = {} if 'max-keys' in args: if args.get('max-keys').isdigit() is False: return get_err_response('InvalidArgument') max_keys = min(int(args.get('max-keys', MAX_BUCKET_LISTING)), MAX_BUCKET_LISTING) if 'acl' in args: env['REQUEST_METHOD'] = 'HEAD' else: # acl request sent with format=json etc confuses swift env['QUERY_STRING'] = 'format=json&limit=%s' % (max_keys + 1) if 'versions' in args: env['QUERY_STRING'] += '&versions' if 'marker' in args: env['QUERY_STRING'] += '&marker=%s' % quote(args['marker']) if 'prefix' in args: env['QUERY_STRING'] += '&prefix=%s' % quote(args['prefix']) if 'delimiter' in args: env['QUERY_STRING'] += '&delimiter=%s' % quote(args['delimiter']) body_iter = self._app_call(env) status = self._get_status_int() headers = dict(self._response_headers) if 'acl' in args: env['REQUEST_METHOD'] = 'GET' # recover HTTP method if is_success(status) and 'acl' in args: return get_s3_acl(headers, container_server.ACL_HEADERS, 'container') if status != HTTP_OK: if status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN): return get_err_response('AccessDenied') elif status == HTTP_NOT_FOUND: return get_err_response('NoSuchBucket') else: return get_err_response('InvalidURI') if 'location' in args: body = ('<?xml version="1.0" encoding="UTF-8"?>' '<LocationConstraint ' 'xmlns="http://s3.amazonaws.com/doc/2006-03-01/"') if self.location == 'US': body += '/>' else: body += ('>%s</LocationConstraint>' % self.location) return Response(body=body, content_type='application/xml') if 'versioning' in args: vers = self._response_header_value('x-container-versioning') or '' body = ( '<VersioningConfiguration ' 'xmlns="http://s3.amazonaws.com/doc/2006-03-01/">' '<Status>%s</Status></VersioningConfiguration>' % vers.capitalize()) return Response(body=body, content_type='application/xml') if 'logging' in args: # logging disabled body = ('<?xml version="1.0" encoding="UTF-8"?>' '<BucketLoggingStatus ' 'xmlns="http://doc.s3.amazonaws.com/2006-03-01" />') return Response(body=body, content_type='application/xml') objects = loads(''.join(list(body_iter))) if 'versions' in args: obj_list = [] for obj in objects: if 'subdir' not in obj: if obj['deleted']: name = xml_escape(unquote(obj['name'].encode('utf-8'))) obj_list.append( '<DeleteMarker>' '<Key>%s</Key>' '<VersionId>%s</VersionId>' '<IsLatest>%s</IsLatest>' '<LastModified>%s</LastModified>' '</DeleteMarker>' % ( name, obj['version_id'], 'true' if obj['is_latest'] else 'false', obj['last_modified'])) else: name = xml_escape(unquote(obj['name'].encode('utf-8'))) obj_list.append( '<Version>' '<Key>%s</Key>' '<VersionId>%s</VersionId>' '<IsLatest>%s</IsLatest>' '<LastModified>%s</LastModified>' '<ETag>"%s"</ETag>' '<Size>%s</Size>' '<StorageClass>STANDARD</StorageClass>' '<Owner>' '<ID>%s</ID>' '<DisplayName>%s</DisplayName>' '</Owner>' '</Version>' % ( name, obj['version_id'], 'true' if obj['is_latest'] else 'false', obj['last_modified'], obj['hash'], obj['bytes'], obj['owner'], obj['owner'])) body = ('<?xml version="1.0" encoding="UTF-8"?>' '<ListVersionsResult ' 'xmlns="http://s3.amazonaws.com/doc/2006-03-01">' '<Prefix>%s</Prefix>' '<KeyMarker>%s</KeyMarker>' '<VersionIdMarker>%s</VersionIdMarker>' '<Delimiter>%s</Delimiter>' '<IsTruncated>%s</IsTruncated>' '<MaxKeys>%s</MaxKeys>' '<Name>%s</Name>' '%s' '%s' '</ListVersionsResult>' % ( xml_escape(args.get('prefix', '')), xml_escape(args.get('key-marker', '')), xml_escape(args.get('version-id-marker', '')), xml_escape(args.get('delimiter', '')), 'true' if len(objects) == (max_keys + 1) else 'false', max_keys, xml_escape(self.container_name), "".join(obj_list), "".join([ '<CommonPrefixes><Prefix>%s</Prefix></CommonPrefixes>' % xml_escape(i['subdir']) for i in objects[:max_keys] if 'subdir' in i]))) else: obj_list = [] prefixes = [] for i in objects: if 'subdir' in i: name = xml_escape(unquote(i['subdir'].encode('utf-8'))) prefixes.append('<CommonPrefixes>' '<Prefix>%s</Prefix>' '</CommonPrefixes>' % name) else: name = xml_escape(unquote(i['name'].encode('utf-8'))) owner = i.get('owner', self.account_name) obj_list.append( '<Contents>' '<Key>%s</Key>' '<LastModified>%sZ</LastModified>' '<ETag>%s</ETag>' '<Size>%s</Size>' '<StorageClass>STANDARD</StorageClass>' '<Owner>' '<ID>%s</ID>' '<DisplayName>%s</DisplayName>' '</Owner>' '</Contents>' % (name, i['last_modified'], i['hash'], i['bytes'], owner, owner)) body = ('<?xml version="1.0" encoding="UTF-8"?>' '<ListBucketResult ' 'xmlns="http://s3.amazonaws.com/doc/2006-03-01">' '<Prefix>%s</Prefix>' '<Marker>%s</Marker>' '<Delimiter>%s</Delimiter>' '<IsTruncated>%s</IsTruncated>' '<MaxKeys>%s</MaxKeys>' '<Name>%s</Name>' '%s' '%s' '</ListBucketResult>' % ( xml_escape(args.get('prefix', '')), xml_escape(args.get('marker', '')), xml_escape(args.get('delimiter', '')), 'true' if (max_keys > 0 and len(objects) == (max_keys + 1)) else 'false', max_keys, xml_escape(self.container_name), ''.join(obj_list), ''.join(prefixes))) return Response(body=body, content_type='application/xml')