This file is indexed.

/usr/lib/python2.7/dist-packages/cloudfiles/container.py is in python-cloudfiles 1.7.11-2build1.

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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
"""
container operations

Containers are storage compartments where you put your data (objects).
A container is similar to a directory or folder on a conventional filesystem
with the exception that they exist in a flat namespace, you can not create
containers inside of containers.

See COPYING for license information.
"""

from storage_object import Object, ObjectResults
from errors import ResponseError, InvalidContainerName, InvalidObjectName, \
                   ContainerNotPublic, CDNNotEnabled
from utils  import requires_name
import consts
from fjson  import json_loads

# Because HTTPResponse objects *have* to have read() called on them
# before they can be used again ...
# pylint: disable-msg=W0612


class Container(object):
    """
    Container object and Object instance factory.

    If your account has the feature enabled, containers can be publically
    shared over a global content delivery network.

    @ivar name: the container's name (generally treated as read-only)
    @type name: str
    @ivar object_count: the number of objects in this container (cached)
    @type object_count: number
    @ivar size_used: the sum of the sizes of all objects in this container
            (cached)
    @type size_used: number
    @ivar cdn_ttl: the time-to-live of the CDN's public cache of this container
            (cached, use make_public to alter)
    @type cdn_ttl: number
    @ivar cdn_log_retention: retention of the logs in the container.
    @type cdn_log_retention: bool

    @undocumented: _fetch_cdn_data
    @undocumented: _list_objects_raw
    """
    def __set_name(self, name):
        # slashes make for invalid names
        if isinstance(name, (str, unicode)) and \
                ('/' in name or len(name) > consts.container_name_limit):
            raise InvalidContainerName(name)
        self._name = name

    name = property(fget=lambda self: self._name, fset=__set_name,
        doc="the name of the container (read-only)")

    def __init__(self, connection=None, name=None, count=None, size=None, metadata=None):
        """
        Containers will rarely if ever need to be instantiated directly by the
        user.

        Instead, use the L{create_container<Connection.create_container>},
        L{get_container<Connection.get_container>},
        L{list_containers<Connection.list_containers>} and
        other methods on a valid Connection object.
        """
        self._name = None
        self.name = name
        self.conn = connection
        self.object_count = count
        self.size_used = size
        self.metadata = metadata
        self.cdn_uri = None
        self.cdn_ssl_uri = None
        self.cdn_streaming_uri = None
        self.cdn_ttl = None
        self.cdn_log_retention = None
        if self.metadata == None:
            self.metadata = {}
        if connection.cdn_enabled:
            self._fetch_cdn_data()

    @requires_name(InvalidContainerName)
    def update_metadata(self, metadata):
        """
        Update Container Metadata
        
        >>> metadata = {'x-container-meta-foo' : 'bar'}
        >>> container.update_metadata(metadata)
        
        @param metadata: A dictionary containing metadata.
        @type metadata: dict
        """
        response = self.conn.make_request('POST', [self.name])
        response.read()
        if (response.status < 200) or (response.status > 299):
            raise ResponseError(response.status, response.reason)
    
    def enable_static_web(self, index=None, listings=None, error=None, listings_css=None):
        """
        Enable static web for this Container

        >>> container.enable_static_web('index.html', 'error.html', True, 'style.css')

        @param index: The name of the index landing page
        @type index : str
        @param listings: A boolean value to enable listing.
        @type error: bool
        @param listings_css: The file to be used when applying CSS to the listing.
        @type listings_css: str
        @param error: The suffix to be used for 404 and 401 error pages.
        @type error: str

        """
        metadata = {'X-Container-Meta-Web-Index' : '',
                    'X-Container-Meta-Web-Listings' : '',
                    'X-Container-Meta-Web-Error' : '',
                    'X-Container-Meta-Web-Listings-CSS' : ''}
        if index is not None:
            metadata['X-Container-Meta-Web-Index'] = index
        if listings is not None:
            metadata['X-Container-Meta-Web-Listings'] = str(listings)
        if error is not None:
            metadata['X-Container-Meta-Web-Error'] = error
        if listings_css is not None:
            metadata['X-Container-Meta-Web-Listings-CSS'] = listings_css
        self.update_metadata(metadata)

    def disable_static_web(self):
        """
        Disable static web for this Container

        >>> container.disable_static_web()
        """
        self.enable_static_web()

    def enable_object_versioning(self, container_name):
        """
        Enable object versioning on this container
        
        >>> container.enable_object_versioning('container_i_want_versions_to_go_to')
        
        @param container_url: The container where versions will be stored
        @type container_name: str
        """
        self.update_metadata({'X-Versions-Location' : container_name})

    def disable_object_versioning(self):
        """
        Disable object versioning on this container

        >>> container.disable_object_versioning()
        """
        self.update_metadata({'X-Versions-Location' : ''})

    @requires_name(InvalidContainerName)
    def _fetch_cdn_data(self):
        """
        Fetch the object's CDN data from the CDN service
        """
        response = self.conn.cdn_request('HEAD', [self.name])
        if response.status >= 200 and response.status < 300:
            for hdr in response.getheaders():
                if hdr[0].lower() == 'x-cdn-uri':
                    self.cdn_uri = hdr[1]
                if hdr[0].lower() == 'x-ttl':
                    self.cdn_ttl = int(hdr[1])
                if hdr[0].lower() == 'x-cdn-ssl-uri':
                    self.cdn_ssl_uri = hdr[1]
                if hdr[0].lower() == 'x-cdn-streaming-uri':
                    self.cdn_streaming_uri = hdr[1]
                if hdr[0].lower() == 'x-log-retention':
                    self.cdn_log_retention = hdr[1] == "True" and True or False

    @requires_name(InvalidContainerName)
    def make_public(self, ttl=consts.default_cdn_ttl):
        """
        Either publishes the current container to the CDN or updates its
        CDN attributes.  Requires CDN be enabled on the account.

        >>> container.make_public(ttl=604800) # expire in 1 week

        @param ttl: cache duration in seconds of the CDN server
        @type ttl: number
        """
        if not self.conn.cdn_enabled:
            raise CDNNotEnabled()
        if self.cdn_uri:
            request_method = 'POST'
        else:
            request_method = 'PUT'
        hdrs = {'X-TTL': str(ttl), 'X-CDN-Enabled': 'True'}
        response = self.conn.cdn_request(request_method, \
                                             [self.name], hdrs=hdrs)
        if (response.status < 200) or (response.status >= 300):
            raise ResponseError(response.status, response.reason)
        self.cdn_ttl = ttl
        for hdr in response.getheaders():
            if hdr[0].lower() == 'x-cdn-uri':
                self.cdn_uri = hdr[1]
            if hdr[0].lower() == 'x-cdn-ssl-uri':
                self.cdn_ssl_uri = hdr[1]

    @requires_name(InvalidContainerName)
    def make_private(self):
        """
        Disables CDN access to this container.
        It may continue to be available until its TTL expires.

        >>> container.make_private()
        """
        if not self.conn.cdn_enabled:
            raise CDNNotEnabled()
        hdrs = {'X-CDN-Enabled': 'False'}
        self.cdn_uri = None
        response = self.conn.cdn_request('POST', [self.name], hdrs=hdrs)
        if (response.status < 200) or (response.status >= 300):
            raise ResponseError(response.status, response.reason)

    @requires_name(InvalidContainerName)
    def purge_from_cdn(self, email=None):
        """
        Purge Edge cache for all object inside of this container.
        You will be notified by email if one is provided when the
        job completes.

        >>> container.purge_from_cdn("user@dmain.com")
        
        or

        >>> container.purge_from_cdn("user@domain.com,user2@domain.com")
        
        or
        
        >>> container.purge_from_cdn()
        
        @param email: A Valid email address
        @type email: str
        """
        if not self.conn.cdn_enabled:
            raise CDNNotEnabled()

        if email:
            hdrs = {"X-Purge-Email": email}
            response = self.conn.cdn_request('DELETE', [self.name], hdrs=hdrs)
        else:
            response = self.conn.cdn_request('DELETE', [self.name])

        if (response.status < 200) or (response.status >= 300):
            raise ResponseError(response.status, response.reason)

    @requires_name(InvalidContainerName)
    def log_retention(self, log_retention=consts.cdn_log_retention):
        """
        Enable CDN log retention on the container. If enabled logs will be
        periodically (at unpredictable intervals) compressed and uploaded to
        a ".CDN_ACCESS_LOGS" container in the form of
        "container_name/YYYY/MM/DD/HH/XXXX.gz". Requires CDN be enabled on the
        account.

        >>> container.log_retention(True)

        @param log_retention: Enable or disable logs retention.
        @type log_retention: bool
        """
        if not self.conn.cdn_enabled:
            raise CDNNotEnabled()

        hdrs = {'X-Log-Retention': log_retention}
        response = self.conn.cdn_request('POST', [self.name], hdrs=hdrs)
        if (response.status < 200) or (response.status >= 300):
            raise ResponseError(response.status, response.reason)

        self.cdn_log_retention = log_retention

    def is_public(self):
        """
        Returns a boolean indicating whether or not this container is
        publically accessible via the CDN.

        >>> container.is_public()
        False
        >>> container.make_public()
        >>> container.is_public()
        True

        @rtype: bool
        @return: whether or not this container is published to the CDN
        """
        if not self.conn.cdn_enabled:
            raise CDNNotEnabled()
        return self.cdn_uri is not None

    @requires_name(InvalidContainerName)
    def public_uri(self):
        """
        Return the URI for this container, if it is publically
        accessible via the CDN.

        >>> connection['container1'].public_uri()
        'http://c00061.cdn.cloudfiles.rackspacecloud.com'

        @rtype: str
        @return: the public URI for this container
        """
        if not self.is_public():
            raise ContainerNotPublic()
        return self.cdn_uri

    @requires_name(InvalidContainerName)
    def public_ssl_uri(self):
        """
        Return the SSL URI for this container, if it is publically
        accessible via the CDN.

        >>> connection['container1'].public_ssl_uri()
        'https://c61.ssl.cf0.rackcdn.com'

        @rtype: str
        @return: the public SSL URI for this container
        """
        if not self.is_public():
            raise ContainerNotPublic()
        return self.cdn_ssl_uri

    @requires_name(InvalidContainerName)
    def public_streaming_uri(self):
        """
        Return the Streaming URI for this container, if it is publically
        accessible via the CDN.

        >>> connection['container1'].public_ssl_uri()
        'https://c61.stream.rackcdn.com'

        @rtype: str
        @return: the public Streaming URI for this container
        """
        if not self.is_public():
            raise ContainerNotPublic()
        return self.cdn_streaming_uri

    @requires_name(InvalidContainerName)
    def create_object(self, object_name):
        """
        Return an L{Object} instance, creating it if necessary.

        When passed the name of an existing object, this method will
        return an instance of that object, otherwise it will create a
        new one.

        >>> container.create_object('new_object')
        <cloudfiles.storage_object.Object object at 0xb778366c>
        >>> obj = container.create_object('new_object')
        >>> obj.name
        'new_object'

        @type object_name: str
        @param object_name: the name of the object to create
        @rtype: L{Object}
        @return: an object representing the newly created storage object
        """
        return Object(self, object_name)

    @requires_name(InvalidContainerName)
    def get_objects(self, prefix=None, limit=None, marker=None,
                    path=None, delimiter=None, **parms):
        """
        Return a result set of all Objects in the Container.

        Keyword arguments are treated as HTTP query parameters and can
        be used to limit the result set (see the API documentation).

        >>> container.get_objects(limit=2)
        ObjectResults: 2 objects
        >>> for obj in container.get_objects():
        ...     print obj.name
        new_object
        old_object

        @param prefix: filter the results using this prefix
        @type prefix: str
        @param limit: return the first "limit" objects found
        @type limit: int
        @param marker: return objects whose names are greater than "marker"
        @type marker: str
        @param path: return all objects in "path"
        @type path: str
        @param delimiter: use this character as a delimiter for subdirectories
        @type delimiter: char

        @rtype: L{ObjectResults}
        @return: an iterable collection of all storage objects in the container
        """
        return ObjectResults(self, self.list_objects_info(
                prefix, limit, marker, path, delimiter, **parms))

    @requires_name(InvalidContainerName)
    def get_object(self, object_name):
        """
        Return an L{Object} instance for an existing storage object.

        If an object with a name matching object_name does not exist
        then a L{NoSuchObject} exception is raised.

        >>> obj = container.get_object('old_object')
        >>> obj.name
        'old_object'

        @param object_name: the name of the object to retrieve
        @type object_name: str
        @rtype: L{Object}
        @return: an Object representing the storage object requested
        """
        return Object(self, object_name, force_exists=True)

    @requires_name(InvalidContainerName)
    def list_objects_info(self, prefix=None, limit=None, marker=None,
                          path=None, delimiter=None, **parms):
        """
        Return information about all objects in the Container.

        Keyword arguments are treated as HTTP query parameters and can
        be used limit the result set (see the API documentation).

        >>> conn['container1'].list_objects_info(limit=2)
        [{u'bytes': 4820,
          u'content_type': u'application/octet-stream',
          u'hash': u'db8b55400b91ce34d800e126e37886f8',
          u'last_modified': u'2008-11-05T00:56:00.406565',
          u'name': u'new_object'},
         {u'bytes': 1896,
          u'content_type': u'application/octet-stream',
          u'hash': u'1b49df63db7bc97cd2a10e391e102d4b',
          u'last_modified': u'2008-11-05T00:56:27.508729',
          u'name': u'old_object'}]

        @param prefix: filter the results using this prefix
        @type prefix: str
        @param limit: return the first "limit" objects found
        @type limit: int
        @param marker: return objects with names greater than "marker"
        @type marker: str
        @param path: return all objects in "path"
        @type path: str
        @param delimiter: use this character as a delimiter for subdirectories
        @type delimiter: char

        @rtype: list({"name":"...", "hash":..., "size":..., "type":...})
        @return: a list of all container info as dictionaries with the
                 keys "name", "hash", "size", and "type"
        """
        parms['format'] = 'json'
        resp = self._list_objects_raw(
            prefix, limit, marker, path, delimiter, **parms)
        return json_loads(resp)

    @requires_name(InvalidContainerName)
    def list_objects(self, prefix=None, limit=None, marker=None,
                     path=None, delimiter=None, **parms):
        """
        Return names of all L{Object}s in the L{Container}.

        Keyword arguments are treated as HTTP query parameters and can
        be used to limit the result set (see the API documentation).

        >>> container.list_objects()
        ['new_object', 'old_object']

        @param prefix: filter the results using this prefix
        @type prefix: str
        @param limit: return the first "limit" objects found
        @type limit: int
        @param marker: return objects with names greater than "marker"
        @type marker: str
        @param path: return all objects in "path"
        @type path: str
        @param delimiter: use this character as a delimiter for subdirectories
        @type delimiter: char

        @rtype: list(str)
        @return: a list of all container names
        """
        resp = self._list_objects_raw(prefix=prefix, limit=limit,
                                      marker=marker, path=path,
                                      delimiter=delimiter, **parms)
        return resp.splitlines()

    @requires_name(InvalidContainerName)
    def _list_objects_raw(self, prefix=None, limit=None, marker=None,
                          path=None, delimiter=None, **parms):
        """
        Returns a chunk list of storage object info.
        """
        if prefix:
            parms['prefix'] = prefix
        if limit:
            parms['limit'] = limit
        if marker:
            parms['marker'] = marker
        if delimiter:
            parms['delimiter'] = delimiter
        if not path is None:
            parms['path'] = path  # empty strings are valid
        response = self.conn.make_request('GET', [self.name], parms=parms)
        if (response.status < 200) or (response.status > 299):
            response.read()
            raise ResponseError(response.status, response.reason)
        return response.read()

    def __getitem__(self, key):
        return self.get_object(key)

    def __str__(self):
        return self.name

    @requires_name(InvalidContainerName)
    def delete_object(self, object_name):
        """
        Permanently remove a storage object.

        >>> container.list_objects()
        ['new_object', 'old_object']
        >>> container.delete_object('old_object')
        >>> container.list_objects()
        ['new_object']

        @param object_name: the name of the object to retrieve
        @type object_name: str
        """
        if isinstance(object_name, Object):
            object_name = object_name.name
        if not object_name:
            raise InvalidObjectName(object_name)
        response = self.conn.make_request('DELETE', [self.name, object_name])
        if (response.status < 200) or (response.status > 299):
            response.read()
            raise ResponseError(response.status, response.reason)
        response.read()


class ContainerResults(object):
    """
    An iterable results set object for Containers.

    This class implements dictionary- and list-like interfaces.
    """
    def __init__(self, conn, containers=list()):
        self._containers = containers
        self._names = [k['name'] for k in containers]
        self.conn = conn

    def __getitem__(self, key):
        return Container(self.conn,
                         self._containers[key]['name'],
                         self._containers[key]['count'],
                         self._containers[key]['bytes'])

    def __getslice__(self, i, j):
        return [Container(self.conn, k['name'], k['count'], \
                              k['size']) for k in self._containers[i:j]]

    def __contains__(self, item):
        return item in self._names

    def __repr__(self):
        return 'ContainerResults: %s containers' % len(self._containers)
    __str__ = __repr__

    def __len__(self):
        return len(self._containers)

    def index(self, value, *args):
        """
        returns an integer for the first index of value
        """
        return self._names.index(value, *args)

    def count(self, value):
        """
        returns the number of occurrences of value
        """
        return self._names.count(value)

# vim:set ai sw=4 ts=4 tw=0 expandtab: