Example #1
0
 def GET(self, request):
     """Handle HTTP GET requests for the Swift Object Server."""
     device, partition, account, container, obj, policy = \
         get_name_and_placement(request, 5, 5, True)
     keep_cache = self.keep_cache_private or (
         'X-Auth-Token' not in request.headers
         and 'X-Storage-Token' not in request.headers)
     try:
         disk_file = self.get_diskfile(device,
                                       partition,
                                       account,
                                       container,
                                       obj,
                                       policy=policy)
     except DiskFileDeviceUnavailable:
         return HTTPInsufficientStorage(drive=device, request=request)
     try:
         with disk_file.open():
             metadata = disk_file.get_metadata()
             obj_size = int(metadata['Content-Length'])
             file_x_ts = Timestamp(metadata['X-Timestamp'])
             keep_cache = (self.keep_cache_private or
                           ('X-Auth-Token' not in request.headers
                            and 'X-Storage-Token' not in request.headers))
             conditional_etag = None
             if 'X-Backend-Etag-Is-At' in request.headers:
                 conditional_etag = metadata.get(
                     request.headers['X-Backend-Etag-Is-At'])
             response = Response(
                 app_iter=disk_file.reader(keep_cache=keep_cache),
                 request=request,
                 conditional_response=True,
                 conditional_etag=conditional_etag)
             response.headers['Content-Type'] = metadata.get(
                 'Content-Type', 'application/octet-stream')
             for key, value in metadata.iteritems():
                 if is_sys_or_user_meta('object', key) or \
                         key.lower() in self.allowed_headers:
                     response.headers[key] = value
             response.etag = metadata['ETag']
             response.last_modified = math.ceil(float(file_x_ts))
             response.content_length = obj_size
             try:
                 response.content_encoding = metadata['Content-Encoding']
             except KeyError:
                 pass
             response.headers['X-Timestamp'] = file_x_ts.normal
             response.headers['X-Backend-Timestamp'] = file_x_ts.internal
             resp = request.get_response(response)
     except DiskFileXattrNotSupported:
         return HTTPInsufficientStorage(drive=device, request=request)
     except (DiskFileNotExist, DiskFileQuarantined) as e:
         headers = {}
         if hasattr(e, 'timestamp'):
             headers['X-Backend-Timestamp'] = e.timestamp.internal
         resp = HTTPNotFound(request=request,
                             headers=headers,
                             conditional_response=True)
     return resp
Example #2
0
 def POST(self, request):
     """Handle HTTP POST requests for the Swift Object Server."""
     device, partition, account, container, obj, policy = \
         get_name_and_placement(request, 5, 5, True)
     req_timestamp = valid_timestamp(request)
     new_delete_at = int(request.headers.get('X-Delete-At') or 0)
     if new_delete_at and new_delete_at < time.time():
         return HTTPBadRequest(body='X-Delete-At in past', request=request,
                               content_type='text/plain')
     try:
         disk_file = self.get_diskfile(
             device, partition, account, container, obj,
             policy=policy)
     except DiskFileDeviceUnavailable:
         return HTTPInsufficientStorage(drive=device, request=request)
     try:
         orig_metadata = disk_file.read_metadata()
     except DiskFileXattrNotSupported:
         return HTTPInsufficientStorage(drive=device, request=request)
     except (DiskFileNotExist, DiskFileQuarantined):
         return HTTPNotFound(request=request)
     orig_timestamp = Timestamp(orig_metadata.get('X-Timestamp', 0))
     if orig_timestamp >= req_timestamp:
         return HTTPConflict(
             request=request,
             headers={'X-Backend-Timestamp': orig_timestamp.internal})
     metadata = {'X-Timestamp': req_timestamp.internal}
     self._preserve_slo_manifest(metadata, orig_metadata)
     metadata.update(val for val in request.headers.items()
                     if is_user_meta('object', val[0]))
     headers_to_copy = (
         request.headers.get(
             'X-Backend-Replication-Headers', '').split() +
         list(self.allowed_headers))
     for header_key in headers_to_copy:
         if header_key in request.headers:
             header_caps = header_key.title()
             metadata[header_caps] = request.headers[header_key]
     orig_delete_at = int(orig_metadata.get('X-Delete-At') or 0)
     if orig_delete_at != new_delete_at:
         if new_delete_at:
             self.delete_at_update('PUT', new_delete_at, account, container,
                                   obj, request, device, policy)
         if orig_delete_at:
             self.delete_at_update('DELETE', orig_delete_at, account,
                                   container, obj, request, device,
                                   policy)
     try:
         disk_file.write_metadata(metadata)
     except (DiskFileXattrNotSupported, DiskFileNoSpace):
         return HTTPInsufficientStorage(drive=device, request=request)
     return HTTPAccepted(request=request)
