Example #1
0
    def POST(self, env, start_response):
        """
        Handle POST Bucket (Delete/Upload Multiple Objects) request
        """
        if 'QUERY_STRING' in env:
            args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1))
        else:
            args = {}

        if 'delete2' in args:
            return self._delete_multiple_objects(env)

        if 'uploads' in args:
            # Pass it through, the s3multi upload helper will handle it.
            return self.app(env, start_response)

        if 'uploadId' in args:
            # Pass it through, the s3multi upload helper will handle it.
            return self.app(env, start_response)

        if 'delete' in args:
            bodye = self.xmlbody2elem(env['wsgi.input'].read())
            keys = bodye.xpath('/Delete/Object')
            res = etree.Element('DeleteResult')
            for key in keys:
                path = '/v1/AUTH_%s/%s/%s' % (quote(
                    self.account_name), quote(
                        self.container_name), quote(key.xpath('Key')[0].text))
                if key.xpath('VersionId'):
                    vid = key.xpath('VersionId')[0].text
                    path = path + '?versionId=' + vid
                env = copyenv(env, method='DELETE', path=path, query_string='')
                body_iter = self._app_call(env)
                status = self._get_status_int()
                if is_success(status):
                    delete = etree.Element('Deleted')
                    delete.append(
                        self.create_elem('Key',
                                         key.xpath('Key')[0].text))
                    res.append(delete)
                else:
                    err = etree.Element('Error')
                    err.append(
                        self.create_elem('Key',
                                         key.xpath('Key')[0].text))
                    res.append(err)

            return Response(status=HTTP_OK, body=self.elem2xmlbody(res))

        return self.get_err_response('Unsupported')
Example #2
0
    def POST(self, env, start_response):
        """
        Handle POST Bucket (Delete/Upload Multiple Objects) request
        """
        if "QUERY_STRING" in env:
            args = dict(urlparse.parse_qsl(env["QUERY_STRING"], 1))
        else:
            args = {}

        if "delete2" in args:
            return self._delete_multiple_objects(env)

        if "uploads" in args:
            # Pass it through, the s3multi upload helper will handle it.
            return self.app(env, start_response)

        if "uploadId" in args:
            # Pass it through, the s3multi upload helper will handle it.
            return self.app(env, start_response)

        if "delete" in args:
            bodye = self.xmlbody2elem(env["wsgi.input"].read())
            keys = bodye.xpath("/Delete/Object")
            res = etree.Element("DeleteResult")
            for key in keys:
                path = "/v1/AUTH_%s/%s/%s" % (
                    quote(self.account_name),
                    quote(self.container_name),
                    quote(key.xpath("Key")[0].text),
                )
                if key.xpath("VersionId"):
                    vid = key.xpath("VersionId")[0].text
                    path = path + "?versionId=" + vid
                env = copyenv(env, method="DELETE", path=path, query_string="")
                body_iter = self._app_call(env)
                status = self._get_status_int()
                if is_success(status):
                    delete = etree.Element("Deleted")
                    delete.append(self.create_elem("Key", key.xpath("Key")[0].text))
                    res.append(delete)
                else:
                    err = etree.Element("Error")
                    err.append(self.create_elem("Key", key.xpath("Key")[0].text))
                    res.append(err)

            return Response(status=HTTP_OK, body=self.elem2xmlbody(res))

        return self.get_err_response("Unsupported")
Example #3
0
    def PUT(self, env, start_response):
        """
        Handle PUT Bucket request
        """
        # checking params available
        AMZ_ACL = set([
            'HTTP_X_AMZ_GRANT_READ', 'HTTP_X_AMZ_GRANT_WRITE',
            'HTTP_X_AMZ_GRANT_READ_ACP', 'HTTP_X_AMZ_GRANT_WRITE_ACP',
            'HTTP_X_AMZ_GRANT_FULL_CONTROL'
        ])
        qs = env.get('QUERY_STRING', '')
        args = urlparse.parse_qs(qs, 1)
        if not args:
            if not self.validate_bucket_name(self.container_name):
                return self.get_err_response('InvalidBucketName')

            if not self.is_unique(self.container_name):
                return self.get_err_response('BucketAlreadyExists')

            # to create a new one
            if 'HTTP_X_AMZ_ACL' in env:
                amz_acl = env['HTTP_X_AMZ_ACL']
                translated_acl = self.swift_acl_translate(canned=amz_acl)
                for header, value in translated_acl:
                    env[header] = value
            elif AMZ_ACL & set(env.keys()):
                acld = dict()
                if 'HTTP_X_AMZ_GRANT_READ' in env.keys():
                    acld['read'] = self.keyvalue2dict(
                        env['HTTP_X_AMZ_GRANT_READ'])
                if 'HTTP_X_AMZ_GRANT_WRITE' in env.keys():
                    acld['write'] = self.keyvalue2dict(
                        env['HTTP_X_AMZ_GRANT_WRITE'])
                if 'HTTP_X_AMZ_GRANT_FULL_CONTROL' in env.keys():
                    acld['full'] = self.keyvalue2dict(
                        env['HTTP_X_AMZ_GRANT_FULL_CONTROL'])
                translated_acl = self.swift_acl_translate(acl=acld)
                for header, value in translated_acl:
                    env[header] = value

            # modify env put to swift
            body_iter = self._app_call(env)
            status = self._get_status_int()

            if status != HTTP_CREATED:
                if status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                elif status == HTTP_ACCEPTED:
                    return self.get_err_response('BucketAlreadyExists')
                else:
                    return self.get_err_response('InvalidURI')

            resp = Response()
            resp.headers['Location'] = self.container_name
            resp.status = HTTP_OK
            return resp

        if len(args) > 1:
            return self.get_err_response('InvalidURI')

        # now args only 1
        action = args.keys().pop()
        if action == 'acl':
            # put acl
            acl = env['wsgi.input'].read()
            env['REQUEST_METHOD'] = 'POST'
            env['QUERY_STRING'] = ''
            env['HTTP_X_CONTAINER_META_ACL'] = quote(acl)
            body_iter = self._app_call(env)
            status = self._get_status_int()
            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response('AccessDenied')
            else:
                return self.get_err_response('InvalidURI')
        elif action == 'cors':
            # put cors
            bodye = self.xmlbody2elem(env['wsgi.input'].read())
            env['HTTP_X_CONTAINER_META_ACCESS_CONTROL_ALLOW_ORIGIN'] = ','.join(
                [
                    i.text for i in bodye.xpath(
                        '/CORSConfiguration/CORSRule/AllowedOrigin')
                ])
            env['HTTP_X_CONTAINER_META_ACCESS_CONTROL_MAX_AGE'] = ','.join([
                i.text for i in bodye.xpath(
                    '/CORSConfiguration/CORSRule/MaxAgeSeconds')
            ])
            env['HTTP_X_CONTAINER_META_ACCESS_CONTROL_EXPOSE_HEADERS'] = ','.join(
                [
                    i.text for i in bodye.xpath(
                        '/CORSConfiguration/CORSRule/ExposeHeader')
                ])
            env['HTTP_X_CONTAINER_META_ACCESS_CONTROL_ALLOW_METHOD'] = ','.join(
                i.text for i in bodye.xpath(
                    '/CORSConfiguration/CORSRule/AllowedMethod'))
            env['QUERY_STRING'] = ''
            env['REQUEST_METHOD'] = 'POST'

            body_iter = self._app_call(env)
            status = self._get_status_int()

            if is_success(status):
                resp = Response()
                resp.headers['Location'] = self.container_name
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response('AccessDenied')
            else:
                return self.get_err_response('InvalidURI')

        elif action == 'lifecycle':
            # put lifecycle
            container_info = get_container_info(env, self.app)
            if container_info['versions']:
                return self.get_err_response('AccessDenied')

            bodye = self.xmlbody2elem(env['wsgi.input'].read())

            tat = bodye.xpath('/LifecycleConfiguration/Rule/Transition/Date')
            env['HTTP_X_CONTAINER_META_TRANS_AT'] = tat[0].text if tat else ''
            tafter = bodye.xpath(
                '/LifecycleConfiguration/Rule/Transition/Days')
            env['HTTP_X_CONTAINER_META_TRANS_AFTER'] = tafter[
                0].text if tafter else ''
            trans = bodye.xpath(
                '/LifecycleConfiguration/Rule/Transition/StorageClass')
            env['HTTP_X_CONTAINER_META_TRANS_CLASS'] = trans[
                0].text if trans else ''

            at = bodye.xpath('/LifecycleConfiguration/Rule/Expiration/Date')
            env['HTTP_X_CONTAINER_META_EXPIRATION_AT'] = at[
                0].text if at else ''
            after = bodye.xpath('/LifecycleConfiguration/Rule/Expiration/Days')
            env['HTTP_X_CONTAINER_META_EXPIRATION_AFTER'] = after[
                0].text if after else ''
            prefix = bodye.xpath('/LifecycleConfiguration/Rule/Prefix')
            env['HTTP_X_CONTAINER_META_EXPIRATION_PREFIX'] = prefix[
                0].text if prefix else ''
            stat = bodye.xpath('/LifecycleConfiguration/Rule/Status')
            env['HTTP_X_CONTAINER_META_EXPIRATION_STATUS'] = stat[
                0].text if stat else ''

            env['REQUEST_METHOD'] = 'POST'
            env['QUERY_STRING'] = ''
            body_iter = self._app_call(env)
            status = self._get_status_int()
            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response('AccessDenied')
            else:
                return self.get_err_response('InvalidURI')
        elif action == 'policy':
            # put policy
            json = env['wsgi.input'].read()
            env['REQUEST_METHOD'] = 'POST'
            env['QUERY_STRING'] = ''
            env['HTTP_X_CONTAINER_META_POLICY'] = quote(json)
            body_iter = self._app_call(env)
            status = self._get_status_int()
            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response('AccessDenied')
            else:
                return self.get_err_response('InvalidURI')
        elif action == 'logging':
            # put logging
            env['REQUEST_METHOD'] = 'POST'
            env['QUERY_STRING'] = ''
            bodye = self.xmlbody2elem(env['wsgi.input'].read())
            target = bodye.xpath(
                '/BucketLoggingStatus/LoggingEnabled/TargetBucket')
            if target:
                env['HTTP_X_CONTAINER_META_LOGGING_TARGET'] = target[0].text
                prefix = bodye.xpath(
                    '/BucketLoggingStatus/LoggingEnabled/TargetPrefix')
                if prefix:
                    env['HTTP_X_CONTAINER_META_LOGGING_PREFIX'] = prefix[
                        0].text
            else:
                env['HTTP_X_CONTAINER_META_LOGGING_TARGET'] = ''
                env['HTTP_X_CONTAINER_META_LOGGING_PREFIX'] = ''

            body_iter = self._app_call(env)
            status = self._get_status_int()
            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response('AccessDenied')
            else:
                return self.get_err_response('InvalidURI')
        elif action == 'notification':
            # put it
            bodye = self.xmlbody2elem(env['wsgi.input'].read())
            topic = bodye.xpath(
                '/NotificationConfiguration/TopicConfiguration/Topic')
            event = bodye.xpath(
                '/NotificationConfiguration/TopicConfiguration/Event')
            if not topic or not event:
                return self.get_err_response('InvalidArgument')

            env['REQUEST_METHOD'] = 'POST'
            env['QUERY_STRING'] = ''

            env['HTTP_CONTAINER_META_NOTI_TOPIC'] = topic[0].text
            env['HTTP_CONTAINER_META_NOTI_EVENT'] = event[0].text

            env['HTTP_X_CONTAINER_META_NOTI'] = quote(body)

            body_iter = self._app_call(env)
            status = self._get_status_int()

            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response('AccessDenied')
            else:
                return self.get_err_response('InvalidURI')
        elif action == 'tagging':
            # put tagging
            bodye = self.xmlbody2elem(env['wsgi.input'].read())
            for tag in bodye.xpath('/Tagging/TagSet/Tag'):
                key = tag.xpath('Key')[0].text
                value = tag.xpath('Key')[0].text + tag.xpath('Value')[0].text
                env['HTTP_X_CONTAINER_META_TAG_%s' % key.upper()] = value
            env['REQUEST_METHOD'] = 'POST'
            env['QUERY_STRING'] = ''
            body_iter = self._app_call(env)
            status = self._get_status_int()
            if is_success(status):
                resp = Response()
                resp.status = HTTP_NO_CONTENT
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response('AccessDenied')
            else:
                return self.get_err_response('InvalidURI')

        elif action == 'requestPayment':
            # put it
            bodye = self.xmlbody2elem(env['wsgi.input'].read())
            target = bodye.xpath('/RequestPaymentConfiguration/Payer')

            if not target or target[0].text not in ('BucketOwner',
                                                    'Requester'):
                return self.get_err_response('InvalidArgument')

            env['REQUEST_METHOD'] = 'POST'
            env['QUERY_STRING'] = ''

            env['HTTP_X_CONTAINER_META_PAYMENT'] = quote(body)

            body_iter = self._app_call(env)
            status = self._get_status_int()

            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response('AccessDenied')
            else:
                return self.get_err_response('InvalidURI')

        elif action == 'versioning':
            bodye = self.xmlbody2elem(env['wsgi.input'].read())
            status = bodye.xpath('/VersioningConfiguration/Status')
            if status:
                status = status[0].text

            env['REQUEST_METHOD'] = 'POST'
            env['HTTP_X_VERSIONS_LOCATION'] = self.version_name(
                self.container_name) if status == 'Enabled' else ''
            env['QUERY_STRING'] = ''
            body_iter = self._app_call(env)
            status = self._get_status_int()

            path = '/v1/AUTH_%s/%s' % (self.account_name,
                                       self.version_name(self.container_name))
            env2 = copyenv(env, method='PUT', path=path, query_string='')
            body_iter2 = self._app_call(env2)
            status2 = self._get_status_int()
            if is_success(status) and is_success(status2):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response('AccessDenied')
            else:
                return self.get_err_response('InvalidURI')
        elif action == 'website':
            # put website
            body = env['wsgi.input'].read()

            env['REQUEST_METHOD'] = 'POST'
            env['QUERY_STRING'] = ''

            env['HTTP_X_CONTAINER_META_WEBSITE'] = quote(body)

            body_iter = self._app_call(env)
            status = self._get_status_int()

            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response('AccessDenied')
            else:
                return self.get_err_response('InvalidURI')
        else:
            return self.get_err_response('InvalidURI')
