This file is indexed.

/usr/share/pyshared/glance/api/middleware/cache.py is in python-glance 2012.1.3+stable~20120821-120fcf-0ubuntu1.5.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

"""
Transparent image file caching middleware, designed to live on
Glance API nodes. When images are requested from the API node,
this middleware caches the returned image file to local filesystem.

When subsequent requests for the same image file are received,
the local cached copy of the image file is returned.
"""

import httplib
import logging
import re

import webob

from glance.api.v1 import images
from glance.common import exception
from glance.common import utils
from glance.common import wsgi
from glance import image_cache
from glance import registry

logger = logging.getLogger(__name__)
get_images_re = re.compile(r'^(/v\d+)*/images/([^\/]+)$')


class CacheFilter(wsgi.Middleware):

    def __init__(self, app, conf, **local_conf):
        self.conf = conf
        self.cache = image_cache.ImageCache(conf)
        self.serializer = images.ImageSerializer(conf)
        logger.info(_("Initialized image cache middleware"))
        super(CacheFilter, self).__init__(app)

    def process_request(self, request):
        """
        For requests for an image file, we check the local image
        cache. If present, we return the image file, appending
        the image metadata in headers. If not present, we pass
        the request on to the next application in the pipeline.
        """
        if request.method != 'GET':
            return None

        match = get_images_re.match(request.path)
        if not match:
            return None

        image_id = match.group(2)

        # /images/detail is unfortunately supported, so here we
        # cut out those requests and anything with a query
        # parameter...
        # See LP Bug #879136
        if '?' in image_id or image_id == 'detail':
            return None

        if self.cache.is_cached(image_id):
            logger.debug(_("Cache hit for image '%s'"), image_id)
            image_iterator = self.get_from_cache(image_id)
            context = request.context
            try:
                image_meta = registry.get_image_metadata(context, image_id)
                # Don't display location
                if 'location' in image_meta:
                    del image_meta['location']

                if not image_meta['size']:
                    # override image size metadata with the actual cached
                    # file size, see LP Bug #900959
                    image_meta['size'] = self.cache.get_image_size(image_id)

                response = webob.Response(request=request)
                return self.serializer.show(response, {
                    'image_iterator': image_iterator,
                    'image_meta': image_meta})
            except exception.NotFound:
                msg = _("Image cache contained image file for image '%s', "
                        "however the registry did not contain metadata for "
                        "that image!" % image_id)
                logger.error(msg)
        return None

    def process_response(self, resp):
        """
        We intercept the response coming back from the main
        images Resource, caching image files to the cache
        """
        if not self.get_status_code(resp) == httplib.OK:
            return resp

        request = resp.request
        if request.method not in ('GET', 'DELETE'):
            return resp

        match = get_images_re.match(request.path)
        if match is None:
            return resp

        image_id = match.group(2)
        if '?' in image_id or image_id == 'detail':
            return resp

        if self.cache.is_cached(image_id):
            if request.method == 'DELETE':
                logger.info(_("Removing image %s from cache"), image_id)
                self.cache.delete_cached_image(image_id)
            return resp

        resp.app_iter = self.cache.get_caching_iter(image_id, resp.app_iter)
        return resp

    def get_status_code(self, response):
        """
        Returns the integer status code from the response, which
        can be either a Webob.Response (used in testing) or httplib.Response
        """
        if hasattr(response, 'status_int'):
            return response.status_int
        return response.status

    def get_from_cache(self, image_id):
        """Called if cache hit"""
        with self.cache.open_for_read(image_id) as cache_file:
            chunks = utils.chunkiter(cache_file)
            for chunk in chunks:
                yield chunk