Example #3
0
 def HEAD(self, request):
     """Handle HTTP HEAD requests for the Swift Object Server."""
     device, partition, account, container, obj, policy = \
         get_name_and_placement(request, 5, 5, True)
     try:
         disk_file = self.get_diskfile(device,
                                       partition,
                                       account,
                                       container,
                                       obj,
                                       policy=policy)
     except DiskFileDeviceUnavailable:
         return HTTPInsufficientStorage(drive=device, request=request)
     try:
         metadata = disk_file.read_metadata()
     except DiskFileXattrNotSupported:
         return HTTPInsufficientStorage(drive=device, request=request)
     except (DiskFileNotExist, DiskFileQuarantined) as e:
         headers = {}
         if hasattr(e, 'timestamp'):
             headers['X-Backend-Timestamp'] = e.timestamp.internal
         return HTTPNotFound(request=request,
                             headers=headers,
                             conditional_response=True)
     conditional_etag = None
     if 'X-Backend-Etag-Is-At' in request.headers:
         conditional_etag = metadata.get(
             request.headers['X-Backend-Etag-Is-At'])
     response = Response(request=request,
                         conditional_response=True,
                         conditional_etag=conditional_etag)
     response.headers['Content-Type'] = metadata.get(
         'Content-Type', 'application/octet-stream')
     for key, value in metadata.iteritems():
         if is_sys_or_user_meta('object', key) or \
                 key.lower() in self.allowed_headers:
             response.headers[key] = value
     response.etag = metadata['ETag']
     ts = Timestamp(metadata['X-Timestamp'])
     response.last_modified = math.ceil(float(ts))
     # Needed for container sync feature
     response.headers['X-Timestamp'] = ts.normal
     response.headers['X-Backend-Timestamp'] = ts.internal
     response.content_length = int(metadata['Content-Length'])
     try:
         response.content_encoding = metadata['Content-Encoding']
     except KeyError:
         pass
     return response
Example #4
0
 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)
Example #5
0
 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)
     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
Example #6
0
 def HEAD(self, request):
     """Handle HTTP HEAD requests for the Swift Object Server."""
     device, partition, account, container, obj = \
         split_and_validate_path(request, 5, 5, True)
     try:
         disk_file = self._diskfile(device, partition, account, container,
                                    obj)
     except DiskFileDeviceUnavailable:
         return HTTPInsufficientStorage(drive=device, request=request)
     if disk_file.is_deleted() or disk_file.is_expired():
         return HTTPNotFound(request=request)
     try:
         file_size = disk_file.get_data_file_size()
     except (DiskFileError, DiskFileNotExist):
         disk_file.quarantine()
         return HTTPNotFound(request=request)
     response = Response(request=request, conditional_response=True)
     response.headers['Content-Type'] = disk_file.metadata.get(
         'Content-Type', 'application/octet-stream')
     for key, value in disk_file.metadata.iteritems():
         if key.lower().startswith('x-object-meta-') or \
                 key.lower() in self.allowed_headers:
             response.headers[key] = value
     response.etag = disk_file.metadata['ETag']
     response.last_modified = float(disk_file.metadata['X-Timestamp'])
     # Needed for container sync feature
     response.headers['X-Timestamp'] = disk_file.metadata['X-Timestamp']
     response.content_length = file_size
     if 'Content-Encoding' in disk_file.metadata:
         response.content_encoding = disk_file.metadata['Content-Encoding']
     return response