Example #4
0
    def GET(self, env, start_response):
        """
        Handle GET Bucket (List Objects) request
        """
        qs = env.get('QUERY_STRING', '')
        args = urlparse.parse_qs(qs, 1)

        key_args = set([
            'cors', 'lifecycle', 'policy', 'logging', 'notification',
            'tagging', 'requestPayment', 'versioning', 'versions', 'website',
            'location'
        ])

        if not key_args & set(args):
            # GET bucket to list objects
            max_keys = self.MAX_BUCKET_LISTING
            if 'max-keys' in args:
                if args.get('max-keys')[0].isdigit() is False:
                    return self.get_err_response('InvalidArgument')
                max_keys = min(int(args.get('max-keys')[0]),
                               self.MAX_BUCKET_LISTING)

            if 'acl' not in args:
                #acl request sent with format=json etc confuses swift
                env['QUERY_STRING'] = 'format=json&limit=%s' % (max_keys + 1)
            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)
            if env['REQUEST_METHOD'] == 'HEAD':
                body_iter = ''
            status = self._get_status_int()
            headers = dict(self._response_headers)

            if is_success(status) and 'acl' in args:
                return self.get_acl(self.account_name, headers)

            if 'versioning' in args:
                # Just report there is no versioning configured here.
                body = ('<VersioningConfiguration '
                        'xmlns="http://s3.amazonaws.com/doc/2006-03-01/"/>')
                return Response(body=body, content_type="text/plain")

            if status != HTTP_OK:
                if status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                elif status == HTTP_NOT_FOUND:
                    return self.get_err_response('NoSuchBucket')
                else:
                    return self.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 '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)))
            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([
                     '<Contents><Key>%s</Key><LastModified>%sZ</LastModif'
                     'ied><ETag>%s</ETag><Size>%s</Size><StorageClass>STA'
                     'NDARD</StorageClass><Owner><ID>%s</ID><DisplayName>'
                     '%s</DisplayName></Owner></Contents>' %
                     (xml_escape(unquote(
                         i['name'])), i['last_modified'], i['hash'],
                      i['bytes'], self.account_name, self.account_name)
                     for i in objects[:max_keys] if 'subdir' not in i
                 ]), "".join([
                     '<CommonPrefixes><Prefix>%s</Prefix></CommonPrefixes>' %
                     xml_escape(i['subdir'])
                     for i in objects[:max_keys] if 'subdir' in i
                 ])))
            return Response(body=body, content_type='application/xml')
        else:
            # GET specified data
            #env['REQUEST_METHOD'] = 'HEAD'
            body_iter = self._app_call(env)
            status = self._get_status_int()
            headers = dict(self._response_headers)

            action = args.keys().pop()
            if action == 'acl':
                # get acl
                # get policy
                acl = headers.get('X-Container-Meta-Policy') or ''

                if is_success(status):
                    if acl:
                        return Response(status=HTTP_OK,
                                        content_type='application/xml',
                                        body=unquote(acl))
                    else:
                        return self.get_err_response('NotSuchPolicy')

                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                else:
                    return self.get_err_response('InvalidURI')
            elif action == 'cors':
                # get cors
                _headers = set([
                    'X-Container-Meta-Access-Control-Expose-Headers',
                    'X-Container-Meta-Access-Control-Allow-Origin',
                    'X-Container-Meta-Access-Control-Max-Age',
                    'X-Container-Meta-Access-Control-Allow-Method'
                ])
                bodye = etree.Element('CORSConfiguration')
                if _headers & set(headers):
                    rule = etree.Element('CORSRule')
                    if 'X-Container-Meta-Access-Control-Expose-Headers' in headers:
                        valuel = headers[
                            'X-Container-Meta-Access-Control-Expose-Headers'].split(
                                ',')
                        for i in valuel:
                            eh = self.create_elem('ExposeHeader', i)
                            rule.append(eh)
                    if 'X-Container-Meta-Access-Control-Allow-Origin' in headers:
                        valuel = headers[
                            'X-Container-Meta-Access-Control-Allow-Origin'].split(
                                ',')
                        for i in valuel:
                            ao = self.create_elem('AllowedOrigin', i)
                            rule.append(ao)
                    if 'X-Container-Meta-Access-Control-Max-Age' in headers:
                        valuel = headers[
                            'X-Container-Meta-Access-Control-Max-Age'].split(
                                ',')
                        for i in valuel:
                            ma = self.create_elem('MaxAgeSeconds', i)
                            rule.append(ma)
                    if 'X-Container-Meta-Access-Control-Allow-Method' in headers:
                        valuel = headers[
                            'X-Container-Meta-Access-Control-Allow-Method'].split(
                                ',')
                        for i in valuel:
                            al = self.create_elem('AllowedMethod', i)
                            rule.append(al)
                    rule.append(self.create_elem('ID', 'unique_rule'))
                    bodye.append(rule)
                else:
                    bodye.text = ''

                if is_success(status):
                    return Response(status=HTTP_OK,
                                    content_type='application/xml',
                                    body=self.elem2xmlbody(bodye))
                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                else:
                    return self.get_err_response('InvalidURI')

            elif action == 'lifecycle':
                # get lifecycle
                bodye = etree.Element('LifecycleConfiguration')
                if 'X-Container-Meta-Expiration-Status' in headers:
                    rule = etree.Element('Rule')
                    rule.append(
                        self.create_elem(
                            'Status',
                            headers['X-Container-Meta-Expiration-Status']))
                    rule.append(self.create_elem('ID', 'unique_rule'))
                    if 'X-Container-Meta-Expiration-Prefix' in headers:
                        rule.append(
                            self.create_elem(
                                'Prefix',
                                headers['X-Container-Meta-Expiration-Prefix']))
                    if 'X-Container-Meta-Expiration-At' in headers or \
                       'X-Container-Meta-Expiration-After' in headers:
                        expir = etree.Element('Expiration')
                        if 'X-Container-Meta-Expiration-At' in headers:
                            expir.append(
                                self.create_elem(
                                    'Date',
                                    headers['X-Container-Meta-Expiration-At']))
                        if 'X-Container-Meta-Expiration-After' in headers:
                            expir.append(
                                self.create_elem(
                                    'Days', headers[
                                        'X-Container-Meta-Expiration-After']))
                        rule.append(expir)
                    if 'X-Container-Meta-Trans-Class' in headers:
                        trans = etree.Element('Transition')
                        cls = self.create_elem(
                            'StorageClass',
                            headers['X-Container-Meta-Trans-Class'])
                        trans.append(cls)
                        if 'X-Container-Meta-Trans-At' in headers:
                            trans.append(
                                self.create_elem(
                                    'Date',
                                    headers['X-Container-Meta-Trans-At']))
                        if 'X-Container-Meta-Trans-After' in headers:
                            trans.append(
                                self.create_elem(
                                    'Days',
                                    headers['X-Container-Meta-Trans-After']))
                        rule.append(trans)
                    bodye.append(rule)
                else:
                    bodye.text = ''

                if is_success(status):
                    return Response(status=HTTP_OK,
                                    content_type='application/xml',
                                    body=self.elem2xmlbody(bodye))
                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                else:
                    return self.get_err_response('InvalidURI')

            elif action == 'policy':
                # get policy
                json = headers.get('X-Container-Meta-Policy') or ''

                if is_success(status):
                    if json:
                        return Response(status=HTTP_OK,
                                        content_type='application/json',
                                        body=unquote(json))
                    else:
                        return self.get_err_response('NotSuchPolicy')

                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                else:
                    return self.get_err_response('InvalidURI')
            elif action == 'logging':
                # get logging
                target = headers.get('X-Container-Meta-Logging-Target') or ''
                prefix = headers.get('X-Container-Meta-Logging-Prefix') or ''
                statuse = etree.Element('BucketLoggingStatus')
                if target:
                    enabled = etree.Element('LoggingEnabled')
                    target_bucket = self.create_elem('TargetBucket', target)
                    if prefix:
                        target_prefix = self.create_elem(
                            'TargetPrefix', prefix)
                    enabled.append(target_bucket)
                    enabled.append(target_prefix)
                    statuse.append(enabled)
                else:
                    pass  # set text None

                if is_success(status):
                    return Response(status=HTTP_OK,
                                    content_type='application/xml',
                                    body=self.elem2xmlbody(statuse))
                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                else:
                    return self.get_err_response('InvalidURI')
            elif action == 'notification':
                # get it
                topic = headers.get('X-Container-Meta-Noti-Topic')
                event = headers.get('X-Container-Meta-Noti-Event')
                if is_success(status):
                    if topic:
                        body = (
                            '<WebsiteConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">'
                            '<NotificationConfiguration> '
                            '<TopicConfiguration>'
                            '<Topic>%s</Topic>'
                            '<Event>%s</Event>'
                            '</TopicConfiguration>'
                            '</NotificationConfiguration>', topic, event)
                        return Response(status=HTTP_OK,
                                        content_type='application/xml',
                                        body=body)
                    else:
                        return self.get_err_response('NotSuchWebsite')

                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                else:
                    return self.get_err_response('InvalidURI')
            elif action == 'tagging':
                # get tagging
                Tagging = etree.Element('Tagging')
                TagSet = etree.Element('TagSet')
                meta_keys = [
                    header[21:] for header in headers
                    if header.startswith('X-Container-Meta-Tag-')
                ]
                for key in meta_keys:
                    Tag = etree.Element('Tag')
                    keyvalues = headers['X-Container-Meta-Tag-' + key]
                    _key = keyvalues[:len(key)]
                    _value = keyvalues[len(key):]
                    Tag.append(self.create_elem('Key', _key))
                    Tag.append(self.create_elem('Value', _value))
                    TagSet.append(Tag)
                Tagging.append(TagSet)
                if is_success(status):
                    return Response(status=HTTP_OK,
                                    content_type='application/xml',
                                    body=self.elem2xmlbody(Tagging))
                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                else:
                    return self.get_err_response('InvalidURI')

            elif action == 'requestPayment':
                # get it
                # default value is BucketOwner
                pay = headers.get('X-Container-Meta-Payment', 'BucketOwner')
                if is_success(status):
                    if pay:
                        return Response(status=HTTP_OK,
                                        content_type='application/xml',
                                        body=unquote(pay))
                    else:
                        return self.get_err_response('NotSuchWebsite')

                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                else:
                    return self.get_err_response('InvalidURI')

            elif action == 'versioning':
                versioning = 'Enabled' if 'X-Versions-Location' in headers else 'Suspended'
                bodye = etree.Element('VersioningConfiguration')
                stat = self.create_elem('Status', versioning)
                bodye.append(stat)
                if is_success(status):
                    return Response(status=HTTP_OK,
                                    content_type='application/xml',
                                    body=self.elem2xmlbody(bodye))
                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                else:
                    return self.get_err_response('InvalidURI')
            elif action == 'website':
                # get website
                website = headers.get('X-Container-Meta-Website')
                fake = (
                    '<WebsiteConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">'
                    '<IndexDocument>'
                    '<Suffix>index.html</Suffix>'
                    '</IndexDocument>'
                    '<ErrorDocument>'
                    '<Key>SomeErrorDocument.html</Key>'
                    '</ErrorDocument>'
                    '</WebsiteConfiguration>')

                if is_success(status):
                    if website:
                        # return fake data
                        return Response(status=HTTP_OK,
                                        content_type='application/xml',
                                        body=fake)
                    else:
                        return self.get_err_response('NotSuchWebsite')

                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                else:
                    return self.get_err_response('InvalidURI')
            elif action == 'location':
                bodye = self.create_elem('LocationConstraint', 'CN')
                return Response(status=HTTP_OK,
                                content_type='application/xml',
                                body=self.elem2xmlbody(bodye))
            elif action == 'versions':
                # get versions container
                path = '/v1/AUTH_%s/%s' % (self.account_name,
                                           self.container_name)
                env = copyenv(env, method='GET', path=path, query_string='')
                body_iter = self._app_call(env)
                status = self._get_status_int()

                # get origin container
                path = '/v1/AUTH_%s/%s' % (
                    quote(self.account_name),
                    quote(self.version_name(self.container_name)))
                env2 = copyenv(env, method='GET', path=path, query_string='')
                body_iter2 = self._app_call(env2)
                status2 = self._get_status_int()

                last = list(body_iter)
                history = list(body_iter2)
                res = etree.Element('ListVersionsResult')
                bucket = self.create_elem('Name', self.container_name)
                res.append(bucket)
                if last:
                    last = [i for i in last[0].split('\n') if i]
                    for i in last:
                        ver = etree.Element('Version')
                        ver.append(self.create_elem('Key', i))
                        ver.append(self.create_elem('VersionId', 'lastest'))
                        ver.append(self.create_elem('IsLastest', 'true'))
                        res.append(ver)

                if history:
                    history = [i for i in history[0].split('\n') if i]
                    for i in history:
                        ver = etree.Element('Version')
                        ver.append(self.create_elem('Key',
                                                    i.split('/')[0][3:]))
                        ver.append(
                            self.create_elem('VersionId',
                                             i.split('/')[1]))
                        ver.append(self.create_elem('IsLastest', 'false'))
                        res.append(ver)

                if is_success(status) and is_success(status2):
                    return Response(status=HTTP_OK,
                                    content_type='application/xml',
                                    body=self.elem2xmlbody(res))
                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response('AccessDenied')
                else:
                    return self.get_err_response('InvalidURI')
            else:
                return self.get_err_response('InvalidURI')
