Пример #1
0
        def run():
            objects = SecureObjectAPI(session.auth.user)

            try:
                searchQueries = objects.search(valuesByQuery.keys())
            except UnknownPathError as error:
                session.log.exception(error)
                unknownPath = error.paths[0]
                raise TNonexistentTag(unknownPath.encode('utf-8'))
            except PermissionDeniedError as error:
                session.log.exception(error)
                path_, operation = error.pathsAndOperations[0]
                if operation == Operation.CREATE_OBJECT:
                    raise TUnauthorized()
                else:
                    raise TNonexistentTag(path_)

            # Run queries.
            try:
                with session.timer.track('index-search'):
                    result = blockingCallFromThread(reactor, searchQueries.get)
            except SearchError as error:
                session.log.exception(error)
                raise TParseError(query, error.message)

            # Build a result set from the searches.
            values = {}
            for parsedQuery, objectIDs in result.iteritems():
                for objectID in objectIDs:
                    for tagAndValue in valuesByQuery[parsedQuery]:
                        value = guessValue(tagAndValue.value)
                        # FIXME: this code sucks, but I rather not having
                        # to modify guessValue to return a list, as that
                        # would break other code.
                        # Hopefully, we'll be able to remove this pretty
                        # soon.
                        if isinstance(value, list):
                            value = [item.decode('utf-8') for item in value]
                        if objectID not in values:
                            values[objectID] = {}
                        values[objectID][tagAndValue.path] = value

            # Update values.
            if values:
                tagValues = SecureTagValueAPI(session.auth.user)
                try:
                    result = tagValues.set(values)
                except UnknownPathError as error:
                    session.log.exception(error)
                    path = error.paths[0]
                    raise TNonexistentTag(path.encode('utf-8'))
                except MalformedPathError as error:
                    # FIXME: Modify MalformedPathError to have a path field.
                    raise TInvalidPath(str(error).encode('utf-8'))
                except PermissionDeniedError as error:
                    session.log.exception(error)
                    path_, operation = error.pathsAndOperations[0]
                    category, action = getCategoryAndAction(operation)
                    raise TPathPermissionDenied(category, action, path_)
Пример #2
0
    def _GET_HEAD_common(self, request, verb):
        """
        The following code is reproduced almost verbatim in
        deferred_render_DELETE in about.py. So if you change this code,
        you'll likely need to change that, and vice versa.
        """
        usage = registry.findUsage(httpObjectCategoryName, verb,
                                   TagInstanceResource)

        registry.checkRequest(usage, request)

        # This will raise TNoInstanceOnObject if there's no instance,
        # and that will return a 404 (see util.py).
        tvalue, tagValue = yield self.facadeClient.getTagInstance(
            self.session, self.path, self.objectId)
        value = guessValue(tvalue)
        accept = request.getHeader('accept') or '*/*'

        if tvalue.valueType == ThriftValueType.BINARY_TYPE:
            contentType = tvalue.binaryKeyMimeType
            if mimeparse.best_match([contentType], accept) == '':
                raise error.NotAcceptable()
            body = value
            # Mark this value as unwrappable for JSON
            request._fluiddb_jsonp_unwrappable = None
        else:
            contentType = mimeparse.best_match(
                contentTypesForPrimitiveValue, accept)
            if contentType == '':
                raise error.NotAcceptable()
            try:
                serializer = util.primitiveTypeSerializer[contentType]
            except KeyError:
                raise TInternalError('No serializer for %r.' % contentType)
            else:
                body = serializer(value)

            typeValue = self._getTypeHeader(tvalue.valueType)
            request.setHeader(util.buildHeader('Type'), typeValue)

        request.setHeader('Content-length', str(len(body)))
        request.setHeader('Content-type', contentType)
        # setting the Last-Modified header for fluiddb/id makes no sense
        if tagValue and tagValue.creationTime:
            request.setHeader(
                'Last-modified',
                tagValue.creationTime.strftime('%a, %d %b %Y %H:%M:%S'))
        request.setResponseCode(usage.successCode)
        defer.returnValue(body)