Example #7
0
 def DELETE(self, request):
     """Handle HTTP DELETE requests for the Swift Object Server."""
     device, partition, account, container, obj, policy_idx = \
         get_name_and_placement(request, 5, 5, True)
     if 'x-timestamp' not in request.headers or \
             not check_float(request.headers['x-timestamp']):
         return HTTPBadRequest(body='Missing timestamp', request=request,
                               content_type='text/plain')
     try:
         disk_file = self.get_diskfile(
             device, partition, account, container, obj,
             policy_idx=policy_idx)
     except DiskFileDeviceUnavailable:
         return HTTPInsufficientStorage(drive=device, request=request)
     try:
         orig_metadata = disk_file.read_metadata()
     except DiskFileExpired as e:
         orig_timestamp = e.timestamp
         orig_metadata = e.metadata
         response_class = HTTPNotFound
     except DiskFileDeleted as e:
         orig_timestamp = e.timestamp
         orig_metadata = {}
         response_class = HTTPNotFound
     except (DiskFileNotExist, DiskFileQuarantined):
         orig_timestamp = 0
         orig_metadata = {}
         response_class = HTTPNotFound
     else:
         orig_timestamp = orig_metadata.get('X-Timestamp', 0)
         if orig_timestamp < request.headers['x-timestamp']:
             response_class = HTTPNoContent
         else:
             response_class = HTTPConflict
     orig_delete_at = int(orig_metadata.get('X-Delete-At') or 0)
     try:
         req_if_delete_at_val = request.headers['x-if-delete-at']
         req_if_delete_at = int(req_if_delete_at_val)
     except KeyError:
         pass
     except ValueError:
         return HTTPBadRequest(
             request=request,
             body='Bad X-If-Delete-At header value')
     else:
         if orig_delete_at != req_if_delete_at:
             return HTTPPreconditionFailed(
                 request=request,
                 body='X-If-Delete-At and X-Delete-At do not match')
     if orig_delete_at:
         self.delete_at_update('DELETE', orig_delete_at, account,
                               container, obj, request, device)
     req_timestamp = request.headers['X-Timestamp']
     if orig_timestamp < req_timestamp:
         disk_file.delete(req_timestamp)
         self.container_update(
             'DELETE', account, container, obj, request,
             HeaderKeyDict({'x-timestamp': req_timestamp}),
             device, policy_idx)
     return response_class(request=request)
Example #8
0
 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 is_sys_or_user_meta('container', key)))
     headers['Content-Type'] = out_content_type
     return HTTPNoContent(request=req, headers=headers, charset='utf-8')
Example #9
0
 def HEAD(self, request):
     """Handle HTTP HEAD requests for the Swift Object Server."""
     device, partition, account, container, obj = \
         split_and_validate_path(request, 5, 5, True)
     try:
         disk_file = self.get_diskfile(
             device, partition, account, container, obj)
     except DiskFileDeviceUnavailable:
         return HTTPInsufficientStorage(drive=device, request=request)
     try:
         metadata = disk_file.read_metadata()
     except (DiskFileNotExist, DiskFileQuarantined):
         return HTTPNotFound(request=request, conditional_response=True)
     response = Response(request=request, conditional_response=True)
     response.headers['Content-Type'] = metadata.get(
         'Content-Type', 'application/octet-stream')
     for key, value in metadata.iteritems():
         if is_user_meta('object', key) or \
                 key.lower() in self.allowed_headers:
             response.headers[key] = value
     response.etag = metadata['ETag']
     ts = metadata['X-Timestamp']
     response.last_modified = math.ceil(float(ts))
     # Needed for container sync feature
     response.headers['X-Timestamp'] = ts
     response.content_length = int(metadata['Content-Length'])
     try:
         response.content_encoding = metadata['Content-Encoding']
     except KeyError:
         pass
     return response