Example #5
0
    def GET(self, env, start_response):
        """
        Handle GET Bucket (List Objects) request
        """
        qs = env.get("QUERY_STRING", "")
        args = urlparse.parse_qs(qs, 1)

        key_args = set(
            [
                "cors",
                "lifecycle",
                "policy",
                "logging",
                "notification",
                "tagging",
                "requestPayment",
                "versioning",
                "versions",
                "website",
                "location",
            ]
        )

        if not key_args & set(args):
            # GET bucket to list objects
            max_keys = self.MAX_BUCKET_LISTING
            if "max-keys" in args:
                if args.get("max-keys")[0].isdigit() is False:
                    return self.get_err_response("InvalidArgument")
                max_keys = min(int(args.get("max-keys")[0]), self.MAX_BUCKET_LISTING)

            if "acl" not in args:
                # acl request sent with format=json etc confuses swift
                env["QUERY_STRING"] = "format=json&limit=%s" % (max_keys + 1)
            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)
            if env["REQUEST_METHOD"] == "HEAD":
                body_iter = ""
            status = self._get_status_int()
            headers = dict(self._response_headers)

            if is_success(status) and "acl" in args:
                return self.get_acl(self.account_name, headers)

            if "versioning" in args:
                # Just report there is no versioning configured here.
                body = "<VersioningConfiguration " 'xmlns="http://s3.amazonaws.com/doc/2006-03-01/"/>'
                return Response(body=body, content_type="text/plain")

            if status != HTTP_OK:
                if status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                elif status == HTTP_NOT_FOUND:
                    return self.get_err_response("NoSuchBucket")
                else:
                    return self.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 "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)))
            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(
                        [
                            "<Contents><Key>%s</Key><LastModified>%sZ</LastModif"
                            "ied><ETag>%s</ETag><Size>%s</Size><StorageClass>STA"
                            "NDARD</StorageClass><Owner><ID>%s</ID><DisplayName>"
                            "%s</DisplayName></Owner></Contents>"
                            % (
                                xml_escape(unquote(i["name"])),
                                i["last_modified"],
                                i["hash"],
                                i["bytes"],
                                self.account_name,
                                self.account_name,
                            )
                            for i in objects[:max_keys]
                            if "subdir" not in i
                        ]
                    ),
                    "".join(
                        [
                            "<CommonPrefixes><Prefix>%s</Prefix></CommonPrefixes>" % xml_escape(i["subdir"])
                            for i in objects[:max_keys]
                            if "subdir" in i
                        ]
                    ),
                )
            )
            return Response(body=body, content_type="application/xml")
        else:
            # GET specified data
            # env['REQUEST_METHOD'] = 'HEAD'
            body_iter = self._app_call(env)
            status = self._get_status_int()
            headers = dict(self._response_headers)

            action = args.keys().pop()
            if action == "acl":
                # get acl
                # get policy
                acl = headers.get("X-Container-Meta-Policy") or ""

                if is_success(status):
                    if acl:
                        return Response(status=HTTP_OK, content_type="application/xml", body=unquote(acl))
                    else:
                        return self.get_err_response("NotSuchPolicy")

                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                else:
                    return self.get_err_response("InvalidURI")
            elif action == "cors":
                # get cors
                _headers = set(
                    [
                        "X-Container-Meta-Access-Control-Expose-Headers",
                        "X-Container-Meta-Access-Control-Allow-Origin",
                        "X-Container-Meta-Access-Control-Max-Age",
                        "X-Container-Meta-Access-Control-Allow-Method",
                    ]
                )
                bodye = etree.Element("CORSConfiguration")
                if _headers & set(headers):
                    rule = etree.Element("CORSRule")
                    if "X-Container-Meta-Access-Control-Expose-Headers" in headers:
                        valuel = headers["X-Container-Meta-Access-Control-Expose-Headers"].split(",")
                        for i in valuel:
                            eh = self.create_elem("ExposeHeader", i)
                            rule.append(eh)
                    if "X-Container-Meta-Access-Control-Allow-Origin" in headers:
                        valuel = headers["X-Container-Meta-Access-Control-Allow-Origin"].split(",")
                        for i in valuel:
                            ao = self.create_elem("AllowedOrigin", i)
                            rule.append(ao)
                    if "X-Container-Meta-Access-Control-Max-Age" in headers:
                        valuel = headers["X-Container-Meta-Access-Control-Max-Age"].split(",")
                        for i in valuel:
                            ma = self.create_elem("MaxAgeSeconds", i)
                            rule.append(ma)
                    if "X-Container-Meta-Access-Control-Allow-Method" in headers:
                        valuel = headers["X-Container-Meta-Access-Control-Allow-Method"].split(",")
                        for i in valuel:
                            al = self.create_elem("AllowedMethod", i)
                            rule.append(al)
                    rule.append(self.create_elem("ID", "unique_rule"))
                    bodye.append(rule)
                else:
                    bodye.text = ""

                if is_success(status):
                    return Response(status=HTTP_OK, content_type="application/xml", body=self.elem2xmlbody(bodye))
                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                else:
                    return self.get_err_response("InvalidURI")

            elif action == "lifecycle":
                # get lifecycle
                bodye = etree.Element("LifecycleConfiguration")
                if "X-Container-Meta-Expiration-Status" in headers:
                    rule = etree.Element("Rule")
                    rule.append(self.create_elem("Status", headers["X-Container-Meta-Expiration-Status"]))
                    rule.append(self.create_elem("ID", "unique_rule"))
                    if "X-Container-Meta-Expiration-Prefix" in headers:
                        rule.append(self.create_elem("Prefix", headers["X-Container-Meta-Expiration-Prefix"]))
                    if "X-Container-Meta-Expiration-At" in headers or "X-Container-Meta-Expiration-After" in headers:
                        expir = etree.Element("Expiration")
                        if "X-Container-Meta-Expiration-At" in headers:
                            expir.append(self.create_elem("Date", headers["X-Container-Meta-Expiration-At"]))
                        if "X-Container-Meta-Expiration-After" in headers:
                            expir.append(self.create_elem("Days", headers["X-Container-Meta-Expiration-After"]))
                        rule.append(expir)
                    if "X-Container-Meta-Trans-Class" in headers:
                        trans = etree.Element("Transition")
                        cls = self.create_elem("StorageClass", headers["X-Container-Meta-Trans-Class"])
                        trans.append(cls)
                        if "X-Container-Meta-Trans-At" in headers:
                            trans.append(self.create_elem("Date", headers["X-Container-Meta-Trans-At"]))
                        if "X-Container-Meta-Trans-After" in headers:
                            trans.append(self.create_elem("Days", headers["X-Container-Meta-Trans-After"]))
                        rule.append(trans)
                    bodye.append(rule)
                else:
                    bodye.text = ""

                if is_success(status):
                    return Response(status=HTTP_OK, content_type="application/xml", body=self.elem2xmlbody(bodye))
                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                else:
                    return self.get_err_response("InvalidURI")

            elif action == "policy":
                # get policy
                json = headers.get("X-Container-Meta-Policy") or ""

                if is_success(status):
                    if json:
                        return Response(status=HTTP_OK, content_type="application/json", body=unquote(json))
                    else:
                        return self.get_err_response("NotSuchPolicy")

                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                else:
                    return self.get_err_response("InvalidURI")
            elif action == "logging":
                # get logging
                target = headers.get("X-Container-Meta-Logging-Target") or ""
                prefix = headers.get("X-Container-Meta-Logging-Prefix") or ""
                statuse = etree.Element("BucketLoggingStatus")
                if target:
                    enabled = etree.Element("LoggingEnabled")
                    target_bucket = self.create_elem("TargetBucket", target)
                    if prefix:
                        target_prefix = self.create_elem("TargetPrefix", prefix)
                    enabled.append(target_bucket)
                    enabled.append(target_prefix)
                    statuse.append(enabled)
                else:
                    pass  # set text None

                if is_success(status):
                    return Response(status=HTTP_OK, content_type="application/xml", body=self.elem2xmlbody(statuse))
                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                else:
                    return self.get_err_response("InvalidURI")
            elif action == "notification":
                # get it
                topic = headers.get("X-Container-Meta-Noti-Topic")
                event = headers.get("X-Container-Meta-Noti-Event")
                if is_success(status):
                    if topic:
                        body = (
                            '<WebsiteConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">'
                            "<NotificationConfiguration> "
                            "<TopicConfiguration>"
                            "<Topic>%s</Topic>"
                            "<Event>%s</Event>"
                            "</TopicConfiguration>"
                            "</NotificationConfiguration>",
                            topic,
                            event,
                        )
                        return Response(status=HTTP_OK, content_type="application/xml", body=body)
                    else:
                        return self.get_err_response("NotSuchWebsite")

                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                else:
                    return self.get_err_response("InvalidURI")
            elif action == "tagging":
                # get tagging
                Tagging = etree.Element("Tagging")
                TagSet = etree.Element("TagSet")
                meta_keys = [header[21:] for header in headers if header.startswith("X-Container-Meta-Tag-")]
                for key in meta_keys:
                    Tag = etree.Element("Tag")
                    keyvalues = headers["X-Container-Meta-Tag-" + key]
                    _key = keyvalues[: len(key)]
                    _value = keyvalues[len(key) :]
                    Tag.append(self.create_elem("Key", _key))
                    Tag.append(self.create_elem("Value", _value))
                    TagSet.append(Tag)
                Tagging.append(TagSet)
                if is_success(status):
                    return Response(status=HTTP_OK, content_type="application/xml", body=self.elem2xmlbody(Tagging))
                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                else:
                    return self.get_err_response("InvalidURI")

            elif action == "requestPayment":
                # get it
                # default value is BucketOwner
                pay = headers.get("X-Container-Meta-Payment", "BucketOwner")
                if is_success(status):
                    if pay:
                        return Response(status=HTTP_OK, content_type="application/xml", body=unquote(pay))
                    else:
                        return self.get_err_response("NotSuchWebsite")

                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                else:
                    return self.get_err_response("InvalidURI")

            elif action == "versioning":
                versioning = "Enabled" if "X-Versions-Location" in headers else "Suspended"
                bodye = etree.Element("VersioningConfiguration")
                stat = self.create_elem("Status", versioning)
                bodye.append(stat)
                if is_success(status):
                    return Response(status=HTTP_OK, content_type="application/xml", body=self.elem2xmlbody(bodye))
                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                else:
                    return self.get_err_response("InvalidURI")
            elif action == "website":
                # get website
                website = headers.get("X-Container-Meta-Website")
                fake = (
                    '<WebsiteConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">'
                    "<IndexDocument>"
                    "<Suffix>index.html</Suffix>"
                    "</IndexDocument>"
                    "<ErrorDocument>"
                    "<Key>SomeErrorDocument.html</Key>"
                    "</ErrorDocument>"
                    "</WebsiteConfiguration>"
                )

                if is_success(status):
                    if website:
                        # return fake data
                        return Response(status=HTTP_OK, content_type="application/xml", body=fake)
                    else:
                        return self.get_err_response("NotSuchWebsite")

                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                else:
                    return self.get_err_response("InvalidURI")
            elif action == "location":
                bodye = self.create_elem("LocationConstraint", "CN")
                return Response(status=HTTP_OK, content_type="application/xml", body=self.elem2xmlbody(bodye))
            elif action == "versions":
                # get versions container
                path = "/v1/AUTH_%s/%s" % (self.account_name, self.container_name)
                env = copyenv(env, method="GET", path=path, query_string="")
                body_iter = self._app_call(env)
                status = self._get_status_int()

                # get origin container
                path = "/v1/AUTH_%s/%s" % (quote(self.account_name), quote(self.version_name(self.container_name)))
                env2 = copyenv(env, method="GET", path=path, query_string="")
                body_iter2 = self._app_call(env2)
                status2 = self._get_status_int()

                last = list(body_iter)
                history = list(body_iter2)
                res = etree.Element("ListVersionsResult")
                bucket = self.create_elem("Name", self.container_name)
                res.append(bucket)
                if last:
                    last = [i for i in last[0].split("\n") if i]
                    for i in last:
                        ver = etree.Element("Version")
                        ver.append(self.create_elem("Key", i))
                        ver.append(self.create_elem("VersionId", "lastest"))
                        ver.append(self.create_elem("IsLastest", "true"))
                        res.append(ver)

                if history:
                    history = [i for i in history[0].split("\n") if i]
                    for i in history:
                        ver = etree.Element("Version")
                        ver.append(self.create_elem("Key", i.split("/")[0][3:]))
                        ver.append(self.create_elem("VersionId", i.split("/")[1]))
                        ver.append(self.create_elem("IsLastest", "false"))
                        res.append(ver)

                if is_success(status) and is_success(status2):
                    return Response(status=HTTP_OK, content_type="application/xml", body=self.elem2xmlbody(res))
                elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                else:
                    return self.get_err_response("InvalidURI")
            else:
                return self.get_err_response("InvalidURI")
