Beispiel #1
0
 def handle_request(self):
     if hasattr(self, self.request.method):
         try:
             handler = getattr(self, self.request.method)
             getattr(handler, 'publicly_accessible')
         except AttributeError:
             # TODO(kota_): add allowed_method list to Allow header
             return HTTPMethodNotAllowed(request=self.request)
         return handler()
     else:
         raise HTTPMethodNotAllowed(request=self.request)
Beispiel #2
0
 def DELETE(self, req):
     """HTTP DELETE request handler."""
     # Extra safety in case someone typos a query string for an
     # account-level DELETE request that was really meant to be caught by
     # some middleware.
     if req.query_string:
         return HTTPBadRequest(request=req)
     if not self.app.allow_account_management:
         return HTTPMethodNotAllowed(
             request=req,
             headers={'Allow': ', '.join(self.allowed_methods)})
     account_partition, accounts = \
         self.app.account_ring.get_nodes(self.account_name)
     headers = {
         'X-Timestamp': normalize_timestamp(time.time()),
         'X-Trans-Id': self.trans_id,
         'Connection': 'close'
     }
     if self.app.memcache:
         self.app.memcache.delete(
             get_account_memcache_key(self.account_name))
     resp = self.make_requests(req, self.app.account_ring,
                               account_partition, 'DELETE', req.path_info,
                               [headers] * len(accounts))
     return resp
Beispiel #3
0
    def handle_request(self, env, req):
        if req.method not in ('GET', 'HEAD'):
            headers = self._getCacheHeaders(CACHE_BAD_URL)
            return HTTPMethodNotAllowed(request=req, headers=headers)
        if self.allowed_origin_remote_ips and \
                req.remote_addr not in self.allowed_origin_remote_ips:
            raise OriginRequestNotAllowed(
                'SOS Origin: Remote IP %s not allowed' % req.remote_addr)

        # allow earlier middleware to override hash and obj_name
        hsh = env.get('swift.cdn_hash')
        object_name = env.get('swift.cdn_object_name')
        if hsh is None or object_name is None:
            for regex in self.cdn_regexes:
                match_obj = regex.match(req.url)
                if match_obj:
                    match_dict = match_obj.groupdict()
                    if not hsh:
                        hsh = match_dict.get('hash')
                    if not object_name:
                        object_name = match_dict.get('object_name')
                    break
        if not hsh:
            self.logger.debug('Hash %s not found in %s' % (hsh, req.url))
            headers = self._getCacheHeaders(CACHE_BAD_URL)
            return HTTPNotFound(request=req, headers=headers)
        if hsh.find('-') >= 0:
            hsh = hsh.split('-', 1)[1]
        try:
            cdn_obj_path = self.get_hsh_obj_path(hsh)
        except ValueError, e:
            self.logger.debug('get_hsh_obj_path error: %s' % e)
            headers = self._getCacheHeaders(CACHE_BAD_URL)
            return HTTPBadRequest(request=req, headers=headers)
Beispiel #4
0
 def __call__(self, env, start_response):
     start_time = time.time()
     req = Request(env)
     self.logger.txn_id = req.headers.get('x-trans-id', None)
     if not check_utf8(req.path_info):
         res = HTTPPreconditionFailed(body='Invalid UTF8 or contains NULL')
     else:
         try:
             # disallow methods which have not been marked 'public'
             try:
                 method = getattr(self, req.method)
                 getattr(method, 'publicly_accessible')
                 replication_method = getattr(method, 'replication', False)
                 if (self.replication_server is not None and
                         self.replication_server != replication_method):
                     raise AttributeError('Not allowed method.')
             except AttributeError:
                 res = HTTPMethodNotAllowed()
             else:
                 res = method(req)
         except HTTPException as error_response:
             res = error_response
         except (Exception, Timeout):
             self.logger.exception(_(
                 'ERROR __call__ error with %(method)s %(path)s '),
                 {'method': req.method, 'path': req.path})
             res = HTTPInternalServerError(body=traceback.format_exc())
     if self.log_requests:
         trans_time = time.time() - start_time
         log_message = get_log_line(req, res, trans_time, '')
         if req.method.upper() == 'REPLICATE':
             self.logger.debug(log_message)
         else:
             self.logger.info(log_message)
     return res(env, start_response)
