<commit_before>"""
Plugin for providing static asset management with AWS' S3 (with or without a
CDN that works with S3, such as CloudFront.)
"""

from __future__ import absolute_import, division, print_function, with_statement, unicode_literals

try:
    from boto.s3.connection import S3Connection
except ImportError:
    S3Connection = None

import os
import hashlib
import mimetypes
from tornado import escape

from .actions import *
from .middleware import *
from .options import *
from .tests import *

def static_url(redis, path):
    """Gets the static path for a file"""
    file_hash = get_cache_buster(redis, path)
    return "%s/%s?v=%s" % (oz.settings["static_host"], path, file_hash)

def get_cache_buster(redis, path):
    """Gets the cache buster value for a given file path"""
    return escape.to_unicode(redis.hget("cache-buster:v1", path))

def set_cache_buster(redis, path, hash):
    """Sets the cache buster value for a given file path"""
    redis.hset("cache-buster:v1", path, hash)

def remove_cache_buster(redis, path):
    """Removes the cache buster for a given file"""
    redis.hdel("cache-buster:v1", path)

def get_bucket(s3_bucket=None, validate=False):
    """Gets a bucket from specified settings"""
    global S3Connection

    if S3Connection != None:
        settings = oz.settings
        s3_bucket = s3_bucket or settings["s3_bucket"]
        return S3Connection(settings["aws_access_key"], settings["aws_secret_key"]).get_bucket(s3_bucket, validate=validate)
    else:
        raise Exception("S3 not supported in this environment as boto is not installed")

def get_file(path):
    """Gets a file"""
    if oz.settings["s3_bucket"]:
        bucket = get_bucket(oz.settings["s3_bucket"])
        return S3File(bucket.new_key(path))
    else:
        return LocalFile(oz.settings["static_path"], path)

class CDNFile(object):
    """File spec for a CDN/S3-hosted file"""

    def __hash__(self):
        return hash("%s:%s" % (self.__class__.__name__, self.path()))

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.path() == other.path()
        else:
            return False

    def hash(self, override=""):
        """Creates a cache buster value for the file"""
        return hashlib.md5(override.encode('utf-8') + self.contents()).hexdigest()

    def path(self):
        """Gets the path of the file"""
        raise NotImplementedError()

    def upload(self, contents, replace=False):<commit_msg>Use sha256 as a new cache busting scheme<commit_after>"""
Plugin for providing static asset management with AWS' S3 (with or without a
CDN that works with S3, such as CloudFront.)
"""

from __future__ import absolute_import, division, print_function, with_statement, unicode_literals

try:
    from boto.s3.connection import S3Connection
except ImportError:
    S3Connection = None

import os
import hashlib
import mimetypes
from tornado import escape

from .actions import *
from .middleware import *
from .options import *
from .tests import *
from .uimodules import *

def static_url(redis, path):
    """Gets the static path for a file"""
    file_hash = get_cache_buster(redis, path)
    return "%s/%s?v=%s" % (oz.settings["static_host"], path, file_hash)

def get_cache_buster(redis, path):
    """Gets the cache buster value for a given file path"""
    return escape.to_unicode(redis.hget("cache-buster:v2", path))

def set_cache_buster(redis, path, hash):
    """Sets the cache buster value for a given file path"""
    redis.hset("cache-buster:v2", path, hash)

def remove_cache_buster(redis, path):
    """Removes the cache buster for a given file"""
    redis.hdel("cache-buster:v2", path)

def get_bucket(s3_bucket=None, validate=False):
    """Gets a bucket from specified settings"""
    global S3Connection

    if S3Connection != None:
        settings = oz.settings
        s3_bucket = s3_bucket or settings["s3_bucket"]
        return S3Connection(settings["aws_access_key"], settings["aws_secret_key"]).get_bucket(s3_bucket, validate=validate)
    else:
        raise Exception("S3 not supported in this environment as boto is not installed")

def get_file(path):
    """Gets a file"""
    if oz.settings["s3_bucket"]:
        bucket = get_bucket(oz.settings["s3_bucket"])
        return S3File(bucket.new_key(path))
    else:
        return LocalFile(oz.settings["static_path"], path)

class CDNFile(object):
    """File spec for a CDN/S3-hosted file"""

    def __hash__(self):
        return hash("%s:%s" % (self.__class__.__name__, self.path()))

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.path() == other.path()
        else:
            return False

    def hash(self, override=""):
        """Creates a cache buster value for the file"""
        return hashlib.sha256(override.encode('utf-8') + self.contents()).hexdigest()

    def path(self):
        """Gets the path of the file"""
        raise NotImplementedError()

    def upload(self, contents, replace=False):
{'fraction_non_alphanumeric': 0.11764705882352941, 'fraction_numerical': 0.010101010101010102, 'mean_word_length': 3.715219421101774, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2605608', 'n_tokens_mistral': 1571, 'n_tokens_neox': 1545, 'n_words': 471}