def POST(self, req): """Handle HTTP POST request.""" drive, part, account, container = split_and_validate_path(req, 4) if 'x-timestamp' not in req.headers or \ not check_float(req.headers['x-timestamp']): return HTTPBadRequest(body='Missing or bad timestamp', request=req, content_type='text/plain') if 'x-container-sync-to' in req.headers: err = validate_sync_to(req.headers['x-container-sync-to'], self.allowed_sync_hosts) if err: return HTTPBadRequest(err) if self.mount_check and not check_mount(self.root, drive): return HTTPInsufficientStorage(drive=drive, request=req) broker = self._get_container_broker(drive, part, account, container) if broker.is_deleted(): return HTTPNotFound(request=req) timestamp = normalize_timestamp(req.headers['x-timestamp']) metadata = {} metadata.update((key, (value, timestamp)) for key, value in req.headers.iteritems() if key.lower() in self.save_headers or key.lower().startswith('x-container-meta-')) if metadata: if 'X-Container-Sync-To' in metadata: if 'X-Container-Sync-To' not in broker.metadata or \ metadata['X-Container-Sync-To'][0] != \ broker.metadata['X-Container-Sync-To'][0]: broker.set_x_container_sync_points(-1, -1) broker.update_metadata(metadata) return HTTPNoContent(request=req)
def HEAD(self, req): """Handle HTTP HEAD request.""" drive, part, account, container, obj = split_and_validate_path( req, 4, 5, True) out_content_type = listing_formats.get_listing_content_type(req) try: check_drive(self.root, drive, self.mount_check) except ValueError: return HTTPInsufficientStorage(drive=drive, request=req) broker = self._get_container_broker(drive, part, account, container, pending_timeout=0.1, stale_reads_ok=True) info, is_deleted = broker.get_info_is_deleted() headers = gen_resp_headers(info, is_deleted=is_deleted) if is_deleted: return HTTPNotFound(request=req, headers=headers) headers.update( (key, value) for key, (value, timestamp) in broker.metadata.items() if value != '' and (key.lower() in self.save_headers or is_sys_or_user_meta('container', key))) headers['Content-Type'] = out_content_type resp = HTTPNoContent(request=req, headers=headers, charset='utf-8') resp.last_modified = math.ceil(float(headers['X-PUT-Timestamp'])) return resp
def HEAD(self, req): """Handle HTTP HEAD request.""" drive, part, account, container, obj = split_and_validate_path( req, 4, 5, True) out_content_type = get_listing_content_type(req) if self.mount_check and not check_mount(self.root, drive): return HTTPInsufficientStorage(drive=drive, request=req) broker = self._get_container_broker(drive, part, account, container, pending_timeout=0.1, stale_reads_ok=True) if broker.is_deleted(): return HTTPNotFound(request=req) info = broker.get_info() headers = { 'X-Container-Object-Count': info['object_count'], 'X-Container-Bytes-Used': info['bytes_used'], 'X-Timestamp': info['created_at'], 'X-PUT-Timestamp': info['put_timestamp'], } headers.update( (key, value) for key, (value, timestamp) in broker.metadata.iteritems() if value != '' and (key.lower() in self.save_headers or key.lower().startswith('x-container-meta-'))) headers['Content-Type'] = out_content_type return HTTPNoContent(request=req, headers=headers, charset='utf-8')
def POST(self, req): """Handle HTTP POST request.""" drive, part, account, container = split_and_validate_path(req, 4) req_timestamp = valid_timestamp(req) if 'x-container-sync-to' in req.headers: err, sync_to, realm, realm_key = validate_sync_to( req.headers['x-container-sync-to'], self.allowed_sync_hosts, self.realms_conf) if err: return HTTPBadRequest(err) if not check_drive(self.root, drive, self.mount_check): return HTTPInsufficientStorage(drive=drive, request=req) broker = self._get_container_broker(drive, part, account, container) if broker.is_deleted(): return HTTPNotFound(request=req) broker.update_put_timestamp(req_timestamp.internal) metadata = {} metadata.update( (key, (value, req_timestamp.internal)) for key, value in req.headers.items() if key.lower() in self.save_headers or is_sys_or_user_meta('container', key)) if metadata: if 'X-Container-Sync-To' in metadata: if 'X-Container-Sync-To' not in broker.metadata or \ metadata['X-Container-Sync-To'][0] != \ broker.metadata['X-Container-Sync-To'][0]: broker.set_x_container_sync_points(-1, -1) broker.update_metadata(metadata, validate_metadata=True) self._update_sync_store(broker, 'POST') return HTTPNoContent(request=req)
def handle_change_secret_key(self, req, access_key): """Change current secret key for given access key. Required headers: - `x-s3auth-secret-key-old`: must match current secret key - `x-s3auth-secret-key-new`: the new secret key """ secret_old = req.headers.get('x-s3auth-secret-key-old') secret_new = req.headers.get('x-s3auth-secret-key-new') if not (secret_old and secret_new): return HTTPBadRequest( body='x-s3auth-secret-key-old and x-s3auth-secret-key-new ' 'headers required', request=req) secret_key, account = self._get_details(req, access_key) if secret_key: if secret_key == secret_old: self._set_details(req, access_key, secret_new, account) return HTTPNoContent(request=req) else: return _denied_response(req) else: return _denied_response(req)
def DELETE(self, req): """Handle HTTP DELETE request.""" drive, part, account, container, obj = split_and_validate_path( req, 4, 5, True) req_timestamp = valid_timestamp(req) try: check_drive(self.root, drive, self.mount_check) except ValueError: return HTTPInsufficientStorage(drive=drive, request=req) # policy index is only relevant for delete_obj (and transitively for # auto create accounts) obj_policy_index = self.get_and_validate_policy_index(req) or 0 broker = self._get_container_broker(drive, part, account, container) if account.startswith(self.auto_create_account_prefix) and obj and \ not os.path.exists(broker.db_file): try: broker.initialize(req_timestamp.internal, obj_policy_index) except DatabaseAlreadyExists: pass if not os.path.exists(broker.db_file): return HTTPNotFound() if obj: # delete object # redirect if a shard range exists for the object name redirect = self._redirect_to_shard(req, broker, obj) if redirect: return redirect broker.delete_object(obj, req.headers.get('x-timestamp'), obj_policy_index) return HTTPNoContent(request=req) else: # delete container if not broker.empty(): return HTTPConflict(request=req) existed = Timestamp(broker.get_info()['put_timestamp']) and \ not broker.is_deleted() broker.delete_db(req_timestamp.internal) if not broker.is_deleted(): return HTTPConflict(request=req) self._update_sync_store(broker, 'DELETE') resp = self.account_update(req, account, container, broker) if resp: return resp if existed: return HTTPNoContent(request=req) return HTTPNotFound()
class AccountController(object): """WSGI controller for the account server.""" def __init__(self, conf): self.logger = get_logger(conf, log_route='account-server') self.root = conf.get('devices', '/srv/node') self.mount_check = config_true_value(conf.get('mount_check', 'true')) replication_server = conf.get('replication_server', None) if replication_server is None: allowed_methods = [ 'DELETE', 'PUT', 'HEAD', 'GET', 'REPLICATE', 'POST' ] else: replication_server = config_true_value(replication_server) if replication_server: allowed_methods = ['REPLICATE'] else: allowed_methods = ['DELETE', 'PUT', 'HEAD', 'GET', 'POST'] self.replication_server = replication_server self.allowed_methods = allowed_methods self.replicator_rpc = ReplicatorRpc(self.root, DATADIR, AccountBroker, self.mount_check, logger=self.logger) self.auto_create_account_prefix = \ conf.get('auto_create_account_prefix') or '.' swift.common.db.DB_PREALLOCATION = \ config_true_value(conf.get('db_preallocation', 'f')) def _get_account_broker(self, drive, part, account): hsh = hash_path(account) db_dir = storage_directory(DATADIR, part, hsh) db_path = os.path.join(self.root, drive, db_dir, hsh + '.db') return AccountBroker(db_path, account=account, logger=self.logger) @public @timing_stats() def DELETE(self, req): """Handle HTTP DELETE request.""" try: drive, part, account = req.split_path(3) validate_device_partition(drive, part) except ValueError, err: return HTTPBadRequest(body=str(err), content_type='text/plain', request=req) if self.mount_check and not check_mount(self.root, drive): return HTTPInsufficientStorage(drive=drive, request=req) if 'x-timestamp' not in req.headers or \ not check_float(req.headers['x-timestamp']): return HTTPBadRequest(body='Missing timestamp', request=req, content_type='text/plain') broker = self._get_account_broker(drive, part, account) if broker.is_deleted(): return HTTPNotFound(request=req) broker.delete_db(req.headers['x-timestamp']) return HTTPNoContent(request=req)
def origin_db_delete(self, env, req): """ Handles DELETEs in the Origin database. This is not really a delete- it will remove the object from the container listing and set cdn_enabled=false and a deleted flag in the .hash_* obj that says that the obj is deleted. This way the container won't show up in the listings, HEAD to the object will return 404s but behind the scenes lookups to the object will be able to determine the account and container from a container_hash. """ try: vsn, account, container = split_path(req.path, 3, 3) except ValueError: return HTTPBadRequest( 'Invalid request. ' 'URI format: /<api version>/<account>/<container>') if self.extra_header_for_deletes and not req.headers.get( self.extra_header_for_deletes, 'f').lower() in TRUE_VALUES: # only do delete if header is set (assuming you want the header) return HTTPMethodNotAllowed(request=req) hsh = self.hash_path(account, container) cdn_obj_path = self.get_hsh_obj_path(hsh) # Remove memcache entry memcache_client = utils.cache_from_env(env) if memcache_client: memcache_key = self.cdn_data_memcache_key(cdn_obj_path) memcache_client.delete(memcache_key) ref_hash_data = HashData(account, container, self.default_ttl, False, False, deleted=True) self._set_hash_data(env, cdn_obj_path, ref_hash_data, update_listings=False) cdn_list_path = quote('/v1/%s/%s/%s' % (self.origin_account, account, container)) list_resp = make_pre_authed_request(env, 'DELETE', cdn_list_path, agent='SwiftOrigin', swift_source='SOS').get_response( self.app) if list_resp.status_int // 100 != 2 and list_resp.status_int != 404: raise OriginDbFailure('Could not DELETE listing path in origin ' 'db: %s %s' % (cdn_list_path, list_resp.status_int)) # Return 404 if container didn't exist if list_resp.status_int == 404: return HTTPNotFound(request=req) return HTTPNoContent(request=req)
def PUT(self, req): """Handle HTTP PUT request.""" drive, part, account, container = split_and_validate_path(req, 3, 4) if self.mount_check and not check_mount(self.root, drive): return HTTPInsufficientStorage(drive=drive, request=req) if container: # put account container pending_timeout = None if 'x-trans-id' in req.headers: pending_timeout = 3 broker = self._get_account_broker(drive, part, account, pending_timeout=pending_timeout) if account.startswith(self.auto_create_account_prefix) and \ not os.path.exists(broker.db_file): try: broker.initialize(normalize_timestamp( req.headers.get('x-timestamp') or time.time())) except DatabaseAlreadyExists: pass if req.headers.get('x-account-override-deleted', 'no').lower() != \ 'yes' and broker.is_deleted(): return HTTPNotFound(request=req) broker.put_container(container, req.headers['x-put-timestamp'], req.headers['x-delete-timestamp'], req.headers['x-object-count'], req.headers['x-bytes-used']) if req.headers['x-delete-timestamp'] > \ req.headers['x-put-timestamp']: return HTTPNoContent(request=req) else: return HTTPCreated(request=req) else: # put account broker = self._get_account_broker(drive, part, account) timestamp = normalize_timestamp(req.headers['x-timestamp']) if not os.path.exists(broker.db_file): try: broker.initialize(timestamp) created = True except DatabaseAlreadyExists: created = False elif broker.is_status_deleted(): return self._deleted_response(broker, req, HTTPForbidden, body='Recently deleted') else: created = broker.is_deleted() broker.update_put_timestamp(timestamp) if broker.is_deleted(): return HTTPConflict(request=req) metadata = {} metadata.update((key, (value, timestamp)) for key, value in req.headers.iteritems() if key.lower().startswith('x-account-meta-')) if metadata: broker.update_metadata(metadata) if created: return HTTPCreated(request=req) else: return HTTPAccepted(request=req)
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
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
def get_account_post_resp(self, req, headers): metadata = {} metadata.update((key, value) for key, value in req.headers.items() if is_sys_or_user_meta('account', key)) try: self.app.storage.account_update(self.account_name, metadata) return HTTPNoContent(request=req) except (exceptions.NotFound, exceptions.NoSuchAccount): if self.app.account_autocreate: self.autocreate_account(req, self.account_name) if metadata: self.app.storage.account_update( self.account_name, metadata, headers=headers) resp = HTTPNoContent(request=req) else: resp = HTTPNotFound(request=req) self.add_acls_from_sys_metadata(resp) return resp
def complete_rsync(self, drive, db_file, args): old_filename = os.path.join(self.root, drive, 'tmp', args[0]) if os.path.exists(db_file): return HTTPNotFound() if not os.path.exists(old_filename): return HTTPNotFound() broker = self.broker_class(old_filename) broker.newid(args[0]) renamer(old_filename, db_file) return HTTPNoContent()
def get_container_head_resp(self, req): headers = dict() out_content_type = get_listing_content_type(req) headers['Content-Type'] = out_content_type oio_headers = {REQID_HEADER: self.trans_id} meta = self.app.storage.container_get_properties(self.account_name, self.container_name, headers=oio_headers) headers.update(self.get_metadata_resp_headers(meta)) return HTTPNoContent(request=req, headers=headers, charset='utf-8')
def get_container_delete_resp(self, req): oio_headers = {REQID_HEADER: self.trans_id} try: self.app.storage.container_delete(self.account_name, self.container_name, headers=oio_headers) except exceptions.ContainerNotEmpty: return HTTPConflict(request=req) resp = HTTPNoContent(request=req) return resp
def DELETE(self, req): """Handle HTTP DELETE request.""" drive, part, account, container, obj = split_and_validate_path( req, 4, 5, True) if 'x-timestamp' not in req.headers or \ not check_float(req.headers['x-timestamp']): return HTTPBadRequest(body='Missing timestamp', request=req, content_type='text/plain') if self.mount_check and not check_mount(self.root, drive): return HTTPInsufficientStorage(drive=drive, request=req) broker = self._get_container_broker(drive, part, account, container) if account.startswith(self.auto_create_account_prefix) and obj and \ not os.path.exists(broker.db_file): requested_policy_index = (self.get_and_validate_policy_index(req) or POLICIES.default.idx) try: broker.initialize( normalize_timestamp( req.headers.get('x-timestamp') or time.time()), requested_policy_index) except DatabaseAlreadyExists: pass if not os.path.exists(broker.db_file): return HTTPNotFound() if obj: # delete object broker.delete_object(obj, req.headers.get('x-timestamp')) return HTTPNoContent(request=req) else: # delete container if not broker.empty(): return HTTPConflict(request=req) existed = float(broker.get_info()['put_timestamp']) and \ not broker.is_deleted() broker.delete_db(req.headers['X-Timestamp']) if not broker.is_deleted(): return HTTPConflict(request=req) resp = self.account_update(req, account, container, broker) if resp: return resp if existed: return HTTPNoContent(request=req) return HTTPNotFound()
def get_container_delete_resp(self, req, headers): oio_headers = {'X-oio-req-id': self.trans_id} try: self.app.storage.container_delete( self.account_name, self.container_name, headers=oio_headers) except exceptions.ContainerNotEmpty: return HTTPConflict(request=req) except exceptions.NoSuchContainer: return HTTPNotFound(request=req) resp = HTTPNoContent(request=req) return resp
def get_container_delete_resp(self, req): oio_headers = {REQID_HEADER: self.trans_id} oio_cache = req.environ.get('oio.cache') perfdata = req.environ.get('oio.perfdata') try: self.app.storage.container_delete( self.account_name, self.container_name, headers=oio_headers, cache=oio_cache, perfdata=perfdata) except exceptions.ContainerNotEmpty: return HTTPConflict(request=req) resp = HTTPNoContent(request=req) return resp
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
def get_container_create_resp(self, req, headers): properties, system = self.properties_from_headers(headers) # TODO container update metadata oio_headers = {'X-oio-req-id': self.trans_id} created = self.app.storage.container_create( self.account_name, self.container_name, properties=properties, system=system, headers=oio_headers) if created: return HTTPCreated(request=req) else: return HTTPNoContent(request=req)
def origin_db_delete(self, env, req): """ Handles DELETEs in the Origin database """ if not self.delete_enabled: return HTTPMethodNotAllowed(request=req) try: vsn, account, container = split_path(req.path, 3, 3) except ValueError: return HTTPBadRequest( 'Invalid request. ' 'URI format: /<api version>/<account>/<container>') hsh = self.hash_path(account, container) cdn_obj_path = self.get_hsh_obj_path(hsh) # Remove memcache entry memcache_client = utils.cache_from_env(env) if memcache_client: memcache_key = self.cdn_data_memcache_key(cdn_obj_path) memcache_client.delete(memcache_key) resp = make_pre_authed_request(env, 'DELETE', cdn_obj_path, agent='SwiftOrigin', swift_source='SOS').get_response( self.app) # A 404 means it's already deleted, which is okay if resp.status_int // 100 != 2 and resp.status_int != 404: raise OriginDbFailure('Could not DELETE .hash obj in origin ' 'db: %s %s' % (cdn_obj_path, resp.status_int)) cdn_list_path = quote('/v1/%s/%s/%s' % (self.origin_account, account, container)) list_resp = make_pre_authed_request(env, 'DELETE', cdn_list_path, agent='SwiftOrigin', swift_source='SOS').get_response( self.app) if list_resp.status_int // 100 != 2 and list_resp.status_int != 404: raise OriginDbFailure('Could not DELETE listing path in origin ' 'db: %s %s' % (cdn_list_path, list_resp.status_int)) # Return 404 if container didn't exist if resp.status_int == 404 and list_resp.status_int == 404: return HTTPNotFound(request=req) return HTTPNoContent(request=req)
def HEAD(self, req): """Handle HTTP HEAD request.""" drive, part, account = split_and_validate_path(req, 3) out_content_type = get_listing_content_type(req) if self.mount_check and not check_mount(self.root, drive): return HTTPInsufficientStorage(drive=drive, request=req) broker = self._get_account_broker(drive, part, account, pending_timeout=0.1, stale_reads_ok=True) if broker.is_deleted(): return self._deleted_response(broker, req, HTTPNotFound) headers = get_response_headers(broker) headers['Content-Type'] = out_content_type return HTTPNoContent(request=req, headers=headers, charset='utf-8')
def __call__(self, env, start_response): req = Request(env) if env['REQUEST_METHOD'] == 'GET' or env['REQUEST_METHOD'] == 'HEAD': if self.status == 200: if 'HTTP_RANGE' in env: resp = Response(request=req, body=self.object_body, conditional_response=True) return resp(env, start_response) start_response( Response(request=req).status, self.response_headers.items()) if env['REQUEST_METHOD'] == 'GET': return self.object_body elif self.status == 401: start_response(HTTPUnauthorized(request=req).status, []) elif self.status == 403: start_response(HTTPForbidden(request=req).status, []) elif self.status == 404: start_response(HTTPNotFound(request=req).status, []) else: start_response(HTTPBadRequest(request=req).status, []) elif env['REQUEST_METHOD'] == 'PUT': if self.status == 201: start_response( HTTPCreated(request=req).status, [('etag', self.response_headers['etag'])]) elif self.status == 401: start_response(HTTPUnauthorized(request=req).status, []) elif self.status == 403: start_response(HTTPForbidden(request=req).status, []) elif self.status == 404: start_response(HTTPNotFound(request=req).status, []) elif self.status == 413: start_response( HTTPRequestEntityTooLarge(request=req).status, []) else: start_response(HTTPBadRequest(request=req).status, []) elif env['REQUEST_METHOD'] == 'DELETE': if self.status == 204: start_response(HTTPNoContent(request=req).status, []) elif self.status == 401: start_response(HTTPUnauthorized(request=req).status, []) elif self.status == 403: start_response(HTTPForbidden(request=req).status, []) elif self.status == 404: start_response(HTTPNotFound(request=req).status, []) else: start_response(HTTPBadRequest(request=req).status, []) return []
def get_container_head_resp(self, req): headers = dict() out_content_type = get_listing_content_type(req) headers['Content-Type'] = out_content_type oio_headers = {'X-oio-req-id': self.trans_id} try: meta = self.app.storage.container_get_properties( self.account_name, self.container_name, headers=oio_headers) headers.update(self.get_metadata_resp_headers(meta)) resp = HTTPNoContent(request=req, headers=headers, charset='utf-8') except exceptions.NoSuchContainer: resp = HTTPNotFound(request=req, headers=headers) return resp
def __call__(self, env, start_response): if env['REQUEST_METHOD'] == 'GET': if self.status == 200: start_response(Response().status, [('Content-Type', 'text/xml')]) json_pattern = [ '"name":%s', '"last_modified":%s', '"hash":%s', '"bytes":%s' ] json_pattern = '{' + ','.join(json_pattern) + '}' json_out = [] for b in self.objects: name = simplejson.dumps(b[0]) time = simplejson.dumps(b[1]) json_out.append(json_pattern % (name, time, b[2], b[3])) account_list = '[' + ','.join(json_out) + ']' return account_list elif self.status == 401: start_response(HTTPUnauthorized().status, []) elif self.status == 403: start_response(HTTPForbidden().status, []) elif self.status == 404: start_response(HTTPNotFound().status, []) else: start_response(HTTPBadRequest().status, []) elif env['REQUEST_METHOD'] == 'PUT': if self.status == 201: start_response(HTTPCreated().status, []) elif self.status == 401: start_response(HTTPUnauthorized().status, []) elif self.status == 403: start_response(HTTPForbidden().status, []) elif self.status == 202: start_response(HTTPAccepted().status, []) else: start_response(HTTPBadRequest().status, []) elif env['REQUEST_METHOD'] == 'DELETE': if self.status == 204: start_response(HTTPNoContent().status, []) elif self.status == 401: start_response(HTTPUnauthorized().status, []) elif self.status == 403: start_response(HTTPForbidden().status, []) elif self.status == 404: start_response(HTTPNotFound().status, []) elif self.status == 409: start_response(HTTPConflict().status, []) else: start_response(HTTPBadRequest().status, []) return []
def create_listing(self, req, out_content_type, resp_headers, result, container, **kwargs): container_list = result['objects'] for p in result.get('prefixes', []): record = {'name': p, 'subdir': True} container_list.append(record) container_list.sort(key=lambda x: x['name']) ret = Response(request=req, headers=resp_headers, content_type=out_content_type, charset='utf-8') versions = kwargs.get('versions', False) slo = kwargs.get('slo', False) if out_content_type == 'application/json': ret.body = json.dumps([ self.update_data_record(r, versions, slo) for r in container_list ]).encode('utf-8') req.environ['swift.format_listing'] = False elif out_content_type.endswith('/xml'): doc = Element('container', name=container.decode('utf-8')) for obj in container_list: record = self.update_data_record(obj, versions, slo) if 'subdir' in record: name = record['subdir'].decode('utf-8') sub = SubElement(doc, 'subdir', name=name) SubElement(sub, 'name').text = name else: obj_element = SubElement(doc, 'object') for field in [ "name", "hash", "bytes", "content_type", "last_modified" ]: SubElement(obj_element, field).text = str( record.pop(field)).decode('utf-8') for field in sorted(record): SubElement(obj_element, field).text = str( record[field]).decode('utf-8') ret.body = tostring(doc, encoding='UTF-8').replace( "<?xml version='1.0' encoding='UTF-8'?>", '<?xml version="1.0" encoding="UTF-8"?>', 1) req.environ['swift.format_listing'] = False else: if not container_list: return HTTPNoContent(request=req, headers=resp_headers) ret.body = ('\n'.join(rec['name'] for rec in container_list) + '\n').encode('utf-8') return ret
def create_listing(self, req, out_content_type, info, metadata, container_list, container): list_meta = get_param(req, 'list_meta', 'f').lower() in TRUE_VALUES resp_headers = { 'X-Container-Object-Count': info['object_count'], 'X-Container-Bytes-Used': info['bytes_used'], 'X-Timestamp': info['created_at'], 'X-PUT-Timestamp': info['put_timestamp'], } for key, (value, timestamp) in metadata.iteritems(): if value and (key.lower() in self.save_headers or is_sys_or_user_meta('container', key)): resp_headers[key] = value ret = Response(request=req, headers=resp_headers, content_type=out_content_type, charset='utf-8') if out_content_type == 'application/json': ret.body = json.dumps([self.update_data_record(record, list_meta) for record in container_list]) elif out_content_type.endswith('/xml'): doc = Element('container', name=container.decode('utf-8')) for obj in container_list: record = self.update_data_record(obj, list_meta) if 'subdir' in record: name = record['subdir'].decode('utf-8') sub = SubElement(doc, 'subdir', name=name) SubElement(sub, 'name').text = name else: obj_element = SubElement(doc, 'object') for field in ["name", "hash", "bytes", "content_type", "last_modified"]: SubElement(obj_element, field).text = str( record.pop(field)).decode('utf-8') for field in sorted(record): if list_meta and field == 'metadata': meta = SubElement(obj_element, field) for k, v in record[field].iteritems(): SubElement(meta, k).text = str( v.decode('utf-8')) else: SubElement(obj_element, field).text = str( record[field]).decode('utf-8') ret.body = tostring(doc, encoding='UTF-8').replace( "<?xml version='1.0' encoding='UTF-8'?>", '<?xml version="1.0" encoding="UTF-8"?>', 1) else: if not container_list: return HTTPNoContent(request=req, headers=resp_headers) ret.body = '\n'.join(rec[0] for rec in container_list) + '\n' return ret
def get_container_post_resp(self, req, headers): properties, system = self.properties_from_headers(headers) if not properties: return self.PUT(req) oio_headers = {'X-oio-req-id': self.trans_id} try: self.app.storage.container_set_properties( self.account_name, self.container_name, properties=properties, system=system, headers=oio_headers) resp = HTTPNoContent(request=req) except exceptions.NoSuchContainer: resp = self.PUT(req) return resp
def POST(self, req): """Handle HTTP POST request.""" drive, part, account = split_and_validate_path(req, 3) req_timestamp = valid_timestamp(req) try: check_drive(self.root, drive, self.mount_check) except ValueError: return HTTPInsufficientStorage(drive=drive, request=req) if not self.check_free_space(drive): return HTTPInsufficientStorage(drive=drive, request=req) broker = self._get_account_broker(drive, part, account) if broker.is_deleted(): return self._deleted_response(broker, req, HTTPNotFound) self._update_metadata(req, broker, req_timestamp) return HTTPNoContent(request=req)
class AccountController(object): """WSGI controller for the account server.""" def __init__(self, conf): self.logger = get_logger(conf, log_route='account-server') self.root = conf.get('devices', '/srv/node') self.mount_check = conf.get('mount_check', 'true').lower() in \ TRUE_VALUES self.replicator_rpc = ReplicatorRpc(self.root, DATADIR, AccountBroker, self.mount_check, logger=self.logger) self.auto_create_account_prefix = \ conf.get('auto_create_account_prefix') or '.' swift.common.db.DB_PREALLOCATION = \ conf.get('db_preallocation', 'f').lower() in TRUE_VALUES def _get_account_broker(self, drive, part, account): hsh = hash_path(account) db_dir = storage_directory(DATADIR, part, hsh) db_path = os.path.join(self.root, drive, db_dir, hsh + '.db') return AccountBroker(db_path, account=account, logger=self.logger) @public def DELETE(self, req): """Handle HTTP DELETE request.""" start_time = time.time() try: drive, part, account = split_path(unquote(req.path), 3) validate_device_partition(drive, part) except ValueError, err: self.logger.increment('DELETE.errors') return HTTPBadRequest(body=str(err), content_type='text/plain', request=req) if self.mount_check and not check_mount(self.root, drive): self.logger.increment('DELETE.errors') return HTTPInsufficientStorage(drive=drive, request=req) if 'x-timestamp' not in req.headers or \ not check_float(req.headers['x-timestamp']): self.logger.increment('DELETE.errors') return HTTPBadRequest(body='Missing timestamp', request=req, content_type='text/plain') broker = self._get_account_broker(drive, part, account) if broker.is_deleted(): self.logger.timing_since('DELETE.timing', start_time) return HTTPNotFound(request=req) broker.delete_db(req.headers['x-timestamp']) self.logger.timing_since('DELETE.timing', start_time) return HTTPNoContent(request=req)