Example #6
0
    def PUT(self, env, start_response):
        """
        Handle PUT Bucket request
        """
        # checking params available
        AMZ_ACL = set(
            [
                "HTTP_X_AMZ_GRANT_READ",
                "HTTP_X_AMZ_GRANT_WRITE",
                "HTTP_X_AMZ_GRANT_READ_ACP",
                "HTTP_X_AMZ_GRANT_WRITE_ACP",
                "HTTP_X_AMZ_GRANT_FULL_CONTROL",
            ]
        )
        qs = env.get("QUERY_STRING", "")
        args = urlparse.parse_qs(qs, 1)
        if not args:
            if not self.validate_bucket_name(self.container_name):
                return self.get_err_response("InvalidBucketName")

            if not self.is_unique(self.container_name):
                return self.get_err_response("BucketAlreadyExists")

            # to create a new one
            if "HTTP_X_AMZ_ACL" in env:
                amz_acl = env["HTTP_X_AMZ_ACL"]
                translated_acl = self.swift_acl_translate(canned=amz_acl)
                for header, value in translated_acl:
                    env[header] = value
            elif AMZ_ACL & set(env.keys()):
                acld = dict()
                if "HTTP_X_AMZ_GRANT_READ" in env.keys():
                    acld["read"] = self.keyvalue2dict(env["HTTP_X_AMZ_GRANT_READ"])
                if "HTTP_X_AMZ_GRANT_WRITE" in env.keys():
                    acld["write"] = self.keyvalue2dict(env["HTTP_X_AMZ_GRANT_WRITE"])
                if "HTTP_X_AMZ_GRANT_FULL_CONTROL" in env.keys():
                    acld["full"] = self.keyvalue2dict(env["HTTP_X_AMZ_GRANT_FULL_CONTROL"])
                translated_acl = self.swift_acl_translate(acl=acld)
                for header, value in translated_acl:
                    env[header] = value

            # modify env put to swift
            body_iter = self._app_call(env)
            status = self._get_status_int()

            if status != HTTP_CREATED:
                if status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                    return self.get_err_response("AccessDenied")
                elif status == HTTP_ACCEPTED:
                    return self.get_err_response("BucketAlreadyExists")
                else:
                    return self.get_err_response("InvalidURI")

            resp = Response()
            resp.headers["Location"] = self.container_name
            resp.status = HTTP_OK
            return resp

        if len(args) > 1:
            return self.get_err_response("InvalidURI")

        # now args only 1
        action = args.keys().pop()
        if action == "acl":
            # put acl
            acl = env["wsgi.input"].read()
            env["REQUEST_METHOD"] = "POST"
            env["QUERY_STRING"] = ""
            env["HTTP_X_CONTAINER_META_ACL"] = quote(acl)
            body_iter = self._app_call(env)
            status = self._get_status_int()
            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response("AccessDenied")
            else:
                return self.get_err_response("InvalidURI")
        elif action == "cors":
            # put cors
            bodye = self.xmlbody2elem(env["wsgi.input"].read())
            env["HTTP_X_CONTAINER_META_ACCESS_CONTROL_ALLOW_ORIGIN"] = ",".join(
                [i.text for i in bodye.xpath("/CORSConfiguration/CORSRule/AllowedOrigin")]
            )
            env["HTTP_X_CONTAINER_META_ACCESS_CONTROL_MAX_AGE"] = ",".join(
                [i.text for i in bodye.xpath("/CORSConfiguration/CORSRule/MaxAgeSeconds")]
            )
            env["HTTP_X_CONTAINER_META_ACCESS_CONTROL_EXPOSE_HEADERS"] = ",".join(
                [i.text for i in bodye.xpath("/CORSConfiguration/CORSRule/ExposeHeader")]
            )
            env["HTTP_X_CONTAINER_META_ACCESS_CONTROL_ALLOW_METHOD"] = ",".join(
                i.text for i in bodye.xpath("/CORSConfiguration/CORSRule/AllowedMethod")
            )
            env["QUERY_STRING"] = ""
            env["REQUEST_METHOD"] = "POST"

            body_iter = self._app_call(env)
            status = self._get_status_int()

            if is_success(status):
                resp = Response()
                resp.headers["Location"] = self.container_name
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response("AccessDenied")
            else:
                return self.get_err_response("InvalidURI")

        elif action == "lifecycle":
            # put lifecycle
            container_info = get_container_info(env, self.app)
            if container_info["versions"]:
                return self.get_err_response("AccessDenied")

            bodye = self.xmlbody2elem(env["wsgi.input"].read())

            tat = bodye.xpath("/LifecycleConfiguration/Rule/Transition/Date")
            env["HTTP_X_CONTAINER_META_TRANS_AT"] = tat[0].text if tat else ""
            tafter = bodye.xpath("/LifecycleConfiguration/Rule/Transition/Days")
            env["HTTP_X_CONTAINER_META_TRANS_AFTER"] = tafter[0].text if tafter else ""
            trans = bodye.xpath("/LifecycleConfiguration/Rule/Transition/StorageClass")
            env["HTTP_X_CONTAINER_META_TRANS_CLASS"] = trans[0].text if trans else ""

            at = bodye.xpath("/LifecycleConfiguration/Rule/Expiration/Date")
            env["HTTP_X_CONTAINER_META_EXPIRATION_AT"] = at[0].text if at else ""
            after = bodye.xpath("/LifecycleConfiguration/Rule/Expiration/Days")
            env["HTTP_X_CONTAINER_META_EXPIRATION_AFTER"] = after[0].text if after else ""
            prefix = bodye.xpath("/LifecycleConfiguration/Rule/Prefix")
            env["HTTP_X_CONTAINER_META_EXPIRATION_PREFIX"] = prefix[0].text if prefix else ""
            stat = bodye.xpath("/LifecycleConfiguration/Rule/Status")
            env["HTTP_X_CONTAINER_META_EXPIRATION_STATUS"] = stat[0].text if stat else ""

            env["REQUEST_METHOD"] = "POST"
            env["QUERY_STRING"] = ""
            body_iter = self._app_call(env)
            status = self._get_status_int()
            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response("AccessDenied")
            else:
                return self.get_err_response("InvalidURI")
        elif action == "policy":
            # put policy
            json = env["wsgi.input"].read()
            env["REQUEST_METHOD"] = "POST"
            env["QUERY_STRING"] = ""
            env["HTTP_X_CONTAINER_META_POLICY"] = quote(json)
            body_iter = self._app_call(env)
            status = self._get_status_int()
            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response("AccessDenied")
            else:
                return self.get_err_response("InvalidURI")
        elif action == "logging":
            # put logging
            env["REQUEST_METHOD"] = "POST"
            env["QUERY_STRING"] = ""
            bodye = self.xmlbody2elem(env["wsgi.input"].read())
            target = bodye.xpath("/BucketLoggingStatus/LoggingEnabled/TargetBucket")
            if target:
                env["HTTP_X_CONTAINER_META_LOGGING_TARGET"] = target[0].text
                prefix = bodye.xpath("/BucketLoggingStatus/LoggingEnabled/TargetPrefix")
                if prefix:
                    env["HTTP_X_CONTAINER_META_LOGGING_PREFIX"] = prefix[0].text
            else:
                env["HTTP_X_CONTAINER_META_LOGGING_TARGET"] = ""
                env["HTTP_X_CONTAINER_META_LOGGING_PREFIX"] = ""

            body_iter = self._app_call(env)
            status = self._get_status_int()
            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response("AccessDenied")
            else:
                return self.get_err_response("InvalidURI")
        elif action == "notification":
            # put it
            bodye = self.xmlbody2elem(env["wsgi.input"].read())
            topic = bodye.xpath("/NotificationConfiguration/TopicConfiguration/Topic")
            event = bodye.xpath("/NotificationConfiguration/TopicConfiguration/Event")
            if not topic or not event:
                return self.get_err_response("InvalidArgument")

            env["REQUEST_METHOD"] = "POST"
            env["QUERY_STRING"] = ""

            env["HTTP_CONTAINER_META_NOTI_TOPIC"] = topic[0].text
            env["HTTP_CONTAINER_META_NOTI_EVENT"] = event[0].text

            env["HTTP_X_CONTAINER_META_NOTI"] = quote(body)

            body_iter = self._app_call(env)
            status = self._get_status_int()

            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response("AccessDenied")
            else:
                return self.get_err_response("InvalidURI")
        elif action == "tagging":
            # put tagging
            bodye = self.xmlbody2elem(env["wsgi.input"].read())
            for tag in bodye.xpath("/Tagging/TagSet/Tag"):
                key = tag.xpath("Key")[0].text
                value = tag.xpath("Key")[0].text + tag.xpath("Value")[0].text
                env["HTTP_X_CONTAINER_META_TAG_%s" % key.upper()] = value
            env["REQUEST_METHOD"] = "POST"
            env["QUERY_STRING"] = ""
            body_iter = self._app_call(env)
            status = self._get_status_int()
            if is_success(status):
                resp = Response()
                resp.status = HTTP_NO_CONTENT
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response("AccessDenied")
            else:
                return self.get_err_response("InvalidURI")

        elif action == "requestPayment":
            # put it
            bodye = self.xmlbody2elem(env["wsgi.input"].read())
            target = bodye.xpath("/RequestPaymentConfiguration/Payer")

            if not target or target[0].text not in ("BucketOwner", "Requester"):
                return self.get_err_response("InvalidArgument")

            env["REQUEST_METHOD"] = "POST"
            env["QUERY_STRING"] = ""

            env["HTTP_X_CONTAINER_META_PAYMENT"] = quote(body)

            body_iter = self._app_call(env)
            status = self._get_status_int()

            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response("AccessDenied")
            else:
                return self.get_err_response("InvalidURI")

        elif action == "versioning":
            bodye = self.xmlbody2elem(env["wsgi.input"].read())
            status = bodye.xpath("/VersioningConfiguration/Status")
            if status:
                status = status[0].text

            env["REQUEST_METHOD"] = "POST"
            env["HTTP_X_VERSIONS_LOCATION"] = self.version_name(self.container_name) if status == "Enabled" else ""
            env["QUERY_STRING"] = ""
            body_iter = self._app_call(env)
            status = self._get_status_int()

            path = "/v1/AUTH_%s/%s" % (self.account_name, self.version_name(self.container_name))
            env2 = copyenv(env, method="PUT", path=path, query_string="")
            body_iter2 = self._app_call(env2)
            status2 = self._get_status_int()
            if is_success(status) and is_success(status2):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response("AccessDenied")
            else:
                return self.get_err_response("InvalidURI")
        elif action == "website":
            # put website
            body = env["wsgi.input"].read()

            env["REQUEST_METHOD"] = "POST"
            env["QUERY_STRING"] = ""

            env["HTTP_X_CONTAINER_META_WEBSITE"] = quote(body)

            body_iter = self._app_call(env)
            status = self._get_status_int()

            if is_success(status):
                resp = Response()
                resp.status = HTTP_OK
                return resp
            elif status in (HTTP_UNAUTHORIZED, HTTP_FORBIDDEN):
                return self.get_err_response("AccessDenied")
            else:
                return self.get_err_response("InvalidURI")
        else:
            return self.get_err_response("InvalidURI")