Пример #3
0
    def _GET_HEAD_common(self, request, verb):
        """
        The following code is reproduced almost verbatim in
        deferred_render_DELETE in about.py. So if you change this code,
        you'll likely need to change that, and vice versa.
        """
        usage = registry.findUsage(httpObjectCategoryName, verb,
                                   TagInstanceResource)

        registry.checkRequest(usage, request)

        # This will raise TNoInstanceOnObject if there's no instance,
        # and that will return a 404 (see util.py).
        tvalue, tagValue = yield self.facadeClient.getTagInstance(
            self.session, self.path, self.objectId)
        value = guessValue(tvalue)
        accept = request.getHeader('accept') or '*/*'

        if tvalue.valueType == ThriftValueType.BINARY_TYPE:
            contentType = tvalue.binaryKeyMimeType
            if mimeparse.best_match([contentType], accept) == '':
                raise error.NotAcceptable()
            body = value
            # Mark this value as unwrappable for JSON
            request._fluiddb_jsonp_unwrappable = None
        else:
            contentType = mimeparse.best_match(contentTypesForPrimitiveValue,
                                               accept)
            if contentType == '':
                raise error.NotAcceptable()
            try:
                serializer = util.primitiveTypeSerializer[contentType]
            except KeyError:
                raise TInternalError('No serializer for %r.' % contentType)
            else:
                body = serializer(value)

            typeValue = self._getTypeHeader(tvalue.valueType)
            request.setHeader(util.buildHeader('Type'), typeValue)

        request.setHeader('Content-length', str(len(body)))
        request.setHeader('Content-type', contentType)
        # setting the Last-Modified header for fluiddb/id makes no sense
        if tagValue and tagValue.creationTime:
            request.setHeader(
                'Last-modified',
                tagValue.creationTime.strftime('%a, %d %b %Y %H:%M:%S'))
        request.setResponseCode(usage.successCode)
        defer.returnValue(body)
Пример #4
0
    def setTagInstance(self, session, path, objectId, thriftValue):
        """Set a L{TagValue} for an object.

        @param session: The L{FluidinfoSession} for the request.
        @param path: The L{Tag.path} of the value to set.
        @param objectId: The object ID to set the value for.
        @param thriftValue: The value to set.
        @raise TNonexistentPath: Raised if the L{Tag.path} doesn't exist.
        @raise TPathPermissionDenied: Raised if the L{User} doesn't have
            permission to set the value.
        @return: A C{Deferred} that will fire when the value has been stored.
        """
        path = path.decode('utf-8')
        objectID = UUID(objectId)
        if thriftValue.valueType == ThriftValueType.BINARY_TYPE:
            value = {'mime-type': thriftValue.binaryKeyMimeType,
                     'contents': thriftValue.binaryKey}
        else:
            value = guessValue(thriftValue)
            if isinstance(value, list):
                value = [item.decode('utf-8') for item in value]
        values = {objectID: {path: value}}

        def run():
            try:
                SecureTagValueAPI(session.auth.user).set(values)
            except UnknownPathError as error:
                session.log.exception(error)
                raise TNonexistentTag(path.encode('utf-8'))
            except MalformedPathError as error:
                raise TInvalidPath(path.encode('utf-8'))
            except PermissionDeniedError as error:
                session.log.exception(error)
                path_, operation = error.pathsAndOperations[0]
                category, action = getCategoryAndAction(operation)
                raise TPathPermissionDenied(category, action, path_)

        return session.transact.run(run)
Пример #5
0
    def testRatingForObjectAboutBarcelona(self):
        """
        Run a series of tests on the ntoll/rating tag on the object about
        barcelona:

          - the tag should initially not be present.
          - we should successfully be able to do a PUT.
          - we should then be able to do a GET, HEAD, and DELETE in that order.
          - a final GET should then indicate the tag is gone.
        """
        about = 'barcelona'
        tag = 'ntoll/rating'
        rating = 6
        objectIdAboutBarcelona = util.generateObjectId()

        fakeQueryResolver = FakeQueryResolver(about, [objectIdAboutBarcelona],
                                              self)
        fakeTagsClient = FakeTagsClient()
        facadeClient = FakeFacadeClient(fakeTagsClient=fakeTagsClient,
                                        fakeQueryResolver=fakeQueryResolver)
        session = FakeSession()
        resource = AboutTagInstanceResource(facadeClient, session, about, tag)

        # Test GET when there is no instance on the object.
        d = defer.Deferred()
        request = FakeRequest('GET', d)
        request.content = StringIO.StringIO()
        resource.render(request)
        yield d
        self.assertEqual(request.status, http.NOT_FOUND)

        # Test PUT.
        payload = json.dumps(rating)
        headers = {
            'Content-Length': [str(len(payload))],
            'Content-Type': [contentTypeForPrimitiveJSON],
        }
        d = defer.Deferred()
        request = FakeRequest('PUT', d, headers)
        request.content = StringIO.StringIO(payload)
        resource.render(request)
        yield d
        self.assertEqual(request.status, http.NO_CONTENT)
        self.assertEqual(
            guessValue(fakeTagsClient.values[tag][objectIdAboutBarcelona]),
            rating)

        # Check that the right path, objectId, and value was passed to the
        # fake tags client.
        self.assertEqual(fakeTagsClient.values, {
            tag: {
                objectIdAboutBarcelona: createThriftValue(rating)
            },
        })

        # Test GET.
        d = defer.Deferred()
        request = FakeRequest('GET', d)
        request.content = StringIO.StringIO()
        resource.render(request)
        body = yield d
        self.assertEqual(request.status, http.OK)
        self.assertEqual(request.getResponseHeader('Content-Type'),
                         contentTypeForPrimitiveJSON)
        receivedRating = json.loads(body)
        self.assertEqual(receivedRating, rating)

        # Test HEAD
        d = defer.Deferred()
        request = FakeRequest('HEAD', d)
        request.content = StringIO.StringIO()
        resource.render(request)
        body = yield d
        self.assertEqual(request.status, http.OK)
        self.assertEqual(body, '')

        # Test DELETE
        d = defer.Deferred()
        request = FakeRequest('DELETE', d)
        request.content = StringIO.StringIO()
        resource.render(request)
        body = yield d
        self.assertEqual(request.status, http.NO_CONTENT)

        # Test GET when, finally, there is no instance on the object.
        d = defer.Deferred()
        request = FakeRequest('GET', d)
        request.content = StringIO.StringIO()
        resource.render(request)
        yield d
        self.assertEqual(request.status, http.NOT_FOUND)

        # Check that the value really was deleted.
        self.assertEqual(fakeTagsClient.values, {tag: {}})
