Пример #1
0
    def __call__(self, req):
        extract_type = req.params.get('extract-archive')
        resp = None
        if extract_type is not None and req.method == 'PUT':
            archive_type = {
                'tar': '',
                'tar.gz': 'gz',
                'tar.bz2': 'bz2'
            }.get(extract_type.lower().strip('.'))
            if archive_type is not None:
                resp = HTTPOk(request=req)
                try:
                    out_content_type = req.accept.best_match(
                        ACCEPTABLE_FORMATS)
                except ValueError:
                    out_content_type = None  # Ignore invalid header
                if out_content_type:
                    resp.content_type = out_content_type
                resp.app_iter = self.handle_extract_iter(
                    req, archive_type, out_content_type=out_content_type)
            else:
                resp = HTTPBadRequest("Unsupported archive format")
        if 'bulk-delete' in req.params and req.method in ['POST', 'DELETE']:
            resp = HTTPOk(request=req)
            try:
                out_content_type = req.accept.best_match(ACCEPTABLE_FORMATS)
            except ValueError:
                out_content_type = None  # Ignore invalid header
            if out_content_type:
                resp.content_type = out_content_type
            resp.app_iter = self.handle_delete_iter(
                req, out_content_type=out_content_type)

        return resp or self.app
Пример #2
0
    def __call__(self, req):
        extract_type = req.params.get('extract-archive')
        resp = None
        if extract_type is not None and req.method == 'PUT':
            archive_type = {
                'tar': '', 'tar.gz': 'gz',
                'tar.bz2': 'bz2'}.get(extract_type.lower().strip('.'))
            if archive_type is not None:
                resp = HTTPOk(request=req)
                out_content_type = req.accept.best_match(ACCEPTABLE_FORMATS)
                if out_content_type:
                    resp.content_type = out_content_type
                resp.app_iter = self.handle_extract_iter(
                    req, archive_type, out_content_type=out_content_type)
            else:
                resp = HTTPBadRequest("Unsupported archive format")
        if 'bulk-delete' in req.params and req.method in ['POST', 'DELETE']:
            resp = HTTPOk(request=req)
            out_content_type = req.accept.best_match(ACCEPTABLE_FORMATS)
            if out_content_type:
                resp.content_type = out_content_type
            resp.app_iter = self.handle_delete_iter(
                req, out_content_type=out_content_type)

        return resp or self.app