Beispiel #5
0
 def __call__(self, env, start_response):
     start_time = time.time()
     req = Request(env)
     self.logger.txn_id = req.headers.get('x-trans-id', None)
     if not check_utf8(req.path_info):
         res = HTTPPreconditionFailed(body='Invalid UTF8')
     else:
         try:
             # disallow methods which have not been marked 'public'
             try:
                 method = getattr(self, req.method)
                 getattr(method, 'publicly_accessible')
             except AttributeError:
                 res = HTTPMethodNotAllowed()
             else:
                 res = method(req)
         except (Exception, Timeout):
             self.logger.exception(
                 _('ERROR __call__ error with %(method)s %(path)s '), {
                     'method': req.method,
                     'path': req.path
                 })
             res = HTTPInternalServerError(body=traceback.format_exc())
     trans_time = '%.4f' % (time.time() - start_time)
     log_message = '%s - - [%s] "%s %s" %s %s "%s" "%s" "%s" %s' % (
         req.remote_addr,
         time.strftime('%d/%b/%Y:%H:%M:%S +0000', time.gmtime()),
         req.method, req.path, res.status.split()[0], res.content_length
         or '-', req.headers.get('x-trans-id', '-'), req.referer
         or '-', req.user_agent or '-', trans_time)
     if req.method.upper() == 'REPLICATE':
         self.logger.debug(log_message)
     else:
         self.logger.info(log_message)
     return res(env, start_response)
Beispiel #6
0
 def __call__(self, env, start_response):
     start_time = time.time()
     req = Request(env)
     self.logger.txn_id = req.headers.get('x-trans-id', None)
     if not check_utf8(req.path_info):
         res = HTTPPreconditionFailed(body='Invalid UTF8 or contains NULL')
     else:
         try:
             # disallow methods which are not publicly accessible
             if req.method not in self.allowed_methods:
                 res = HTTPMethodNotAllowed()
             else:
                 res = getattr(self, req.method)(req)
         except HTTPException as error_response:
             res = error_response
         except (Exception, Timeout):
             self.logger.exception(
                 _('ERROR __call__ error with %(method)s'
                   ' %(path)s '), {
                       'method': req.method,
                       'path': req.path
                   })
             res = HTTPInternalServerError(body=traceback.format_exc())
     if self.log_requests:
         trans_time = time.time() - start_time
         additional_info = ''
         if res.headers.get('x-container-timestamp') is not None:
             additional_info += 'x-container-timestamp: %s' % \
                 res.headers['x-container-timestamp']
         log_msg = get_log_line(req, res, trans_time, additional_info)
         if req.method.upper() == 'REPLICATE':
             self.logger.debug(log_msg)
         else:
             self.logger.info(log_msg)
     return res(env, start_response)
    def __call__(self, env, start_response):
        request = Request(env)
        if not request.path.startswith(self.endpoints_path):
            return self.app(env, start_response)

        if request.method != 'GET':
            return HTTPMethodNotAllowed(req=request,
                                        headers={"Allow":
                                                 "GET"})(env, start_response)

        try:
            version, account, container, obj = self._parse_path(request)
        except ValueError as err:
            return HTTPBadRequest(str(err))(env, start_response)

        if account is not None:
            account = unquote(account)
        if container is not None:
            container = unquote(container)
        if obj is not None:
            obj = unquote(obj)

        storage_policy_index = None
        if obj is not None:
            container_info = get_container_info(
                {'PATH_INFO': '/v1/%s/%s' % (account, container)},
                self.app,
                swift_source='LE')
            storage_policy_index = container_info['storage_policy']
            obj_ring = self.get_object_ring(storage_policy_index)
            partition, nodes = obj_ring.get_nodes(account, container, obj)
            endpoint_template = 'http://{ip}:{port}/{device}/{partition}/' + \
                                '{account}/{container}/{obj}'
        elif container is not None:
            partition, nodes = self.container_ring.get_nodes(
                account, container)
            endpoint_template = 'http://{ip}:{port}/{device}/{partition}/' + \
                                '{account}/{container}'
        else:
            partition, nodes = self.account_ring.get_nodes(account)
            endpoint_template = 'http://{ip}:{port}/{device}/{partition}/' + \
                                '{account}'

        endpoints = []
        for node in nodes:
            endpoint = endpoint_template.format(ip=node['ip'],
                                                port=node['port'],
                                                device=node['device'],
                                                partition=partition,
                                                account=quote(account),
                                                container=quote(container
                                                                or ''),
                                                obj=quote(obj or ''))
            endpoints.append(endpoint)

        resp = self.response_map[version](
            request,
            endpoints=endpoints,
            storage_policy_index=storage_policy_index)
        return resp(env, start_response)