Пример #6
0
    def testRatingForObjectAboutBarcelona(self):
        """
        Run a series of tests on the ntoll/rating tag on the object about
        barcelona:

          - the tag should initially not be present.
          - we should successfully be able to do a PUT.
          - we should then be able to do a GET, HEAD, and DELETE in that order.
          - a final GET should then indicate the tag is gone.
        """
        about = 'barcelona'
        tag = 'ntoll/rating'
        rating = 6
        objectIdAboutBarcelona = util.generateObjectId()

        fakeQueryResolver = FakeQueryResolver(
            about, [objectIdAboutBarcelona], self)
        fakeTagsClient = FakeTagsClient()
        facadeClient = FakeFacadeClient(fakeTagsClient=fakeTagsClient,
                                        fakeQueryResolver=fakeQueryResolver)
        session = FakeSession()
        resource = AboutTagInstanceResource(facadeClient, session, about, tag)

        # Test GET when there is no instance on the object.
        d = defer.Deferred()
        request = FakeRequest('GET', d)
        request.content = StringIO.StringIO()
        resource.render(request)
        yield d
        self.assertEqual(request.status, http.NOT_FOUND)

        # Test PUT.
        payload = json.dumps(rating)
        headers = {
            'Content-Length': [str(len(payload))],
            'Content-Type': [contentTypeForPrimitiveJSON],
        }
        d = defer.Deferred()
        request = FakeRequest('PUT', d, headers)
        request.content = StringIO.StringIO(payload)
        resource.render(request)
        yield d
        self.assertEqual(request.status, http.NO_CONTENT)
        self.assertEqual(
            guessValue(fakeTagsClient.values[tag][objectIdAboutBarcelona]),
            rating)

        # Check that the right path, objectId, and value was passed to the
        # fake tags client.
        self.assertEqual(fakeTagsClient.values, {
            tag: {objectIdAboutBarcelona: createThriftValue(rating)},
        })

        # Test GET.
        d = defer.Deferred()
        request = FakeRequest('GET', d)
        request.content = StringIO.StringIO()
        resource.render(request)
        body = yield d
        self.assertEqual(request.status, http.OK)
        self.assertEqual(request.getResponseHeader('Content-Type'),
                         contentTypeForPrimitiveJSON)
        receivedRating = json.loads(body)
        self.assertEqual(receivedRating, rating)

        # Test HEAD
        d = defer.Deferred()
        request = FakeRequest('HEAD', d)
        request.content = StringIO.StringIO()
        resource.render(request)
        body = yield d
        self.assertEqual(request.status, http.OK)
        self.assertEqual(body, '')

        # Test DELETE
        d = defer.Deferred()
        request = FakeRequest('DELETE', d)
        request.content = StringIO.StringIO()
        resource.render(request)
        body = yield d
        self.assertEqual(request.status, http.NO_CONTENT)

        # Test GET when, finally, there is no instance on the object.
        d = defer.Deferred()
        request = FakeRequest('GET', d)
        request.content = StringIO.StringIO()
        resource.render(request)
        yield d
        self.assertEqual(request.status, http.NOT_FOUND)

        # Check that the value really was deleted.
        self.assertEqual(fakeTagsClient.values, {tag: {}})