Example #10
0
    def GET(self, req):
        """Handle HTTP GET request."""
        drive, part, account = split_and_validate_path(req, 3)
        prefix = get_param(req, 'prefix')
        delimiter = get_param(req, 'delimiter')
        limit = constraints.ACCOUNT_LISTING_LIMIT
        given_limit = get_param(req, 'limit')
        reverse = config_true_value(get_param(req, 'reverse'))
        if given_limit and given_limit.isdigit():
            limit = int(given_limit)
            if limit > constraints.ACCOUNT_LISTING_LIMIT:
                return HTTPPreconditionFailed(
                    request=req,
                    body='Maximum limit is %d' %
                    constraints.ACCOUNT_LISTING_LIMIT)
        marker = get_param(req, 'marker', '')
        end_marker = get_param(req, 'end_marker')
        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_account_broker(drive, part, account,
                                          pending_timeout=0.1,
                                          stale_reads_ok=True)
        if broker.is_deleted():
            return self._deleted_response(broker, req, HTTPNotFound)
        return account_listing_response(account, req, out_content_type, broker,
                                        limit, marker, end_marker, prefix,
                                        delimiter, reverse)
Example #11
0
    def GET(self, req):
        """Handle HTTP GET request."""
        drive, part, account = split_and_validate_path(req, 3)
        prefix = get_param(req, 'prefix')
        delimiter = get_param(req, 'delimiter')
        if delimiter and (len(delimiter) > 1 or ord(delimiter) > 254):
            # delimiters can be made more flexible later
            return HTTPPreconditionFailed(body='Bad delimiter')
        limit = constraints.ACCOUNT_LISTING_LIMIT
        given_limit = get_param(req, 'limit')
        if given_limit and given_limit.isdigit():
            limit = int(given_limit)
            if limit > constraints.ACCOUNT_LISTING_LIMIT:
                return HTTPPreconditionFailed(
                    request=req,
                    body='Maximum limit is %d' %
                    constraints.ACCOUNT_LISTING_LIMIT)
        marker = get_param(req, 'marker', '')
        end_marker = get_param(req, 'end_marker')
        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)
        return account_listing_response(account, req, out_content_type, broker,
                                        limit, marker, end_marker, prefix,
                                        delimiter)
Example #12
0
    def GET(self, req):
        """Handle HTTP GET request."""
        drive, part, account = get_account_name_and_placement(req)
        prefix = get_param(req, 'prefix')
        delimiter = get_param(req, 'delimiter')
        reverse = config_true_value(get_param(req, 'reverse'))
        limit = constrain_req_limit(req, constraints.ACCOUNT_LISTING_LIMIT)
        marker = get_param(req, 'marker', '')
        end_marker = get_param(req, 'end_marker')
        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_account_broker(drive,
                                          part,
                                          account,
                                          pending_timeout=0.1,
                                          stale_reads_ok=True)
        if broker.is_deleted():
            return self._deleted_response(broker, req, HTTPNotFound)
        return account_listing_response(account, req, out_content_type, broker,
                                        limit, marker, end_marker, prefix,
                                        delimiter, reverse)
Example #13
0
 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 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)
     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)
Example #14
0
 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 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)
     return HTTPNoContent(request=req)
Example #15
0
 def HEAD(self, req):
     """Handle HTTP HEAD request."""
     #logging.info("...head...")
     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)
     info = broker.get_info()
     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']
     }
     headers.update(
         (key, value)
         for key, (value, timestamp) in broker.metadata.iteritems()
         if value != '')
     headers['Content-Type'] = out_content_type
     return HTTPNoContent(request=req, headers=headers, charset='utf-8')