Beispiel #8
0
 def PUT(self, req):
     """HTTP PUT request handler."""
     if not self.app.allow_account_management:
         return HTTPMethodNotAllowed(
             request=req,
             headers={'Allow': ', '.join(self.allowed_methods)})
     error_response = check_metadata(req, 'account')
     if error_response:
         return error_response
     if len(self.account_name) > MAX_ACCOUNT_NAME_LENGTH:
         resp = HTTPBadRequest(request=req)
         resp.body = 'Account name length of %d longer than %d' % \
                     (len(self.account_name), MAX_ACCOUNT_NAME_LENGTH)
         return resp
     account_partition, accounts = \
         self.app.account_ring.get_nodes(self.account_name)
     headers = {
         'X-Timestamp': normalize_timestamp(time.time()),
         'x-trans-id': self.trans_id,
         'Connection': 'close'
     }
     self.transfer_headers(req.headers, headers)
     if self.app.memcache:
         self.app.memcache.delete(
             get_account_memcache_key(self.account_name))
     resp = self.make_requests(req, self.app.account_ring,
                               account_partition, 'PUT', req.path_info,
                               [headers] * len(accounts))
     return resp
Beispiel #9
0
    def handle_request(self, req):
        """
        Entry point for auth requests (ones that match the self.auth_prefix).
        Should return a WSGI-style callable (such as swob.Response).

        :param req: swob.Request object
        """
        req.start_time = time()
        handler = None
        if req.method != 'GET':
            req.response = HTTPMethodNotAllowed(request=req)
            return req.response
        try:
            version, account, user, _junk = split_path(req.path_info, 1, 4,
                                                       True)
        except ValueError:
            self.logger.increment('errors')
            return HTTPNotFound(request=req)
        if version in ('v1', 'v1.0', 'auth'):
            if req.method == 'GET':
                handler = self.handle_get_token
        if not handler:
            self.logger.increment('errors')
            req.response = HTTPBadRequest(request=req)
        else:
            req.response = handler(req)
        return req.response
Beispiel #10
0
 def __call__(self, env, start_response):
     start_time = time.time()
     req = Request(env)
     self.logger.txn_id = req.headers.get('x-trans-id', None)
     if not check_utf8(wsgi_to_str(req.path_info), internal=True):
         res = HTTPPreconditionFailed(body='Invalid UTF8 or contains NULL')
     else:
         try:
             # disallow methods which have not been marked 'public'
             if req.method not in self.allowed_methods:
                 res = HTTPMethodNotAllowed()
             else:
                 res = getattr(self, req.method)(req)
         except HTTPException as error_response:
             res = error_response
         except (Exception, Timeout):
             self.logger.exception(
                 _('ERROR __call__ error with %(method)s %(path)s '), {
                     'method': req.method,
                     'path': req.path
                 })
             res = HTTPInternalServerError(body=traceback.format_exc())
     if self.log_requests:
         trans_time = time.time() - start_time
         log_message = get_log_line(req, res, trans_time, '',
                                    self.log_format,
                                    self.anonymization_method,
                                    self.anonymization_salt)
         if req.method.upper() == 'REPLICATE':
             self.logger.debug(log_message)
         else:
             self.logger.info(log_message)
     return res(env, start_response)
Beispiel #11
0
 def PUT(self, req):
     """HTTP PUT request handler."""
     if not self.app.allow_account_management:
         return HTTPMethodNotAllowed(
             request=req,
             headers={'Allow': ', '.join(self.allowed_methods)})
     error_response = check_metadata(req, 'account')
     if error_response:
         return error_response
     if len(self.account_name) > constraints.MAX_ACCOUNT_NAME_LENGTH:
         resp = HTTPBadRequest(request=req)
         resp.body = 'Account name length of %d longer than %d' % \
                     (len(self.account_name),
                      constraints.MAX_ACCOUNT_NAME_LENGTH)
         return resp
     account_partition, accounts = \
         self.app.account_ring.get_nodes(self.account_name)
     headers = self.generate_request_headers(req, transfer=True)
     clear_info_cache(self.app, req.environ, self.account_name)
     resp = self.make_requests(req, self.app.account_ring,
                               account_partition, 'PUT',
                               req.swift_entity_path,
                               [headers] * len(accounts))
     self.add_acls_from_sys_metadata(resp)
     return resp
Beispiel #12
0
    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)
Beispiel #13
0
 def handle_request(self):
     if hasattr(self, self.request.method) and self.is_valid_request:
         try:
             handler = getattr(self, self.request.method)
             getattr(handler, 'publicly_accessible')
         except AttributeError:
             return HTTPMethodNotAllowed(request=self.request)
         return handler()
     else:
         return self.request.get_response(self.app)
Beispiel #14
0
 def get_handler(self, controller, req):
     try:
         handler = getattr(controller, req.method)
         getattr(handler, 'publicly_accessible')
     except AttributeError:
         allowed_methods = getattr(controller, 'allowed_methods', set())
         return HTTPMethodNotAllowed(
             request=req,
             headers={'Allow': ', '.join(allowed_methods)})
     else:
         return handler(req)
Beispiel #15
0
 def _not_allowed_wrapper(self, req, *args, **kwargs):
     try:
         return fnc(self, req, *args, **kwargs)
     except MethodNotAllowed as exc:
         headers = dict()
         if 'worm' in exc.message.lower():
             headers['Allow'] = 'GET, HEAD, PUT'
         else:
             # TODO(FVE): load Allow header from exception attributes
             pass
         return HTTPMethodNotAllowed(request=req, headers=headers)
Beispiel #16
0
    def __call__(self, env, start_response):
        request = Request(env)

        if not request.path.startswith(self.endpoints_path):
            return self.app(env, start_response)

        if request.method != 'GET':
            return HTTPMethodNotAllowed(req=request,
                                        headers={"Allow":
                                                 "GET"})(env, start_response)

        try:
            clean_path = request.path[len(self.endpoints_path) - 1:]
            account, container, obj = \
                split_path(clean_path, 1, 3, True)
        except ValueError:
            return HTTPBadRequest('No account specified')(env, start_response)

        if account is not None:
            account = unquote(account)
        if container is not None:
            container = unquote(container)
        if obj is not None:
            obj = unquote(obj)

        if obj is not None:
            partition, nodes = self.object_ring.get_nodes(
                account, container, obj)
            endpoint_template = 'http://{ip}:{port}/{device}/{partition}/' + \
                                '{account}/{container}/{obj}'
        elif container is not None:
            partition, nodes = self.container_ring.get_nodes(
                account, container)
            endpoint_template = 'http://{ip}:{port}/{device}/{partition}/' + \
                                '{account}/{container}'
        else:
            partition, nodes = self.account_ring.get_nodes(account)
            endpoint_template = 'http://{ip}:{port}/{device}/{partition}/' + \
                                '{account}'

        endpoints = []
        for node in nodes:
            endpoint = endpoint_template.format(ip=node['ip'],
                                                port=node['port'],
                                                device=node['device'],
                                                partition=partition,
                                                account=quote(account),
                                                container=quote(container
                                                                or ''),
                                                obj=quote(obj or ''))
            endpoints.append(endpoint)

        return Response(json.dumps(endpoints),
                        content_type='application/json')(env, start_response)
Beispiel #17
0
 def handle_request(self):
     if self.is_crystal_valid_request and hasattr(self,
                                                  self.request.method):
         try:
             handler = getattr(self, self.request.method)
             getattr(handler, 'publicly_accessible')
         except AttributeError:
             return HTTPMethodNotAllowed(request=self.request)
         return handler()
     else:
         self.logger.info('Request disabled for Crystal')
         return self.request.get_response(self.app)
Beispiel #18
0
 def DELETE(self, req):
     """HTTP DELETE request handler."""
     if req.query_string:
         return HTTPBadRequest(request=req)
     if not self.app.allow_account_management:
         return HTTPMethodNotAllowed(
             request=req,
             headers={'Allow': ', '.join(self.allowed_methods)})
     headers = self.generate_request_headers(req)
     clear_info_cache(self.app, req.environ, self.account_name)
     resp = self.get_account_delete_resp(req, headers)
     return resp
Beispiel #19
0
    def __call__(self, env, start_response):
        """WSGI Application entry point for the Swift Object Server."""
        start_time = time.time()
        req = Request(env)
        self.logger.txn_id = req.headers.get('x-trans-id', None)

        if not check_utf8(req.path_info):
            res = HTTPPreconditionFailed(body='Invalid UTF8 or contains NULL')
        else:
            try:
                # disallow methods which have not been marked 'public'
                try:
                    method = getattr(self, req.method)
                    getattr(method, 'publicly_accessible')
                    replication_method = getattr(method, 'replication', False)
                    if (self.replication_server is not None and
                            self.replication_server != replication_method):
                        raise AttributeError('Not allowed method.')
                except AttributeError:
                    res = HTTPMethodNotAllowed()
                else:
                    res = method(req)
            except DiskFileCollision:
                res = HTTPForbidden(request=req)
            except HTTPException as error_response:
                res = error_response
            except (Exception, Timeout):
                self.logger.exception(_(
                    'ERROR __call__ error with %(method)s'
                    ' %(path)s '), {'method': req.method, 'path': req.path})
                res = HTTPInternalServerError(body=traceback.format_exc())
        trans_time = time.time() - start_time
        if self.log_requests:
            log_line = '%s - - [%s] "%s %s" %s %s "%s" "%s" "%s" %.4f' % (
                req.remote_addr,
                time.strftime('%d/%b/%Y:%H:%M:%S +0000',
                              time.gmtime()),
                req.method, req.path, res.status.split()[0],
                res.content_length or '-', req.referer or '-',
                req.headers.get('x-trans-id', '-'),
                req.user_agent or '-',
                trans_time)
            if req.method in ('REPLICATE', 'REPLICATION') or \
                    'X-Backend-Replication' in req.headers:
                self.logger.debug(log_line)
            else:
                self.logger.info(log_line)
        if req.method in ('PUT', 'DELETE'):
            slow = self.slow - trans_time
            if slow > 0:
                sleep(slow)
        return res(env, start_response)
Beispiel #20
0
 def __call__(self, env, start_response):
     """
     Boilerplate code for how the server's code gets called
     upon receiving a request.
     Taken directly from other servers.
     """
     # start_time = time.time()
     req = Request(env)
     self.logger.txn_id = req.headers.get('x-trans-id', None)
     if not check_utf8(req.path_info):
         res = HTTPPreconditionFailed(body='Invalid UTF8 or contains NULL')
     else:
         try:
             # disallow methods which have not been marked 'public'
             try:
                 method = getattr(self, req.method)
                 getattr(method, 'publicly_accessible')
                 replication_method = getattr(method, 'replication', False)
                 if (self.replication_server is not None
                         and self.replication_server != replication_method):
                     raise AttributeError('Not allowed method.')
             except AttributeError:
                 res = HTTPMethodNotAllowed()
             else:
                 res = method(req)
         except HTTPException as error_response:
             res = error_response
         except (Exception, Timeout):
             self.logger.exception(
                 _('ERROR __call__ error with %(method)s %(path)s '), {
                     'method': req.method,
                     'path': req.path
                 })
             res = HTTPInternalServerError(body=traceback.format_exc())
     # trans_time = '%.4f' % (time.time() - start_time)
     # if self.log_requests:
     #     log_message = '%s - - [%s] "%s %s" %s %s "%s" "%s" "%s" %s' % (
     #         req.remote_addr,
     #         time.strftime('%d/%b/%Y:%H:%M:%S +0000',
     #                       time.gmtime()),
     #         req.method, req.path,
     #         res.status.split()[0], res.content_length or '-',
     #         req.headers.get('x-trans-id', '-'),
     #         req.referer or '-', req.user_agent or '-',
     #         trans_time)
     #     if req.method.upper() == 'REPLICATE':
     #         self.logger.debug(log_message)
     #     else:
     #         self.logger.info(log_message)
     return res(env, start_response)
Beispiel #21
0
    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)
Beispiel #22
0
def create_error_response(error, message):
    if error == 400:
        response = HTTPBadRequest(body=message)
    elif error == 401:
        response = HTTPUnauthorized(body=message)
    elif error == 403:
        response = HTTPForbidden(body=message)
    elif error == 404:
        response = HTTPNotFound(body=message)
    elif error == 405:
        response = HTTPMethodNotAllowed(body=message)
    else:
        response = HTTPServerError(body=message)

    return response
Beispiel #23
0
 def DELETE(self, req):
     """HTTP DELETE request handler."""
     if not self.app.allow_account_management:
         return HTTPMethodNotAllowed(request=req)
     account_partition, accounts = \
         self.app.account_ring.get_nodes(self.account_name)
     headers = {'X-Timestamp': normalize_timestamp(time.time()),
                'X-Trans-Id': self.trans_id,
                'Connection': 'close'}
     if self.app.memcache:
         self.app.memcache.delete('account%s' % req.path_info.rstrip('/'))
     resp = self.make_requests(req, self.app.account_ring,
         account_partition, 'DELETE', req.path_info,
         [headers] * len(accounts))
     return resp
Beispiel #24
0
 def __call__(self, env, start_response):
     print "account server __call__"
     start_time = time.time()
     req = Request(env)
     self.logger.txn_id = req.headers.get('x-trans-id', None)
     if not check_utf8(req.path_info):
         res = HTTPPreconditionFailed(body='Invalid UTF8 or contains NULL')
     else:
         try:
             # disallow methods which are not publicly accessible
             try:
                 method = getattr(self, req.method)
                 getattr(method, 'publicly_accessible')
                 replication_method = getattr(method, 'replication', False)
                 if (self.replication_server is not None
                         and self.replication_server != replication_method):
                     raise AttributeError('Not allowed method.')
             except AttributeError:
                 res = HTTPMethodNotAllowed()
             else:
                 res = method(req)
         except HTTPException as error_response:
             res = error_response
         except (Exception, Timeout):
             self.logger.exception(
                 _('ERROR __call__ error with %(method)s'
                   ' %(path)s '), {
                       'method': req.method,
                       'path': req.path
                   })
             res = HTTPInternalServerError(body=traceback.format_exc())
     trans_time = '%.4f' % (time.time() - start_time)
     additional_info = ''
     if res.headers.get('x-container-timestamp') is not None:
         additional_info += 'x-container-timestamp: %s' % \
             res.headers['x-container-timestamp']
     log_message = '%s - - [%s] "%s %s" %s %s "%s" "%s" "%s" %s "%s"' % (
         req.remote_addr,
         time.strftime('%d/%b/%Y:%H:%M:%S +0000', time.gmtime()),
         req.method, req.path, res.status.split()[0], res.content_length
         or '-', req.headers.get('x-trans-id', '-'), req.referer
         or '-', req.user_agent or '-', trans_time, additional_info)
     if req.method.upper() == 'REPLICATE':
         self.logger.debug(log_message)
     else:
         self.logger.info(log_message)
     return res(env, start_response)
Beispiel #25
0
    def __call__(self, env, start_response):
        """WSGI Application entry point for the Swift Object Server."""
        start_time = time.time()
        req = Request(env)
        self.logger.txn_id = req.headers.get('x-trans-id', None)

        if not check_utf8(req.path_info):
            res = HTTPPreconditionFailed(body='Invalid UTF8 or contains NULL')
        else:
            try:
                # disallow methods which have not been marked 'public'
                try:
                    method = getattr(self, req.method)
                    getattr(method, 'publicly_accessible')
                    replication_method = getattr(method, 'replication', False)
                    if (self.replication_server is not None and
                            self.replication_server != replication_method):
                        raise AttributeError('Not allowed method.')
                except AttributeError:
                    res = HTTPMethodNotAllowed()
                else:
                    res = method(req)
            except DiskFileCollision:
                res = HTTPForbidden(request=req)
            except HTTPException as error_response:
                res = error_response
            except (Exception, Timeout):
                self.logger.exception(_(
                    'ERROR __call__ error with %(method)s'
                    ' %(path)s '), {'method': req.method, 'path': req.path})
                res = HTTPInternalServerError(body=traceback.format_exc())
        trans_time = time.time() - start_time
        if self.log_requests:
            log_line = get_log_line(req, res, trans_time, '')
            if req.method in ('REPLICATE', 'REPLICATION') or \
                    'X-Backend-Replication' in req.headers:
                self.logger.debug(log_line)
            else:
                self.logger.info(log_line)
        if req.method in ('PUT', 'DELETE'):
            slow = self.slow - trans_time
            if slow > 0:
                sleep(slow)
	my_debug('returning from __call__ or objserver', res)
	my_debug('returnign from __call__ of objserver', start_response)
        return res(env, start_response)
Beispiel #26
0
 def DELETE(self, req):
     """HTTP DELETE request handler."""
     # Extra safety in case someone typos a query string for an
     # account-level DELETE request that was really meant to be caught by
     # some middleware.
     if req.query_string:
         return HTTPBadRequest(request=req)
     if not self.app.allow_account_management:
         return HTTPMethodNotAllowed(
             request=req,
             headers={'Allow': ', '.join(self.allowed_methods)})
     account_partition, accounts = \
         self.app.account_ring.get_nodes(self.account_name)
     headers = self.generate_request_headers(req)
     clear_info_cache(self.app, req.environ, self.account_name)
     resp = self.make_requests(req, self.app.account_ring,
                               account_partition, 'DELETE', req.path_info,
                               [headers] * len(accounts))
     return resp
Beispiel #27
0
    def __call__(self, env, start_response):
        req = Request(env)

        if req.method not in self.write_methods:
            return self.app(env, start_response)

        try:
            version, account, container, obj = req.split_path(1, 4, True)
        except ValueError:
            return self.app(env, start_response)

        if req.method == 'COPY' and 'Destination-Account' in req.headers:
            dest_account = req.headers.get('Destination-Account')
            account = check_account_format(req, dest_account)

        if self.account_read_only(req, account):
            msg = 'Writes are disabled for this account.'
            return HTTPMethodNotAllowed(body=msg)(env, start_response)

        return self.app(env, start_response)
Beispiel #28
0
    def PUT(self, req):
        """HTTP PUT request handler."""
        if not self.app.allow_account_management:
            return HTTPMethodNotAllowed(
                request=req,
                headers={'Allow': ', '.join(self.allowed_methods)})
        error_response = check_metadata(req, 'account')
        if error_response:
            return error_response
        if len(self.account_name) > constraints.MAX_ACCOUNT_NAME_LENGTH:
            resp = HTTPBadRequest(request=req)
            resp.body = ('Account name length of %d longer than %d' %
                         (len(self.account_name),
                          constraints.MAX_ACCOUNT_NAME_LENGTH)).encode('utf-8')
            return resp

        headers = self.generate_request_headers(req, transfer=True)
        clear_info_cache(self.app, req.environ, self.account_name)
        resp = self.get_account_put_resp(req, headers)
        self.add_acls_from_sys_metadata(resp)
        return resp
Beispiel #29
0
 def PUT(self, req):
     """HTTP PUT request handler."""
     if not self.app.allow_account_management:
         return HTTPMethodNotAllowed(
             request=req,
             headers={'Allow': ', '.join(self.allowed_methods)})
     error_response = check_metadata(req, 'account')
     if error_response:
         return error_response
     if len(self.account_name) > MAX_ACCOUNT_NAME_LENGTH:
         resp = HTTPBadRequest(request=req)
         resp.body = 'Account name length of %d longer than %d' % \
                     (len(self.account_name), MAX_ACCOUNT_NAME_LENGTH)
         return resp
     account_partition, accounts = \
         self.app.account_ring.get_nodes(self.account_name)
     headers = self.generate_request_headers(req, transfer=True)
     if self.app.memcache:
         self.app.memcache.delete(
             get_account_memcache_key(self.account_name))
     resp = self.make_requests(req, self.app.account_ring,
                               account_partition, 'PUT', req.path_info,
                               [headers] * len(accounts))
     return resp
Beispiel #30
0
    def handle_request(self, req):
        """
        Entry point for proxy server.
        Should return a WSGI-style callable (such as swob.Response).

        :param req: swob.Request object
        """
        try:
            self.logger.set_statsd_prefix('proxy-server')
            if req.content_length and req.content_length < 0:
                self.logger.increment('errors')
                return HTTPBadRequest(request=req,
                                      body='Invalid Content-Length')

            try:
                if not check_utf8(req.path_info):
                    self.logger.increment('errors')
                    return HTTPPreconditionFailed(
                        request=req, body='Invalid UTF8 or contains NULL')
            except UnicodeError:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(
                    request=req, body='Invalid UTF8 or contains NULL')

            try:
                controller, path_parts = self.get_controller(req)
                p = req.path_info
                if isinstance(p, six.text_type):
                    p = p.encode('utf-8')
            except APIVersionError:
                self.logger.increment('errors')
                return HTTPBadRequest(request=req)
            except ValueError:
                self.logger.increment('errors')
                return HTTPNotFound(request=req)
            if not controller:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(request=req, body='Bad URL')
            if self.deny_host_headers and \
                    req.host.split(':')[0] in self.deny_host_headers:
                return HTTPForbidden(request=req, body='Invalid host header')

            self.logger.set_statsd_prefix('proxy-server.' +
                                          controller.server_type.lower())
            controller = controller(self, **path_parts)
            if 'swift.trans_id' not in req.environ:
                # if this wasn't set by an earlier middleware, set it now
                trans_id_suffix = self.trans_id_suffix
                trans_id_extra = req.headers.get('x-trans-id-extra')
                if trans_id_extra:
                    trans_id_suffix += '-' + trans_id_extra[:32]
                trans_id = generate_trans_id(trans_id_suffix)
                req.environ['swift.trans_id'] = trans_id
                self.logger.txn_id = trans_id
            req.headers['x-trans-id'] = req.environ['swift.trans_id']
            controller.trans_id = req.environ['swift.trans_id']
            self.logger.client_ip = get_remote_client(req)
            try:
                handler = getattr(controller, req.method)
                getattr(handler, 'publicly_accessible')
            except AttributeError:
                allowed_methods = getattr(controller, 'allowed_methods', set())
                return HTTPMethodNotAllowed(
                    request=req, headers={'Allow': ', '.join(allowed_methods)})
            old_authorize = None
            if 'swift.authorize' in req.environ:
                # We call authorize before the handler, always. If authorized,
                # we remove the swift.authorize hook so isn't ever called
                # again. If not authorized, we return the denial unless the
                # controller's method indicates it'd like to gather more
                # information and try again later.
                resp = req.environ['swift.authorize'](req)
                if not resp and not req.headers.get('X-Copy-From-Account') \
                        and not req.headers.get('Destination-Account'):
                    # No resp means authorized, no delayed recheck required.
                    old_authorize = req.environ['swift.authorize']
                else:
                    # Response indicates denial, but we might delay the denial
                    # and recheck later. If not delayed, return the error now.
                    if not getattr(handler, 'delay_denial', None):
                        return resp
            # Save off original request method (GET, POST, etc.) in case it
            # gets mutated during handling.  This way logging can display the
            # method the client actually sent.
            req.environ['swift.orig_req_method'] = req.method
            try:
                if old_authorize:
                    req.environ.pop('swift.authorize', None)
                return handler(req)
            finally:
                if old_authorize:
                    req.environ['swift.authorize'] = old_authorize
        except HTTPException as error_response:
            return error_response
        except (Exception, Timeout):
            self.logger.exception(_('ERROR Unhandled exception in request'))
            return HTTPServerError(request=req)