Example #1
0
 def handle_request(self, env, start_response):
     try:
         return self._handle_request(env, start_response)
     except UnicodeDecodeError:
         self.logger.exception('Failed to decode request %r', env)
         resp = swob.HTTPBadRequest('Failed to decode request')
         return resp(env, start_response)
Example #2
0
    def initialize_request(self):
        """
        Basic validation of request and mount check.

        This function will be called before attempting to acquire a
        replication semaphore lock, so contains only quick checks.
        """
        # This environ override has been supported since eventlet 0.14:
        # https://bitbucket.org/eventlet/eventlet/commits/ \
        #     4bd654205a4217970a57a7c4802fed7ff2c8b770
        self.request.environ['eventlet.minimum_write_chunk_size'] = 0
        self.device, self.partition, self.policy = \
            request_helpers.get_name_and_placement(self.request, 2, 2, False)
        self.frag_index = self.node_index = None
        if self.request.headers.get('X-Backend-Ssync-Frag-Index'):
            self.frag_index = int(
                self.request.headers['X-Backend-Ssync-Frag-Index'])
        if self.request.headers.get('X-Backend-Ssync-Node-Index'):
            self.node_index = int(
                self.request.headers['X-Backend-Ssync-Node-Index'])
            if self.node_index != self.frag_index:
                # a primary node should only receive it's own fragments
                raise swob.HTTPBadRequest(
                    'Frag-Index (%s) != Node-Index (%s)' %
                    (self.frag_index, self.node_index))
        utils.validate_device_partition(self.device, self.partition)
        self.diskfile_mgr = self.app._diskfile_router[self.policy]
        if not self.diskfile_mgr.get_dev_path(self.device):
            raise swob.HTTPInsufficientStorage(drive=self.device)
        self.fp = self.request.environ['wsgi.input']
Example #3
0
    def __call__(self, req):
        try:
            vrs, acc, con, obj = req.split_path(2, 4, rest_with_last=True)
        except ValueError:
            return self.app

        # All requests
        if req.method == 'GET':
            account_info = get_account_info(req.environ, self.app)
            if account_info:
                recycled = account_info['meta'].get('recycled', '')
                delete_date = account_info['meta'].get('earliest-delete-date',
                                                       '')
                if recycled == 'yes' and delete_date != '':
                    return swob.HTTPNotFound(
                        headers={
                            'x-account-meta-recycled': 'yes',
                            'x-account-meta-earliest-delete-date': delete_date
                        },
                        body=
                        ("Account is marked for deletion. "
                         "Send X-Remove-Account-Meta-Recycled header via POST to undelete."
                         ))

        # Account specific requests
        if con is None:
            if req.method == 'DELETE':
                account_info = get_account_info(req.environ, self.app)
                if account_info:
                    try:
                        recycled = account_info['meta'].get('recycled', '')
                        delete_date = int(account_info['meta'].get(
                            'earliest-delete-date', '0'))

                        if recycled != "yes":
                            return swob.HTTPMethodNotAllowed(
                                content_type="text/plain",
                                body=
                                ("Account cannot be deleted directly. "
                                 "Send 'X-Account-Meta-Recycled: yes' in POST request to mark for deletion.\n"
                                 ))

                        if time() < delete_date:
                            return swob.HTTPMethodNotAllowed(
                                content_type="text/plain",
                                headers={
                                    'x-account-meta-recycled':
                                    'yes',
                                    'x-account-meta-earliest-delete-date':
                                    delete_date
                                },
                                body=
                                ("Account cannot be deleted yet, "
                                 "X-Account-Meta-Earliest-Delete-Date not reached yet.\n"
                                 ))
                        return self.app
                    except ValueError:
                        return swob.HTTPInternalError(
                            content_type="text/plain",
                            body=(
                                "Internal error. Cannot read recycled state.\n"
                            ))

            if req.method == 'POST':
                if 'x-account-meta-earliest-delete-date' in req.headers or 'x-remove-account-meta-earliest-delete-date' in req.headers:
                    return swob.HTTPMethodNotAllowed(
                        content_type="text/plain",
                        body=("Header X-Account-Meta-Earliest-Delete-Date "
                              "cannot be set manually.\n"))

                if 'x-account-meta-recycled' in req.headers and req.headers[
                        'x-account-meta-recycled'] == "yes":
                    req.headers['x-account-meta-recycled'] = "yes"
                    req.headers['x-account-meta-earliest-delete-date'] = str(
                        int(time()) + self.account_recycled_seconds)
                    return self.app

                if 'x-remove-account-meta-recycled' in req.headers:
                    req.headers['x-remove-account-meta-recycled'] = "x"
                    req.headers[
                        'x-remove-account-meta-earliest-delete-date'] = "x"
                    return self.app

            return self.app

        # Container specific requests
        if obj is None:
            return self.app

        # Object specific requests
        if req.method == 'GET':
            object_info = get_object_info(req.environ, self.app)
            if object_info:
                recycled = object_info['meta'].get('recycled', '')
                delete_date = object_info['meta'].get('delete-date', '')
                if recycled == 'yes':
                    return swob.HTTPNotFound(
                        headers={
                            'x-object-meta-recycled': 'yes',
                            'x-object-meta-delete-date': delete_date
                        },
                        body=
                        ("Object is marked for deletion. "
                         "Send X-Remove-Object-Meta-Recycled header via POST to undelete.\n"
                         ))

        if req.method == 'DELETE':
            return swob.HTTPMethodNotAllowed(
                content_type="text/plain",
                body=(
                    "DELETE requests are not allowed. "
                    "Use POST with 'X-Object-Meta-Recycled: yes' instead.\n"))

        if req.method == 'POST' or req.method == 'PUT':
            if 'x-delete-at' in req.headers or 'x-delete-after' in req.headers or 'x-object-meta-delete-date' in req.headers:
                return swob.HTTPMethodNotAllowed(
                    content_type="text/plain",
                    body=
                    ("Setting X-Delete-At/X-Delete-After/X-Object-Meta-Delete-Date directly is not allowed. "
                     "Use POST with 'X-Object-Meta-Recycled: yes' instead.\n"))

            if 'x-object-meta-recycled' in req.headers:
                if req.headers['x-object-meta-recycled'] != "yes":
                    return swob.HTTPBadRequest(
                        content_type="text/plain",
                        body=("Invalid value for X-Object-Meta-Recycled. "
                              "Only 'yes' is allowed.\n"))

                req.headers['x-object-meta-recycled'] = "yes"
                req.headers['x-object-meta-delete-date'] = str(
                    int(time()) + self.object_recycle_keep_seconds)
                req.headers['x-delete-after'] = str(
                    self.object_recycle_keep_seconds)
                return self.app

            if 'x-remove-object-meta-recycled' in req.headers:
                req.headers['x-remove-object-meta-recycled'] = "x"
                req.headers['x-remove-object-meta-delete-date'] = "x"
                req.headers['x-remove-delete-at'] = "x"
                req.headers['x-remove-delete-after'] = "x"
                return self.app

        return self.app
Example #4
0
    def GET(self, req):
        """Serves a GET to the middleware."""
        try:
            version, account, path = swift_utils.split_path(
                req.path, 2, 3, True)
        except ValueError:
            return swob.HTTPBadRequest(request=req)

        if path:
            path = utils.unicode_unquote(path).rstrip("/")

        self.logger.debug("Searching")

        # Get all of the request variables that we need.
        fmt = req.params.get('format', '').lower()
        accept_header = req.headers.get('Accept', '').lower()

        # Check for Accept header as well
        if fmt == '' and accept_header != '':
            if 'json' in accept_header:
                fmt = 'json'
            elif 'xml' in accept_header:
                fmt = 'xml'

        queries = []
        for key, value in req.str_params.items():
            if key.startswith('q.'):
                val = value.decode("utf-8").strip('*')
                queries.append((key[2:], val))

        query = req.str_params.get('q')
        if query:
            query = query.decode("utf-8").strip('*')
        limit = int(req.params.get('limit', 0)
                    or req.params.get('rows', 0)) or 100
        start = int(req.params.get('start', 0) or req.params.get('offset', 0))
        sort = req.params.get('sort', None)

        _type = req.params.get('type', None)

        if _type not in ['object', 'container', None, '']:
            return swob.HTTPBadRequest(request=req)

        field = (req.params.get('field', None) or req.params.get('df', None)
                 or '_all')

        marker = req.params.get('marker', None)

        recursive = req.params.get('recursive', True)
        if type(recursive) is not bool:
            if recursive.lower() in ['false', '0', 'f']:
                recursive = False
            else:
                recursive = True

        srch = index.Searcher(self.elastic_hosts,
                              self.search_index_name,
                              account,
                              logger=self.logger)
        srch.logger = self.logger
        if query:
            srch.add_condition(field, query)
        for f, q in queries:
            if f.startswith("meta-"):
                f = "meta." + f[5:]
            srch.add_condition(f, q)
        srch.path = path
        srch.recursive = recursive
        srch.type = _type
        srch.sort = sort
        srch.limit = limit
        srch.start = start
        srch.marker = marker

        try:
            results = srch.execute()
        except socket.timeout:
            return swob.HTTPServiceUnavailable(req=req)

        self.logger.debug(results)

        result_list = []
        for item in results:
            t = index.filter_result_props(item)
            result_list.append(t)

        headers = [
            ('X-Search-Items-Count', len(result_list)),
            ('X-Search-Items-Total', results.total),
            ('X-Search-Items-Offset', start),
        ]

        if fmt == 'json':
            headers.append(('Content-Type', 'application/json; charset=utf-8'))
            return swob.Response(request=req,
                                 body=json.dumps(result_list),
                                 headers=headers)
        elif fmt == 'xml':
            headers.append(('Content-Type', 'application/xml; charset=utf-8'))
            output_list = [
                '<?xml version="1.0" encoding="UTF-8"?>', '<results>'
            ]
            for res in result_list:
                item = '<object>'
                for key, val in res.iteritems():
                    item += '<%s>%s</%s>' % (key, saxutils.escape(
                        str(val)), key)
                item += '</object>'
                output_list.append(item)
            output_list.append('</results>')
            res_body = '\n'.join(output_list)
            return swob.Response(request=req, body=res_body, headers=headers)
        else:
            headers.append(('Content-Type', 'text/plain'))
            res_body = ''
            for res in result_list:
                for key, val in res.iteritems():
                    res_body += str(key) + ': ' + str(val) + '\n'
                res_body += '\n'
            return swob.Response(request=req, body=res_body, headers=headers)