Example #16
0
 def HEAD(self, req):
     """Handle HTTP HEAD request."""
     drive, part, account, container, obj = get_obj_name_and_placement(req)
     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(
         (str_to_wsgi(key), str_to_wsgi(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
Example #17
0
 def PUT(self, req):
     try:
         return server.ContainerController.PUT(self, req)
     except DiskFileNoSpace:
         # As container==directory in the File connector, we might run outi
         # of space or exceed quota when creating containers.
         drive = req.split_path(1, 1, True)
         return HTTPInsufficientStorage(drive=drive, request=req)
Example #18
0
 def GET(self, request):
     """Handle HTTP GET requests for the Swift Object Server."""
     device, partition, account, container, obj = \
         split_and_validate_path(request, 5, 5, True)
     keep_cache = self.keep_cache_private or (
         'X-Auth-Token' not in request.headers
         and 'X-Storage-Token' not in request.headers)
     try:
         disk_file = self.get_diskfile(device, partition, account,
                                       container, obj)
     except DiskFileDeviceUnavailable:
         return HTTPInsufficientStorage(drive=device, request=request)
     try:
         with disk_file.open():
             metadata = disk_file.get_metadata()
             obj_size = int(metadata['Content-Length'])
             file_x_ts = metadata['X-Timestamp']
             file_x_ts_flt = float(file_x_ts)
             try:
                 if_unmodified_since = request.if_unmodified_since
             except (OverflowError, ValueError):
                 # catches timestamps before the epoch
                 return HTTPPreconditionFailed(request=request)
             file_x_ts_utc = datetime.fromtimestamp(file_x_ts_flt, UTC)
             if if_unmodified_since and file_x_ts_utc > if_unmodified_since:
                 return HTTPPreconditionFailed(request=request)
             try:
                 if_modified_since = request.if_modified_since
             except (OverflowError, ValueError):
                 # catches timestamps before the epoch
                 return HTTPPreconditionFailed(request=request)
             if if_modified_since and file_x_ts_utc <= if_modified_since:
                 return HTTPNotModified(request=request)
             keep_cache = (self.keep_cache_private or
                           ('X-Auth-Token' not in request.headers
                            and 'X-Storage-Token' not in request.headers))
             response = Response(
                 app_iter=disk_file.reader(keep_cache=keep_cache),
                 request=request,
                 conditional_response=True)
             response.headers['Content-Type'] = metadata.get(
                 'Content-Type', 'application/octet-stream')
             for key, value in metadata.iteritems():
                 if is_user_meta('object', key) or \
                         key.lower() in self.allowed_headers:
                     response.headers[key] = value
             response.etag = metadata['ETag']
             response.last_modified = math.ceil(file_x_ts_flt)
             response.content_length = obj_size
             try:
                 response.content_encoding = metadata['Content-Encoding']
             except KeyError:
                 pass
             response.headers['X-Timestamp'] = file_x_ts
             resp = request.get_response(response)
     except (DiskFileNotExist, DiskFileQuarantined):
         resp = HTTPNotFound(request=request, conditional_response=True)
     return resp
Example #19
0
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)
Example #20
0
 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)
Example #21
0
 def REPLICATE(self, req):
     """
     Handle HTTP REPLICATE request (json-encoded RPC calls for replication.)
     """
     post_args = split_and_validate_path(req, 3)
     drive, partition, hash = post_args
     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)
     try:
         args = json.load(req.environ['wsgi.input'])
     except ValueError as err:
         return HTTPBadRequest(body=str(err), content_type='text/plain')
     ret = self.replicator_rpc.dispatch(post_args, args)
     ret.request = req
     return ret
Example #22
0
 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)
     metadata = {}
     metadata.update((key, (value, req_timestamp.internal))
                     for key, value in req.headers.items()
                     if is_sys_or_user_meta('account', key))
     if metadata:
         broker.update_metadata(metadata, validate_metadata=True)
     return HTTPNoContent(request=req)
Example #23
0
 def DELETE(self, req):
     """Handle HTTP DELETE request."""
     drive, part, account = split_and_validate_path(req, 3)
     if self.mount_check and not check_mount(self.root, drive):
         return HTTPInsufficientStorage(drive=drive, request=req)
     req_timestamp = valid_timestamp(req)
     broker = self._get_account_broker(drive, part, account)
     if broker.is_deleted():
         return self._deleted_response(broker, req, HTTPNotFound)
     broker.delete_db(req_timestamp.internal)
     return self._deleted_response(broker, req, HTTPNoContent)
Example #24
0
 def REPLICATE(self, req):
     """
     Handle HTTP REPLICATE request (json-encoded RPC calls for replication.)
     """
     post_args = split_and_validate_path(req, 3)
     drive, partition, hash = post_args
     if self.mount_check and not check_mount(self.root, drive):
         return HTTPInsufficientStorage(drive=drive, request=req)
     try:
         args = json.load(req.environ['wsgi.input'])
     except ValueError, err:
         return HTTPBadRequest(body=str(err), content_type='text/plain')
Example #25
0
 def PUT(self, req):
     """Handle HTTP PUT 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 '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 self.mount_check and not check_mount(self.root, drive):
         return HTTPInsufficientStorage(drive=drive, request=req)
     timestamp = normalize_timestamp(req.headers['x-timestamp'])
     broker = self._get_container_broker(drive, part, account, container)
     if obj:     # put container object
         if account.startswith(self.auto_create_account_prefix) and \
                 not os.path.exists(broker.db_file):
             try:
                 broker.initialize(timestamp)
             except DatabaseAlreadyExists:
                 pass
         if not os.path.exists(broker.db_file):
             return HTTPNotFound()
         broker.put_object(obj, timestamp, int(req.headers['x-size']),
                           req.headers['x-content-type'],
                           req.headers['x-etag'])
         return HTTPCreated(request=req)
     else:   # put container
         created = self._update_or_create(req, broker, timestamp)
         metadata = {}
         metadata.update(
             (key, (value, timestamp))
             for key, value in req.headers.iteritems()
             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)
         resp = self.account_update(req, account, container, broker)
         if resp:
             return resp
         if created:
             return HTTPCreated(request=req)
         else:
             return HTTPAccepted(request=req)
Example #26
0
 def POST(self, req):
     """Handle HTTP POST request."""
     drive, part, account, container = get_container_name_and_placement(req)
     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)
     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_container_broker(drive, part, account, container)
     if broker.is_deleted():
         return HTTPNotFound(request=req)
     broker.update_put_timestamp(req_timestamp.internal)
     self._update_metadata(req, broker, req_timestamp, 'POST')
     return HTTPNoContent(request=req)
Example #27
0
 def DELETE(self, req):
     """Handle HTTP DELETE request."""
     drive, part, account = get_account_name_and_placement(req)
     try:
         check_drive(self.root, drive, self.mount_check)
     except ValueError:
         return HTTPInsufficientStorage(drive=drive, request=req)
     req_timestamp = valid_timestamp(req)
     broker = self._get_account_broker(drive, part, account)
     if broker.is_deleted():
         return self._deleted_response(broker, req, HTTPNotFound)
     broker.delete_db(req_timestamp.internal)
     return self._deleted_response(broker, req, HTTPNoContent)
Example #28
0
    def UPDATE(self, req):
        """
        Handle HTTP UPDATE request (merge_items RPCs coming from the proxy.)
        """
        drive, part, account, container = get_container_name_and_placement(req)
        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)

        requested_policy_index = self.get_and_validate_policy_index(req)
        broker = self._get_container_broker(drive, part, account, container)
        self._maybe_autocreate(broker, req_timestamp, account,
                               requested_policy_index)
        try:
            objs = json.load(req.environ['wsgi.input'])
        except ValueError as err:
            return HTTPBadRequest(body=str(err), content_type='text/plain')
        broker.merge_items(objs)
        return HTTPAccepted(request=req)
Example #29
0
 def DELETE(self, req):
     """Handle HTTP DELETE request."""
     drive, part, account = split_and_validate_path(req, 3)
     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 self._deleted_response(broker, req, HTTPNotFound)
     broker.delete_db(req.headers['x-timestamp'])
     return self._deleted_response(broker, req, HTTPNoContent)
Example #30
0
 def REPLICATE(self, request):
     """
     Handle REPLICATE requests for the Swift Object Server.  This is used
     by the object replicator to get hashes for directories.
     """
     device, partition, suffix = split_and_validate_path(
         request, 2, 3, True)
     try:
         hashes = self._diskfile_mgr.get_hashes(device, partition, suffix)
     except DiskFileDeviceUnavailable:
         resp = HTTPInsufficientStorage(drive=device, request=request)
     else:
         resp = Response(body=pickle.dumps(hashes))
     return resp