Пример #7
0
    def _GET_HEAD_common(self, request, verb):
        """
        I handle the common actions taken by GET and HEAD requests, which
        are virtually identical, except HEAD drops the body.

        This code, apart from the yield self._setObjectId(), is taken
        verbatim from _GET_HEAD_common in objects.py. So if you change this
        code, you'll likely need to change that, and vice versa.

        @param request: The HTTP request.
        @param verb: A C{str}, either 'GET' or 'HEAD'.

        @return: A C{Deferred} which fires with the body of a GET request,
                 having set all the response headers that are common to GET
                 and HEAD.  (The body will be dropped (below) for HEAD
                 requests.)
        """
        usage = registry.findUsage(httpAboutCategoryName, verb,
                                   AboutTagInstanceResource)

        registry.checkRequest(usage, request)
        yield self._setObjectId()

        # This will raise TNoInstanceOnObject if there's no instance,
        # and that will return a 404 (see util.py).
        tvalue, tagValue = yield self.facadeClient.getTagInstance(
            self.session, self.path, self.objectId)
        value = guessValue(tvalue)
        accept = request.getHeader('accept') or '*/*'

        if tvalue.valueType == ThriftValueType.BINARY_TYPE:
            contentType = tvalue.binaryKeyMimeType
            if mimeparse.best_match([contentType], accept) == '':
                raise error.NotAcceptable()
            body = value
            # Mark this value as unwrappable for JSON
            request._fluiddb_jsonp_unwrappable = None
        else:
            contentType = mimeparse.best_match(contentTypesForPrimitiveValue,
                                               accept)
            if contentType == '':
                raise error.NotAcceptable()
            try:
                serializer = util.primitiveTypeSerializer[contentType]
            except KeyError:
                raise TInternalError('No serializer for %r.' % contentType)
            else:
                body = serializer(value)

            typeValue = self._getTypeHeader(tvalue.valueType)
            request.setHeader(util.buildHeader('Type'), typeValue)

        request.setHeader('Content-length', str(len(body)))
        request.setHeader('Content-type', contentType)
        # setting the Last-Modified header for fluiddb/id makes no sense
        if tagValue and tagValue.creationTime:
            request.setHeader(
                'Last-modified',
                tagValue.creationTime.strftime('%a, %d %b %Y %H:%M:%S'))
        request.setResponseCode(usage.successCode)
        defer.returnValue(body)
Пример #8
0
    def _GET_HEAD_common(self, request, verb):
        """
        I handle the common actions taken by GET and HEAD requests, which
        are virtually identical, except HEAD drops the body.

        This code, apart from the yield self._setObjectId(), is taken
        verbatim from _GET_HEAD_common in objects.py. So if you change this
        code, you'll likely need to change that, and vice versa.

        @param request: The HTTP request.
        @param verb: A C{str}, either 'GET' or 'HEAD'.

        @return: A C{Deferred} which fires with the body of a GET request,
                 having set all the response headers that are common to GET
                 and HEAD.  (The body will be dropped (below) for HEAD
                 requests.)
        """
        usage = registry.findUsage(httpAboutCategoryName, verb,
                                   AboutTagInstanceResource)

        registry.checkRequest(usage, request)
        yield self._setObjectId()

        # This will raise TNoInstanceOnObject if there's no instance,
        # and that will return a 404 (see util.py).
        tvalue, tagValue = yield self.facadeClient.getTagInstance(
            self.session, self.path, self.objectId)
        value = guessValue(tvalue)
        accept = request.getHeader('accept') or '*/*'

        if tvalue.valueType == ThriftValueType.BINARY_TYPE:
            contentType = tvalue.binaryKeyMimeType
            if mimeparse.best_match([contentType], accept) == '':
                raise error.NotAcceptable()
            body = value
            # Mark this value as unwrappable for JSON
            request._fluiddb_jsonp_unwrappable = None
        else:
            contentType = mimeparse.best_match(
                contentTypesForPrimitiveValue, accept)
            if contentType == '':
                raise error.NotAcceptable()
            try:
                serializer = util.primitiveTypeSerializer[contentType]
            except KeyError:
                raise TInternalError('No serializer for %r.' % contentType)
            else:
                body = serializer(value)

            typeValue = self._getTypeHeader(tvalue.valueType)
            request.setHeader(util.buildHeader('Type'), typeValue)

        request.setHeader('Content-length', str(len(body)))
        request.setHeader('Content-type', contentType)
        # setting the Last-Modified header for fluiddb/id makes no sense
        if tagValue and tagValue.creationTime:
            request.setHeader(
                'Last-modified',
                tagValue.creationTime.strftime('%a, %d %b %Y %H:%M:%S'))
        request.setResponseCode(usage.successCode)
        defer.returnValue(body)