Пример #3
0
def account_listing_response(account, req, response_content_type, broker=None,
                             limit='', marker='', end_marker='', prefix='',
                             delimiter='', reverse=False):
    if broker is None:
        broker = FakeAccountBroker()

    resp_headers = get_response_headers(broker)

    account_list = broker.list_containers_iter(limit, marker, end_marker,
                                               prefix, delimiter, reverse)
    data = []
    for (name, object_count, bytes_used, put_timestamp, is_subdir) \
            in account_list:
        name_ = name.decode('utf8') if six.PY2 else name
        if is_subdir:
            data.append({'subdir': name_})
        else:
            data.append(
                {'name': name_, 'count': object_count, 'bytes': bytes_used,
                 'last_modified': Timestamp(put_timestamp).isoformat})
    if response_content_type.endswith('/xml'):
        account_list = listing_formats.account_to_xml(data, account)
        ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    elif response_content_type.endswith('/json'):
        account_list = json.dumps(data).encode('ascii')
        ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    elif data:
        account_list = listing_formats.listing_to_text(data)
        ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    else:
        ret = HTTPNoContent(request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Пример #4
0
def account_listing_response(account, req, response_content_type,
                             info=None, listing=None, s3_buckets_only=False):
    now = time.time()
    if info is None:
        info = {'containers': 0,
                'objects': 0,
                'bytes': 0,
                'metadata': {},
                'ctime': Timestamp(now).internal}
    if listing is None:
        listing = []
    elif listing and len(listing[0]) < 5:
        # oio-sds < 4.2 does not return mtime
        listing = [x + [now] for x in listing]

    resp_headers = get_response_headers(info)

    if response_content_type == 'application/json':
        data = []
        for (name, object_count, bytes_used, is_subdir, mtime) in listing:
            if is_subdir:
                if not s3_buckets_only:
                    data.append({'subdir': name})
            else:
                data.append({'name': name, 'count': object_count,
                             'bytes': bytes_used,
                             'last_modified': Timestamp(mtime).isoformat})
        account_list = json.dumps(data)
    elif response_content_type.endswith('/xml'):
        output_list = ['<?xml version="1.0" encoding="UTF-8"?>',
                       '<account name=%s>' % saxutils.quoteattr(account)]
        for (name, object_count, bytes_used, is_subdir, mtime) in listing:
            if is_subdir:
                if not s3_buckets_only:
                    output_list.append(
                        '<subdir name=%s />' % saxutils.quoteattr(name))
            else:
                item = '<container><name>%s</name><count>%s</count>' \
                       '<bytes>%s</bytes><last_modified>%s</last_modified>' \
                       '</container>' % \
                       (saxutils.escape(name), object_count, bytes_used,
                        Timestamp(mtime).isoformat)
                output_list.append(item)
        output_list.append('</account>')
        account_list = '\n'.join(output_list)
    else:
        if not listing:
            resp = HTTPNoContent(request=req, headers=resp_headers)
            resp.content_type = response_content_type
            resp.charset = 'utf-8'
            return resp
        account_list = '\n'.join(r[0] for r in listing) + '\n'
    ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Пример #5
0
def account_listing_response(account,
                             req,
                             response_content_type,
                             broker=None,
                             limit='',
                             marker='',
                             end_marker='',
                             prefix='',
                             delimiter='',
                             reverse=False):
    if broker is None:
        broker = FakeAccountBroker()

    resp_headers = get_response_headers(broker)

    account_list = broker.list_containers_iter(limit, marker, end_marker,
                                               prefix, delimiter, reverse)
    if response_content_type == 'application/json':
        data = []
        for (name, object_count, bytes_used, is_subdir) in account_list:
            if is_subdir:
                data.append({'subdir': name})
            else:
                data.append({
                    'name': name,
                    'count': object_count,
                    'bytes': bytes_used
                })
        account_list = json.dumps(data)
    elif response_content_type.endswith('/xml'):
        output_list = [
            '<?xml version="1.0" encoding="UTF-8"?>',
            '<account name=%s>' % saxutils.quoteattr(account)
        ]
        for (name, object_count, bytes_used, is_subdir) in account_list:
            if is_subdir:
                output_list.append('<subdir name=%s />' %
                                   saxutils.quoteattr(name))
            else:
                item = '<container><name>%s</name><count>%s</count>' \
                       '<bytes>%s</bytes></container>' % \
                       (saxutils.escape(name), object_count, bytes_used)
                output_list.append(item)
        output_list.append('</account>')
        account_list = '\n'.join(output_list)
    else:
        if not account_list:
            resp = HTTPNoContent(request=req, headers=resp_headers)
            resp.content_type = response_content_type
            resp.charset = 'utf-8'
            return resp
        account_list = '\n'.join(r[0] for r in account_list) + '\n'
    ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Пример #6
0
def account_listing_response(account, req, response_content_type, broker=None,
                             limit='', marker='', end_marker='', prefix='',
                             delimiter='', reverse=False):
    """
    This is an exact copy of swift.account.utis.account_listing_response()
    except for one difference i.e this method passes response_content_type
    to broker.list_containers_iter() method.
    """
    if broker is None:
        broker = FakeAccountBroker()

    resp_headers = get_response_headers(broker)

    account_list = broker.list_containers_iter(limit, marker, end_marker,
                                               prefix, delimiter,
                                               response_content_type, reverse)
    if response_content_type == 'application/json':
        data = []
        for (name, object_count, bytes_used, put_tstamp,
             is_subdir) in account_list:
            if is_subdir:
                data.append({'subdir': name})
            else:
                data.append({'name': name, 'count': object_count,
                             'bytes': bytes_used,
                             'last_modified': Timestamp(put_tstamp).isoformat})
        account_list = json.dumps(data)
    elif response_content_type.endswith('/xml'):
        output_list = ['<?xml version="1.0" encoding="UTF-8"?>',
                       '<account name=%s>' % saxutils.quoteattr(account)]
        for (name, object_count, bytes_used, put_tstamp,
             is_subdir) in account_list:
            if is_subdir:
                output_list.append(
                    '<subdir name=%s />' % saxutils.quoteattr(name))
            else:
                item = '<container><name>%s</name><count>%s</count>' \
                       '<bytes>%s</bytes><last_modified>%s</last_modified> \
                        </container>' % \
                       (saxutils.escape(name), object_count, bytes_used,
                        Timestamp(put_tstamp).isoformat)
                output_list.append(item)
        output_list.append('</account>')
        account_list = '\n'.join(output_list)
    else:
        if not account_list:
            resp = HTTPNoContent(request=req, headers=resp_headers)
            resp.content_type = response_content_type
            resp.charset = 'utf-8'
            return resp
        account_list = '\n'.join(r[0] for r in account_list) + '\n'
    ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Пример #7
0
    def __call__(self, req):
        extract_type = req.params.get("extract-archive")
        resp = None
        if extract_type is not None and req.method == "PUT":
            archive_type = {"tar": "", "tar.gz": "gz", "tar.bz2": "bz2"}.get(extract_type.lower().strip("."))
            if archive_type is not None:
                resp = HTTPOk(request=req)
                out_content_type = req.accept.best_match(ACCEPTABLE_FORMATS)
                if out_content_type:
                    resp.content_type = out_content_type
                resp.app_iter = self.handle_extract_iter(req, archive_type, out_content_type=out_content_type)
            else:
                resp = HTTPBadRequest("Unsupported archive format")
        if "bulk-delete" in req.params and req.method == "DELETE":
            resp = HTTPOk(request=req)
            out_content_type = req.accept.best_match(ACCEPTABLE_FORMATS)
            if out_content_type:
                resp.content_type = out_content_type
            resp.app_iter = self.handle_delete_iter(req, out_content_type=out_content_type)

        return resp or self.app
Пример #8
0
def account_listing_response(account, req, response_content_type, broker=None,
                             limit='', marker='', end_marker='', prefix='',
                             delimiter=''):
    if broker is None:
        broker = FakeAccountBroker()

    info = broker.get_info()
    resp_headers = {
        'X-Account-Container-Count': info['container_count'],
        'X-Account-Object-Count': info['object_count'],
        'X-Account-Bytes-Used': info['bytes_used'],
        'X-Timestamp': info['created_at'],
        'X-PUT-Timestamp': info['put_timestamp']}
    resp_headers.update((key, value)
                        for key, (value, timestamp) in
                        broker.metadata.iteritems() if value != '')

    account_list = broker.list_containers_iter(limit, marker, end_marker,
                                               prefix, delimiter)
    if response_content_type == 'application/json':
        data = []
        for (name, object_count, bytes_used, is_subdir) in account_list:
            if is_subdir:
                data.append({'subdir': name})
            else:
                data.append({'name': name, 'count': object_count,
                             'bytes': bytes_used})
        account_list = json.dumps(data)
    elif response_content_type.endswith('/xml'):
        output_list = ['<?xml version="1.0" encoding="UTF-8"?>',
                       '<account name=%s>' % saxutils.quoteattr(account)]
        for (name, object_count, bytes_used, is_subdir) in account_list:
            if is_subdir:
                output_list.append(
                    '<subdir name=%s />' % saxutils.quoteattr(name))
            else:
                item = '<container><name>%s</name><count>%s</count>' \
                       '<bytes>%s</bytes></container>' % \
                       (saxutils.escape(name), object_count, bytes_used)
                output_list.append(item)
        output_list.append('</account>')
        account_list = '\n'.join(output_list)
    else:
        if not account_list:
            resp = HTTPNoContent(request=req, headers=resp_headers)
            resp.content_type = response_content_type
            resp.charset = 'utf-8'
            return resp
        account_list = '\n'.join(r[0] for r in account_list) + '\n'
    ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Пример #9
0
def account_listing_response(account, req, response_content_type,
                             info=None, listing=None):
    if info is None:
        now = Timestamp(time.time()).internal
        info = {'containers': 0,
                'objects': 0,
                'bytes': 0,
                'metadata': {},
                'ctime': now}
    if listing is None:
        listing = []

    resp_headers = get_response_headers(info)

    if response_content_type == 'application/json':
        data = []
        for (name, object_count, bytes_used, is_subdir) in listing:
            if is_subdir:
                data.append({'subdir': name})
            else:
                data.append({'name': name, 'count': object_count,
                             'bytes': bytes_used})
        account_list = json.dumps(data)
    elif response_content_type.endswith('/xml'):
        output_list = ['<?xml version="1.0" encoding="UTF-8"?>',
                       '<account name=%s>' % saxutils.quoteattr(account)]
        for (name, object_count, bytes_used, is_subdir) in listing:
            if is_subdir:
                output_list.append(
                    '<subdir name=%s />' % saxutils.quoteattr(name))
            else:
                item = '<container><name>%s</name><count>%s</count>' \
                       '<bytes>%s</bytes></container>' % \
                       (saxutils.escape(name), object_count, bytes_used)
                output_list.append(item)
        output_list.append('</account>')
        account_list = '\n'.join(output_list)
    else:
        if not listing:
            resp = HTTPNoContent(request=req, headers=resp_headers)
            resp.content_type = response_content_type
            resp.charset = 'utf-8'
            return resp
        account_list = '\n'.join(r[0] for r in listing) + '\n'
    ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Пример #10
0
def account_listing_response(account, req, response_content_type,
                             info=None, listing=None):
    if info is None:
        now = Timestamp(time.time()).internal
        info = {'containers': 0,
                'objects': 0,
                'bytes': 0,
                'metadata': {},
                'ctime': now}
    if listing is None:
        listing = []

    resp_headers = get_response_headers(info)

    if response_content_type == 'application/json':
        data = []
        for (name, object_count, bytes_used, is_subdir) in listing:
            if is_subdir:
                data.append({'subdir': name})
            else:
                data.append({'name': name, 'count': object_count,
                             'bytes': bytes_used})
        account_list = json.dumps(data)
    elif response_content_type.endswith('/xml'):
        output_list = ['<?xml version="1.0" encoding="UTF-8"?>',
                       '<account name=%s>' % saxutils.quoteattr(account)]
        for (name, object_count, bytes_used, is_subdir) in listing:
            if is_subdir:
                output_list.append(
                    '<subdir name=%s />' % saxutils.quoteattr(name))
            else:
                item = '<container><name>%s</name><count>%s</count>' \
                       '<bytes>%s</bytes></container>' % \
                       (saxutils.escape(name), object_count, bytes_used)
                output_list.append(item)
        output_list.append('</account>')
        account_list = '\n'.join(output_list)
    else:
        if not listing:
            resp = HTTPNoContent(request=req, headers=resp_headers)
            resp.content_type = response_content_type
            resp.charset = 'utf-8'
            return resp
        account_list = '\n'.join(r[0] for r in listing) + '\n'
    ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Пример #11
0
    def handle_multipart_delete(self, req):
        """
        Will delete all the segments in the SLO manifest and then, if
        successful, will delete the manifest file.

        :params req: a swob.Request with an obj in path
        :returns: swob.Response whose app_iter set to Bulk.handle_delete_iter
        """
        resp = HTTPOk(request=req)
        out_content_type = req.accept.best_match(ACCEPTABLE_FORMATS)
        if out_content_type:
            resp.content_type = out_content_type
        resp.app_iter = self.bulk_deleter.handle_delete_iter(
            req, objs_to_delete=self.get_segments_to_delete_iter(req),
            user_agent='MultipartDELETE', swift_source='SLO',
            out_content_type=out_content_type)
        return resp
Пример #12
0
    def handle_multipart_delete(self, req):
        """
        Will delete all the segments in the SLO manifest and then, if
        successful, will delete the manifest file.

        :params req: a swob.Request with an obj in path
        :returns: swob.Response whose app_iter set to Bulk.handle_delete_iter
        """
        resp = HTTPOk(request=req)
        out_content_type = req.accept.best_match(ACCEPTABLE_FORMATS)
        if out_content_type:
            resp.content_type = out_content_type
        resp.app_iter = self.bulk_deleter.handle_delete_iter(
            req, objs_to_delete=self.get_segments_to_delete_iter(req),
            user_agent='MultipartDELETE', swift_source='SLO',
            out_content_type=out_content_type)
        return resp
Пример #13
0
def account_listing_response(account,
                             req,
                             response_content_type,
                             broker=None,
                             limit=constraints.ACCOUNT_LISTING_LIMIT,
                             marker='',
                             end_marker='',
                             prefix='',
                             delimiter='',
                             reverse=False):
    if broker is None:
        broker = FakeAccountBroker()

    resp_headers = get_response_headers(broker)

    account_list = broker.list_containers_iter(limit, marker, end_marker,
                                               prefix, delimiter, reverse,
                                               req.allow_reserved_names)
    data = []
    for (name, object_count, bytes_used, put_timestamp, is_subdir) \
            in account_list:
        name_ = name.decode('utf8') if six.PY2 else name
        if is_subdir:
            data.append({'subdir': name_})
        else:
            data.append({
                'name': name_,
                'count': object_count,
                'bytes': bytes_used,
                'last_modified': Timestamp(put_timestamp).isoformat
            })
    if response_content_type.endswith('/xml'):
        account_list = listing_formats.account_to_xml(data, account)
        ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    elif response_content_type.endswith('/json'):
        account_list = json.dumps(data).encode('ascii')
        ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    elif data:
        account_list = listing_formats.listing_to_text(data)
        ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    else:
        ret = HTTPNoContent(request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Пример #14
0
def account_listing_response(account, req, response_content_type, broker=None,
                             limit='', marker='', end_marker='', prefix='',
                             delimiter='', reverse=False):
    if broker is None:
        broker = FakeAccountBroker()

    resp_headers = get_response_headers(broker)

    account_list = broker.list_containers_iter(limit, marker, end_marker,
                                               prefix, delimiter, reverse)
    if response_content_type == 'application/json':
        data = []
        for (name, object_count, bytes_used, is_subdir) in account_list:
            if is_subdir:
                data.append({'subdir': name})
            else:
                data.append({'name': name, 'count': object_count,
                             'bytes': bytes_used})
        account_list = json.dumps(data)
    elif response_content_type.endswith('/xml'):
        output_list = ['<?xml version="1.0" encoding="UTF-8"?>',
                       '<account name=%s>' % saxutils.quoteattr(account)]
        for (name, object_count, bytes_used, is_subdir) in account_list:
            if is_subdir:
                output_list.append(
                    '<subdir name=%s />' % saxutils.quoteattr(name))
            else:
                item = '<container><name>%s</name><count>%s</count>' \
                       '<bytes>%s</bytes></container>' % \
                       (saxutils.escape(name), object_count, bytes_used)
                output_list.append(item)
        output_list.append('</account>')
        account_list = '\n'.join(output_list)
    else:
        if not account_list:
            resp = HTTPNoContent(request=req, headers=resp_headers)
            resp.content_type = response_content_type
            resp.charset = 'utf-8'
            return resp
        account_list = '\n'.join(r[0] for r in account_list) + '\n'
    ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Пример #15
0
    def handle_multipart_delete(self, req):
        """
        Will delete all the segments in the SLO manifest and then, if
        successful, will delete the manifest file.
        :params req: a swob.Request with an obj in path
        :raises HTTPServerError: on invalid manifest
        :returns: swob.Response whose app_iter set to Bulk.handle_delete_iter
        """
        if not check_utf8(req.path_info):
            raise HTTPPreconditionFailed(
                request=req, body='Invalid UTF8 or contains NULL')

        resp = HTTPOk(request=req)
        out_content_type = req.accept.best_match(ACCEPTABLE_FORMATS)
        if out_content_type:
            resp.content_type = out_content_type
        resp.app_iter = self.bulk_deleter.handle_delete_iter(
            req, objs_to_delete=self.get_segments_to_delete_iter(req),
            user_agent='MultipartDELETE', swift_source='SLO',
            out_content_type=out_content_type)
        return resp
Пример #16
0
    def handle_multipart_delete(self, req):
        """
        Will delete all the segments in the SLO manifest and then, if
        successful, will delete the manifest file.
        :params req: a swob.Request with an obj in path
        :raises HTTPServerError: on invalid manifest
        :returns: swob.Response whose app_iter set to Bulk.handle_delete_iter
        """
        if not check_utf8(req.path_info):
            raise HTTPPreconditionFailed(
                request=req, body='Invalid UTF8 or contains NULL')

        resp = HTTPOk(request=req)
        out_content_type = req.accept.best_match(ACCEPTABLE_FORMATS)
        if out_content_type:
            resp.content_type = out_content_type
        resp.app_iter = self.bulk_deleter.handle_delete_iter(
            req, objs_to_delete=self.get_segments_to_delete_iter(req),
            user_agent='MultipartDELETE', swift_source='SLO',
            out_content_type=out_content_type)
        return resp
Пример #17
0
def account_listing_bucket_response(account,
                                    req,
                                    response_content_type,
                                    listing=None):
    if response_content_type != 'application/json':
        # AWS S3 is always call wit format=json
        # check method GET in ServiceController (swift3/controllers/service.py)
        return HTTPPreconditionFailed(body='Invalid content type')

    data = []
    for entry in listing:
        data.append({
            'name': entry['name'],
            'count': entry['objects'],
            'bytes': entry['bytes'],
            'last_modified': Timestamp(entry['mtime']).isoformat
        })
    account_list = json.dumps(data, encoding="utf-8")
    ret = HTTPOk(body=account_list, request=req, headers={})
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Пример #18
0
def account_listing_response(account,
                             req,
                             response_content_type,
                             broker=None,
                             limit='',
                             marker='',
                             end_marker='',
                             prefix='',
                             delimiter='',
                             reverse=False):
    """
    This is an exact copy of swift.account.utis.account_listing_response()
    except for one difference i.e this method passes response_content_type
    to broker.list_containers_iter() method.
    """
    if broker is None:
        broker = FakeAccountBroker()

    resp_headers = get_response_headers(broker)

    account_list = broker.list_containers_iter(limit, marker, end_marker,
                                               prefix, delimiter,
                                               response_content_type, reverse)
    if response_content_type == 'application/json':
        data = []
        for (name, object_count, bytes_used, put_tstamp,
             is_subdir) in account_list:
            if is_subdir:
                data.append({'subdir': name})
            else:
                data.append({
                    'name': name,
                    'count': object_count,
                    'bytes': bytes_used,
                    'last_modified': Timestamp(put_tstamp).isoformat
                })
        account_list = json.dumps(data)
    elif response_content_type.endswith('/xml'):
        output_list = [
            '<?xml version="1.0" encoding="UTF-8"?>',
            '<account name=%s>' % saxutils.quoteattr(account)
        ]
        for (name, object_count, bytes_used, put_tstamp,
             is_subdir) in account_list:
            if is_subdir:
                output_list.append('<subdir name=%s />' %
                                   saxutils.quoteattr(name))
            else:
                item = '<container><name>%s</name><count>%s</count>' \
                       '<bytes>%s</bytes><last_modified>%s</last_modified> \
                        </container>'                                      % \
                       (saxutils.escape(name), object_count, bytes_used,
                        Timestamp(put_tstamp).isoformat)
                output_list.append(item)
        output_list.append('</account>')
        account_list = '\n'.join(output_list)
    else:
        if not account_list:
            resp = HTTPNoContent(request=req, headers=resp_headers)
            resp.content_type = response_content_type
            resp.charset = 'utf-8'
            return resp
        account_list = '\n'.join(r[0] for r in account_list) + '\n'
    ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret