コード例 #1
0
ファイル: tests.py プロジェクト: ArcTanSusan/django
 def test_not_modified(self):
     response = HttpResponseNotModified()
     self.assertEqual(response.status_code, 304)
     # 304 responses should not have content/content-type
     with self.assertRaises(AttributeError):
         response.content = "Hello dear"
     self.assertNotIn('content-type', response)
コード例 #2
0
ファイル: cache.py プロジェクト: nbsky/django
def _not_modified(request, response=None):
    if response:
        # We need to keep the cookies, see ticket #4994.
        cookies = response.cookies
        response = HttpResponseNotModified()
        response.cookies = cookies
        return response
    else:
        return HttpResponseNotModified()
コード例 #3
0
ファイル: cache.py プロジェクト: Geekfish/django
def _not_modified(request, response=None):
    new_response = HttpResponseNotModified()
    if response:
        # Preserve the headers required by Section 4.1 of RFC 7232, as well as
        # Last-Modified.
        for header in ('Cache-Control', 'Content-Location', 'Date', 'ETag', 'Expires', 'Last-Modified', 'Vary'):
            if header in response:
                new_response[header] = response[header]

        # Preserve cookies as per the cookie specification: "If a proxy server
        # receives a response which contains a Set-cookie header, it should
        # propagate the Set-cookie header to the client, regardless of whether
        # the response was 304 (Not Modified) or 200 (OK).
        # https://curl.haxx.se/rfc/cookie_spec.html
        new_response.cookies = response.cookies
    return new_response
コード例 #4
0
ファイル: http.py プロジェクト: faridani/Mturk-Tracker
        def inner(request, *args, **kwargs):
            # Get HTTP request headers
            if_modified_since = request.META.get("HTTP_IF_MODIFIED_SINCE")
            if_none_match = request.META.get("HTTP_IF_NONE_MATCH")
            if_match = request.META.get("HTTP_IF_MATCH")
            if if_none_match or if_match:
                # There can be more than one ETag in the request, so we
                # consider the list of values.
                etags = parse_etags(if_none_match or if_match)

            # Compute values (if any) for the requested resource.
            if etag_func:
                res_etag = etag_func(request, *args, **kwargs)
            else:
                res_etag = None
            if last_modified_func:
                dt = last_modified_func(request, *args, **kwargs)
                if dt:
                    res_last_modified = formatdate(timegm(dt.utctimetuple()))[:26] + 'GMT'
                else:
                    res_last_modified = None
            else:
                res_last_modified = None

            response = None
            if not ((if_match and (if_modified_since or if_none_match)) or
                    (if_match and if_none_match)):
                # We only get here if no undefined combinations of headers are
                # specified.
                if ((if_none_match and (res_etag in etags or
                        "*" in etags and res_etag)) and
                        (not if_modified_since or
                            res_last_modified == if_modified_since)):
                    if request.method in ("GET", "HEAD"):
                        response = HttpResponseNotModified()
                    else:
                        response = HttpResponse(status=412)
                elif if_match and ((not res_etag and "*" in etags) or
                        (res_etag and res_etag not in etags)):
                    response = HttpResponse(status=412)
                elif (not if_none_match and if_modified_since and
                        request.method == "GET" and
                        res_last_modified == if_modified_since):
                    response = HttpResponseNotModified()

            if response is None:
                response = func(request, *args, **kwargs)

            # Set relevant headers on the response if they don't already exist.
            if res_last_modified and not response.has_header('Last-Modified'):
                response['Last-Modified'] = res_last_modified
            if res_etag and not response.has_header('ETag'):
                response['ETag'] = quote_etag(res_etag)

            return response
コード例 #5
0
ファイル: http.py プロジェクト: 101studio/django
        def inner(request, *args, **kwargs):
            # Get HTTP request headers
            if_modified_since = request.META.get("HTTP_IF_MODIFIED_SINCE")
            if if_modified_since:
                if_modified_since = parse_http_date_safe(if_modified_since)
            if_none_match = request.META.get("HTTP_IF_NONE_MATCH")
            if_match = request.META.get("HTTP_IF_MATCH")
            if if_none_match or if_match:
                # There can be more than one ETag in the request, so we
                # consider the list of values.
                try:
                    etags = parse_etags(if_none_match or if_match)
                except ValueError:
                    # In case of invalid etag ignore all ETag headers.
                    # Apparently Opera sends invalidly quoted headers at times
                    # (we should be returning a 400 response, but that's a
                    # little extreme) -- this is Django bug #10681.
                    if_none_match = None
                    if_match = None

            # Compute values (if any) for the requested resource.
            if etag_func:
                res_etag = etag_func(request, *args, **kwargs)
            else:
                res_etag = None
            if last_modified_func:
                dt = last_modified_func(request, *args, **kwargs)
                if dt:
                    res_last_modified = timegm(dt.utctimetuple())
                else:
                    res_last_modified = None
            else:
                res_last_modified = None

            response = None
            if not ((if_match and (if_modified_since or if_none_match)) or
                    (if_match and if_none_match)):
                # We only get here if no undefined combinations of headers are
                # specified.
                if ((if_none_match and (res_etag in etags or
                        "*" in etags and res_etag)) and
                        (not if_modified_since or
                            (res_last_modified and if_modified_since and
                            res_last_modified <= if_modified_since))):
                    if request.method in ("GET", "HEAD"):
                        response = HttpResponseNotModified()
                    else:
                        logger.warning('Precondition Failed: %s' % request.path,
                            extra={
                                'status_code': 412,
                                'request': request
                            }
                        )
                        response = HttpResponse(status=412)
                elif if_match and ((not res_etag and "*" in etags) or
                        (res_etag and res_etag not in etags)):
                    logger.warning('Precondition Failed: %s' % request.path,
                        extra={
                            'status_code': 412,
                            'request': request
                        }
                    )
                    response = HttpResponse(status=412)
                elif (not if_none_match and request.method == "GET" and
                        res_last_modified and if_modified_since and
                        res_last_modified <= if_modified_since):
                    response = HttpResponseNotModified()

            if response is None:
                response = func(request, *args, **kwargs)

            # Set relevant headers on the response if they don't already exist.
            if res_last_modified and not response.has_header('Last-Modified'):
                response['Last-Modified'] = http_date(res_last_modified)
            if res_etag and not response.has_header('ETag'):
                response['ETag'] = quote_etag(res_etag)

            return response
コード例 #6
0
"""
コード例 #7
0
 def test_not_modified_repr(self):
     response = HttpResponseNotModified()
     self.assertEqual(repr(response), '<HttpResponseNotModified status_code=304>')
コード例 #8
0
ファイル: middleware.py プロジェクト: taozeze/ANALYSE
    def process_request(self, request):
        # look to see if the request is prefixed with an asset prefix tag
        if (
            request.path.startswith('/' + XASSET_LOCATION_TAG + '/') or
            request.path.startswith('/' + AssetLocator.CANONICAL_NAMESPACE)
        ):
            try:
                loc = StaticContent.get_location_from_path(request.path)
            except (InvalidLocationError, InvalidKeyError):
                # return a 'Bad Request' to browser as we have a malformed Location
                response = HttpResponse()
                response.status_code = 400
                return response

            # first look in our cache so we don't have to round-trip to the DB
            content = get_cached_content(loc)
            if content is None:
                # nope, not in cache, let's fetch from DB
                try:
                    content = AssetManager.find(loc, as_stream=True)
                except NotFoundError:
                    response = HttpResponse()
                    response.status_code = 404
                    return response

                # since we fetched it from DB, let's cache it going forward, but only if it's < 1MB
                # this is because I haven't been able to find a means to stream data out of memcached
                if content.length is not None:
                    if content.length < 1048576:
                        # since we've queried as a stream, let's read in the stream into memory to set in cache
                        content = content.copy_to_in_mem()
                        set_cached_content(content)
            else:
                # NOP here, but we may wish to add a "cache-hit" counter in the future
                pass

            # Check that user has access to content
            if getattr(content, "locked", False):
                if not hasattr(request, "user") or not request.user.is_authenticated():
                    return HttpResponseForbidden('Unauthorized')
                if not request.user.is_staff:
                    if getattr(loc, 'deprecated', False) and not CourseEnrollment.is_enrolled_by_partial(
                        request.user, loc.course_key
                    ):
                        return HttpResponseForbidden('Unauthorized')
                    if not getattr(loc, 'deprecated', False) and not CourseEnrollment.is_enrolled(
                        request.user, loc.course_key
                    ):
                        return HttpResponseForbidden('Unauthorized')

            # convert over the DB persistent last modified timestamp to a HTTP compatible
            # timestamp, so we can simply compare the strings
            last_modified_at_str = content.last_modified_at.strftime("%a, %d-%b-%Y %H:%M:%S GMT")

            # see if the client has cached this content, if so then compare the
            # timestamps, if they are the same then just return a 304 (Not Modified)
            if 'HTTP_IF_MODIFIED_SINCE' in request.META:
                if_modified_since = request.META['HTTP_IF_MODIFIED_SINCE']
                if if_modified_since == last_modified_at_str:
                    return HttpResponseNotModified()

            # *** File streaming within a byte range ***
            # If a Range is provided, parse Range attribute of the request
            # Add Content-Range in the response if Range is structurally correct
            # Request -> Range attribute structure: "Range: bytes=first-[last]"
            # Response -> Content-Range attribute structure: "Content-Range: bytes first-last/totalLength"
            # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
            response = None
            if request.META.get('HTTP_RANGE'):
                # Data from cache (StaticContent) has no easy byte management, so we use the DB instead (StaticContentStream)
                if type(content) == StaticContent:
                    content = AssetManager.find(loc, as_stream=True)

                header_value = request.META['HTTP_RANGE']
                try:
                    unit, ranges = parse_range_header(header_value, content.length)
                except ValueError as exception:
                    # If the header field is syntactically invalid it should be ignored.
                    log.exception(
                        u"%s in Range header: %s for content: %s", exception.message, header_value, unicode(loc)
                    )
                else:
                    if unit != 'bytes':
                        # Only accept ranges in bytes
                        log.warning(u"Unknown unit in Range header: %s for content: %s", header_value, unicode(loc))
                    elif len(ranges) > 1:
                        # According to Http/1.1 spec content for multiple ranges should be sent as a multipart message.
                        # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16
                        # But we send back the full content.
                        log.warning(
                            u"More than 1 ranges in Range header: %s for content: %s", header_value, unicode(loc)
                        )
                    else:
                        first, last = ranges[0]

                        if 0 <= first <= last < content.length:
                            # If the byte range is satisfiable
                            response = HttpResponse(content.stream_data_in_range(first, last))
                            response['Content-Range'] = 'bytes {first}-{last}/{length}'.format(
                                first=first, last=last, length=content.length
                            )
                            response['Content-Length'] = str(last - first + 1)
                            response.status_code = 206  # Partial Content
                        else:
                            log.warning(
                                u"Cannot satisfy ranges in Range header: %s for content: %s", header_value, unicode(loc)
                            )
                            return HttpResponse(status=416)  # Requested Range Not Satisfiable

            # If Range header is absent or syntactically invalid return a full content response.
            if response is None:
                response = HttpResponse(content.stream_data())
                response['Content-Length'] = content.length

            # "Accept-Ranges: bytes" tells the user that only "bytes" ranges are allowed
            response['Accept-Ranges'] = 'bytes'
            response['Content-Type'] = content.content_type
            response['Last-Modified'] = last_modified_at_str

            return response
コード例 #9
0
ファイル: __init__.py プロジェクト: tylerwei/app_spree
def serve (request,
			path,					# media path.
			document_root=None,
			show_indexes=False,		# it's for the compatibility with static.serve.
			force_mimetype=None,	# force the specific mime type.
			compress=True,			# compress output content
			update=False,			# don't use cache.
			width=None,				# only for image
			height=None,			# only for image
			use_template=True,		# parse content thru django template.
			improve=True,			# improve image quality.
			mode=None,				# improve image quality.
		) :

	__argument = request.GET.copy()

	if path.startswith("http%3A%2F%2F") or path.startswith("http://") :
		if path.startswith("http%3A%2F%2F") :
			path = urllib.unquote(path)

		fullpath = path
		func_get_media = get_media_external
	else :
		document_root = os.path.abspath(document_root)

		# for multibyte url handling.
		fullpath = os.path.abspath(
			os.path.join(
				document_root,
				"/".join([urllib.unquote(str(i)) for i in path.split("/")]),
			)
		)

		# prevent to follow up the prior directory.
		if not fullpath.startswith(document_root) :
			return HttpResponse("Access Denied", status=401)

		if not os.path.exists(fullpath) :
			raise Http404, "'%s' does not exist" % fullpath

		if os.path.isdir(fullpath) : # DMS does not support directory index page.
			if show_indexes :
				return django_static.serve(request, path=path, document_root=document_root, show_indexes=True, )
			else :
				raise Http404, "Directory indexes are not allowed here."


		func_get_media = get_media_internal

	if __argument.has_key("compress") :
		compress = parse_boolean_query(__argument.get("compress"))

	if __argument.has_key("force_mimetype") :
		force_mimetype = __argument.get("force_mimetype", "").strip()

	if __argument.has_key("width") :
		width = __argument.get("width", None)

	if __argument.has_key("height") :
		height = __argument.get("height", None)

	if __argument.has_key("update") :
		update = parse_boolean_query(__argument.get("update"))

	if __argument.has_key("improve") :
		improve = parse_boolean_query(__argument.get("improve"))

	if __argument.has_key("mode") :
		mode = __argument.get("mode", mode)

	kwargs = {
		"update": update,
		"compress": compress,
		"force_mimetype": force_mimetype,
		"width": width,
		"height": height,
		"improve": improve,
		"mode": mode,
	}

	# for IE series, check 'HTTP_IF_NONE_MATCH' first.
	if not update and \
			request.META.get("HTTP_IF_NONE_MATCH", None) == get_etag(fullpath) :
		return HttpResponseNotModified()
	elif not update and func_get_media == get_media_internal and not was_modified_since(request, fullpath) :
		return HttpResponseNotModified()
	else :
		# check MAX_FILE_SIZE_COMPRESS
		if func_get_media == get_media_internal and os.stat(fullpath)[stat.ST_SIZE] > MAX_FILE_SIZE_COMPRESS :
			compress = None
			kwargs.update({"compress": compress, })

		if not update :
			# We use cache. If you did not enable the caching,
			# nothing will be happended.
			response = cache.get(get_cache_name(request, **kwargs))
			if response :
				return response

	(cf, mimetype, status_code, last_modified, ) = func_get_media(request, fullpath, **kwargs)

	if status_code == 304 :
		return HttpResponseNotModified()

	if compress :
		try :
			compress = list(set([i for i in request.META.get("HTTP_ACCEPT_ENCODING", "").split(",") if i.strip()]) & set(["gzip", "deflate"]))[0]
		except :
			pass

	response = HttpResponse(
		compress and compress_string(cf.read(), compress) or cf.read(),
		mimetype=mimetype,
	)
	response["Last-Modified"] = last_modified
	response["Expires"] = rfc822.formatdate(time.mktime((datetime.datetime.now() + datetime.timedelta(seconds=CACHE_MIDDLEWARE_SECONDS)).timetuple()))
	response["ETag"] = get_etag(fullpath)

	if compress :
		response["Content-Encoding"] = compress

	cache.set(
		get_cache_name(request, **kwargs),
		response,
		CACHE_MIDDLEWARE_SECONDS,
	)

	return response
コード例 #10
0
ファイル: views.py プロジェクト: guyt101z/tendenci
def plugin_static_serve(request, plugin, path, show_indexes=False):
    """
    Serve static files below a given point in the directory structure.

    To use, put a URL pattern such as::

        (r'^(?P<path>.*)$', 'django.views.static.serve', {'document_root' : '/path/to/my/files/'})

    in your URLconf. You must provide the ``document_root`` param. You may
    also set ``show_indexes`` to ``True`` if you'd like to serve a basic index
    of the directory.  This index view will use the template hardcoded below,
    but if you'd like to override it, you can create a template called
    ``static/directory_index.html``.
    """

    import mimetypes
    import os
    import posixpath
    import stat
    import urllib
    from email.Utils import parsedate_tz, mktime_tz

    from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseNotModified
    from django.utils.http import http_date
    from django.views.static import was_modified_since, directory_index

    from django.conf import settings

    document_root = os.path.join(settings.PROJECT_ROOT, 'plugins', plugin,
                                 'media')

    # Clean up given path to only allow serving files below document_root.
    path = posixpath.normpath(urllib.unquote(path))
    path = path.lstrip('/')
    newpath = ''
    for part in path.split('/'):
        if not part:
            # Strip empty path components.
            continue
        drive, part = os.path.splitdrive(part)
        head, part = os.path.split(part)
        if part in (os.curdir, os.pardir):
            # Strip '.' and '..' in path.
            continue
        newpath = os.path.join(newpath, part).replace('\\', '/')

    if newpath and path != newpath:
        return HttpResponseRedirect(newpath)
    fullpath = os.path.join(document_root, newpath)

    if os.path.isdir(fullpath):
        if show_indexes:
            return directory_index(newpath, fullpath)
        raise Http404("Directory indexes are not allowed here.")
    if not os.path.exists(fullpath):
        raise Http404('"%s" does not exist' % fullpath)

    # Respect the If-Modified-Since header.
    statobj = os.stat(fullpath)
    mimetype = mimetypes.guess_type(fullpath)[0] or 'application/octet-stream'
    if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
                              statobj[stat.ST_MTIME], statobj[stat.ST_SIZE]):
        return HttpResponseNotModified(mimetype=mimetype)
    contents = open(fullpath, 'rb').read()
    response = HttpResponse(contents, mimetype=mimetype)
    response["Last-Modified"] = http_date(statobj[stat.ST_MTIME])
    response["Content-Length"] = len(contents)
    return response
コード例 #11
0
def serve(request, path, document_root='', storage=None, stream=True):
    """
    This is a copy of django.views.static.serve except that it requires
    a ``storage`` param, and serves files from that storage object.

    It also attempts to open files rather than checking if they exist first.
    This allows custom filesystem wrappers to kick in.

    """

    if request.path.endswith('/'):
        raise Http404('Directory indexes are not allowed.')

    # Clean up given path to only allow serving files below document_root.
    path = posixpath.normpath(urllib.unquote(path))
    path = path.lstrip('/')
    newpath = ''
    for part in path.split('/'):
        if not part:
            # Strip empty path components.
            continue
        drive, part = os.path.splitdrive(part)
        head, part = os.path.split(part)
        if part in (os.curdir, os.pardir):
            # Strip '.' and '..' in path.
            continue
        newpath = os.path.join(newpath, part).replace('\\', '/')
    if newpath and path != newpath:
        return HttpResponseRedirect(newpath)

    fullpath = os.path.join(document_root, newpath)

    mimetype, encoding = mimetypes.guess_type(fullpath)
    mimetype = mimetype or 'application/octet-stream'

    # Respect the If-Modified-Since header.
    try:
        file_info = storage.fs.getinfo(fullpath)
    except (OSError, ResourceNotFoundError):
        file_info = None
    else:
        size = file_info['size']
        modified_time = file_info['modified_time']
        if isinstance(modified_time, datetime.datetime):
            modified_time = int(time.mktime(modified_time.timetuple()))
        if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
                                  modified_time, size):
            return HttpResponseNotModified(mimetype=mimetype)

    # Try to open the file without checking if it exists first. This allows
    # custom FS wrappers to activate for missing thumbnail images.
    try:
        open_file = storage.open(fullpath, 'rb')
    except (OSError, ResourceNotFoundError):
        raise Http404('"%s" does not exist' % fullpath)

    if file_info is None or not stream:
        # This is an automatically generated file. Read the
        # contents into memory here so the size can be determined.
        contents = open_file.read()
        open_file.close()
        size = len(contents)
        modified_time = int(time.time())
    else:
        # Stream the file contents without reading it into memory.
        contents = FileWrapper(open_file)

    response = HttpResponse(contents, mimetype=mimetype)
    response['Last-Modified'] = http_date(modified_time)
    response['Content-Length'] = size
    if encoding:
        response['Content-Encoding'] = encoding

    # Set a blank Etag to prevent the file contents from being read by
    # middleware just to generate it. This should be fine, because the
    # last-modified date is a good enough way to tell if a file has changed.
    response['ETag'] = ''

    return response
コード例 #12
0
ファイル: static.py プロジェクト: Kenstogram/my-first-blog
    path = posixpath.normpath(unquote(path)).lstrip('/')
=======
    path = posixpath.normpath(path).lstrip('/')
>>>>>>> 37c99181c9a6b95433d60f8c8ef9af5731096435
    fullpath = safe_join(document_root, path)
    if os.path.isdir(fullpath):
        if show_indexes:
            return directory_index(path, fullpath)
        raise Http404(_("Directory indexes are not allowed here."))
    if not os.path.exists(fullpath):
        raise Http404(_('"%(path)s" does not exist') % {'path': fullpath})
    # Respect the If-Modified-Since header.
    statobj = os.stat(fullpath)
    if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
                              statobj.st_mtime, statobj.st_size):
        return HttpResponseNotModified()
    content_type, encoding = mimetypes.guess_type(fullpath)
    content_type = content_type or 'application/octet-stream'
    response = FileResponse(open(fullpath, 'rb'), content_type=content_type)
    response["Last-Modified"] = http_date(statobj.st_mtime)
    if stat.S_ISREG(statobj.st_mode):
        response["Content-Length"] = statobj.st_size
    if encoding:
        response["Content-Encoding"] = encoding
    return response


DEFAULT_DIRECTORY_INDEX_TEMPLATE = """
{% load i18n %}
<!DOCTYPE html>
<html lang="en">
コード例 #13
0
ファイル: middleware.py プロジェクト: saltfun/edx-platform
    def process_request(self, request):
        """Process the given request"""
        asset_path = request.path

        if self.is_asset_request(request):
            # Make sure we can convert this request into a location.
            if AssetLocator.CANONICAL_NAMESPACE in asset_path:
                asset_path = asset_path.replace('block/', 'block@', 1)

            # If this is a versioned request, pull out the digest and chop off the prefix.
            requested_digest = None
            if StaticContent.is_versioned_asset_path(asset_path):
                requested_digest, asset_path = StaticContent.parse_versioned_asset_path(
                    asset_path)

            # Make sure we have a valid location value for this asset.
            try:
                loc = StaticContent.get_location_from_path(asset_path)
            except (InvalidLocationError, InvalidKeyError):
                return HttpResponseBadRequest()

            # Attempt to load the asset to make sure it exists, and grab the asset digest
            # if we're able to load it.
            actual_digest = None
            try:
                content = self.load_asset_from_location(loc)
                actual_digest = getattr(content, "content_digest", None)
            except (ItemNotFoundError, NotFoundError):
                return HttpResponseNotFound()

            # If this was a versioned asset, and the digest doesn't match, redirect
            # them to the actual version.
            if requested_digest is not None and actual_digest is not None and (
                    actual_digest != requested_digest):
                actual_asset_path = StaticContent.add_version_to_asset_path(
                    asset_path, actual_digest)
                return HttpResponsePermanentRedirect(actual_asset_path)

            # Set the basics for this request. Make sure that the course key for this
            # asset has a run, which old-style courses do not.  Otherwise, this will
            # explode when the key is serialized to be sent to NR.
            safe_course_key = loc.course_key
            if safe_course_key.run is None:
                safe_course_key = safe_course_key.replace(run='only')

            if newrelic:
                newrelic.agent.add_custom_parameter('course_id',
                                                    safe_course_key)
                newrelic.agent.add_custom_parameter('org', loc.org)
                newrelic.agent.add_custom_parameter('contentserver.path',
                                                    loc.path)

                # Figure out if this is a CDN using us as the origin.
                is_from_cdn = StaticContentServer.is_cdn_request(request)
                newrelic.agent.add_custom_parameter('contentserver.from_cdn',
                                                    is_from_cdn)

                # Check if this content is locked or not.
                locked = self.is_content_locked(content)
                newrelic.agent.add_custom_parameter('contentserver.locked',
                                                    locked)

            # Check that user has access to the content.
            if not self.is_user_authorized(request, content, loc):
                return HttpResponseForbidden('Unauthorized')

            # Figure out if the client sent us a conditional request, and let them know
            # if this asset has changed since then.
            last_modified_at_str = content.last_modified_at.strftime(
                HTTP_DATE_FORMAT)
            if 'HTTP_IF_MODIFIED_SINCE' in request.META:
                if_modified_since = request.META['HTTP_IF_MODIFIED_SINCE']
                if if_modified_since == last_modified_at_str:
                    return HttpResponseNotModified()

            # *** File streaming within a byte range ***
            # If a Range is provided, parse Range attribute of the request
            # Add Content-Range in the response if Range is structurally correct
            # Request -> Range attribute structure: "Range: bytes=first-[last]"
            # Response -> Content-Range attribute structure: "Content-Range: bytes first-last/totalLength"
            # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
            response = None
            if request.META.get('HTTP_RANGE'):
                # If we have a StaticContent, get a StaticContentStream.  Can't manipulate the bytes otherwise.
                if isinstance(content, StaticContent):
                    content = AssetManager.find(loc, as_stream=True)

                header_value = request.META['HTTP_RANGE']
                try:
                    unit, ranges = parse_range_header(header_value,
                                                      content.length)
                except ValueError as exception:
                    # If the header field is syntactically invalid it should be ignored.
                    log.exception(u"%s in Range header: %s for content: %s",
                                  text_type(exception), header_value,
                                  six.text_type(loc))
                else:
                    if unit != 'bytes':
                        # Only accept ranges in bytes
                        log.warning(
                            u"Unknown unit in Range header: %s for content: %s",
                            header_value, text_type(loc))
                    elif len(ranges) > 1:
                        # According to Http/1.1 spec content for multiple ranges should be sent as a multipart message.
                        # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16
                        # But we send back the full content.
                        log.warning(
                            u"More than 1 ranges in Range header: %s for content: %s",
                            header_value, text_type(loc))
                    else:
                        first, last = ranges[0]

                        if 0 <= first <= last < content.length:
                            # If the byte range is satisfiable
                            response = HttpResponse(
                                content.stream_data_in_range(first, last))
                            response[
                                'Content-Range'] = u'bytes {first}-{last}/{length}'.format(
                                    first=first,
                                    last=last,
                                    length=content.length)
                            response['Content-Length'] = str(last - first + 1)
                            response.status_code = 206  # Partial Content

                            if newrelic:
                                newrelic.agent.add_custom_parameter(
                                    'contentserver.ranged', True)
                        else:
                            log.warning(
                                u"Cannot satisfy ranges in Range header: %s for content: %s",
                                header_value, text_type(loc))
                            return HttpResponse(
                                status=416)  # Requested Range Not Satisfiable

            # If Range header is absent or syntactically invalid return a full content response.
            if response is None:
                response = HttpResponse(content.stream_data())
                response['Content-Length'] = content.length

            if newrelic:
                newrelic.agent.add_custom_parameter(
                    'contentserver.content_len', content.length)
                newrelic.agent.add_custom_parameter(
                    'contentserver.content_type', content.content_type)

            # "Accept-Ranges: bytes" tells the user that only "bytes" ranges are allowed
            response['Accept-Ranges'] = 'bytes'
            response['Content-Type'] = content.content_type
            response['X-Frame-Options'] = 'ALLOW'

            # Set any caching headers, and do any response cleanup needed.  Based on how much
            # middleware we have in place, there's no easy way to use the built-in Django
            # utilities and properly sanitize and modify a response to ensure that it is as
            # cacheable as possible, which is why we do it ourselves.
            self.set_caching_headers(content, response)

            return response
コード例 #14
0
    def get(self, request, *args, **kwargs):
        """Handle GET requests for this view.

        This will create the renderer for the diff fragment and render it in
        order to get the PatchError information. It then returns a response
        with a zip file containing all the debug data.

        If no PatchError occurred, this will return a 404.

        Args:
            request (django.http.HttpRequest):
                The HTTP request.

            *args (tuple):
                Additional positional arguments for the view.

            **kwargs (dict):
                Additional keyword arguments for the view.

        Returns:
            django.http.HttpResponse:
            A response containing the data bundle.
        """
        try:
            renderer_settings = self._get_renderer_settings(**kwargs)
            etag = self.make_etag(renderer_settings, **kwargs)

            if etag_if_none_match(request, etag):
                return HttpResponseNotModified()

            diff_info_or_response = self.process_diffset_info(**kwargs)

            if isinstance(diff_info_or_response, HttpResponse):
                return diff_info_or_response
        except Http404:
            return HttpResponseNotFound()
        except Exception as e:
            logging.exception(
                '%s.get: Error when processing diffset info for filediff '
                'ID=%s, interfilediff ID=%s, chunk_index=%s: %s',
                self.__class__.__name__,
                kwargs.get('filediff_id'),
                kwargs.get('interfilediff_id'),
                kwargs.get('chunk_index'),
                e,
                request=request)
            return HttpResponseServerError()

        kwargs.update(diff_info_or_response)

        try:
            context = self.get_context_data(**kwargs)

            renderer = self.create_renderer(
                context=context,
                renderer_settings=renderer_settings,
                *args,
                **kwargs)
            renderer.render_to_response(request)
        except PatchError as e:
            patch_error = e
        except Exception as e:
            logging.exception(
                '%s.get: Error when rendering diffset for filediff ID=%s, '
                'interfilediff ID=%s, chunk_index=%s: %s',
                self.__class__.__name__,
                kwargs.get('filediff_id'),
                kwargs.get('interfilediff_id'),
                kwargs.get('chunk_index'),
                e,
                request=request)
            return HttpResponseServerError()
        else:
            return HttpResponseNotFound()

        zip_data = StringIO()

        with ZipFile(zip_data, 'w') as zipfile:
            basename = os.path.basename(patch_error.filename)
            zipfile.writestr('%s.orig' % basename, patch_error.orig_file)
            zipfile.writestr('%s.diff' % basename, patch_error.diff)

            if patch_error.rejects:
                zipfile.writestr('%s.rej' % basename, patch_error.rejects)

            if patch_error.new_file:
                zipfile.writestr('%s.new' % basename, patch_error.new_file)

        rsp = HttpResponse(zip_data.getvalue(), content_type='application/zip')
        rsp['Content-Disposition'] = \
            'attachment; filename=%s.zip' % basename

        return rsp
コード例 #15
0
    def get(self, request, *args, **kwargs):
        """Handle GET requests for this view.

        This will create the renderer for the diff fragment, render it, and
        return it.

        If there's an error when rendering the diff fragment, an error page
        will be rendered and returned instead.

        Args:
            request (django.http.HttpRequest):
                The HTTP request.

            *args (tuple):
                Additional positional arguments for the view.

            **kwargs (dict):
                Additional keyword arguments for the view.

        Returns:
            django.http.HttpResponse:
            A response containing the rendered fragment.
        """
        filediff_id = kwargs.get('filediff_id')
        interfilediff_id = kwargs.get('interfilediff_id')
        chunk_index = kwargs.get('chunk_index')

        base_filediff_id = request.GET.get('base-filediff-id')

        try:
            renderer_settings = self._get_renderer_settings(**kwargs)
            etag = self.make_etag(renderer_settings, **kwargs)

            if etag_if_none_match(request, etag):
                return HttpResponseNotModified()

            diff_info_or_response = self.process_diffset_info(
                base_filediff_id=base_filediff_id, **kwargs)

            if isinstance(diff_info_or_response, HttpResponse):
                return diff_info_or_response
        except Http404:
            raise
        except Exception as e:
            logging.exception(
                '%s.get: Error when processing diffset info '
                'for filediff ID=%s, interfilediff ID=%s, '
                'chunk_index=%s: %s',
                self.__class__.__name__,
                filediff_id,
                interfilediff_id,
                chunk_index,
                e,
                request=request)

            return exception_traceback(self.request, e,
                                       self.error_template_name)

        kwargs.update(diff_info_or_response)

        try:
            context = self.get_context_data(**kwargs)

            renderer = self.create_renderer(
                context=context,
                renderer_settings=renderer_settings,
                *args,
                **kwargs)
            response = renderer.render_to_response(request)
        except PatchError as e:
            logging.warning(
                '%s.get: PatchError when rendering diffset for filediff '
                'ID=%s, interfilediff ID=%s, chunk_index=%s: %s',
                self.__class__.__name__,
                filediff_id,
                interfilediff_id,
                chunk_index,
                e,
                request=request)

            try:
                url_kwargs = {
                    key: kwargs[key]
                    for key in ('chunk_index', 'interfilediff_id',
                                'review_request_id', 'filediff_id', 'revision',
                                'interdiff_revision')
                    if key in kwargs and kwargs[key] is not None
                }

                bundle_url = local_site_reverse('patch-error-bundle',
                                                kwargs=url_kwargs,
                                                request=request)
            except NoReverseMatch:
                # We'll sometimes see errors about this failing to resolve when
                # web crawlers start accessing fragment URLs without the proper
                # attributes. Ignore them.
                bundle_url = ''

            if e.rejects:
                lexer = get_lexer_by_name('diff')
                formatter = HtmlFormatter()
                rejects = highlight(e.rejects, lexer, formatter)
            else:
                rejects = None

            return HttpResponseServerError(
                render_to_string(template_name=self.patch_error_template_name,
                                 context={
                                     'bundle_url': bundle_url,
                                     'file':
                                     diff_info_or_response['diff_file'],
                                     'filename': os.path.basename(e.filename),
                                     'patch_output': e.error_output,
                                     'rejects': mark_safe(rejects),
                                 },
                                 request=request))
        except FileNotFoundError as e:
            return HttpResponseServerError(
                render_to_string(template_name=self.error_template_name,
                                 context={
                                     'error': e,
                                     'file':
                                     diff_info_or_response['diff_file'],
                                 },
                                 request=request))
        except Exception as e:
            logging.exception(
                '%s.get: Error when rendering diffset for '
                'filediff ID=%s, interfilediff ID=%s, '
                'chunkindex=%s: %s',
                self.__class__.__name__,
                filediff_id,
                interfilediff_id,
                chunk_index,
                e,
                request=request)

            return exception_traceback(self.request,
                                       e,
                                       self.error_template_name,
                                       extra_context={
                                           'file':
                                           diff_info_or_response['diff_file'],
                                       })

        if response.status_code == 200:
            set_etag(response, etag)

        return response
コード例 #16
0
        def inner(request, *args, **kwargs):
            # Get HTTP request headers
            if_modified_since = request.META.get("HTTP_IF_MODIFIED_SINCE")
            if if_modified_since:
                if_modified_since = parse_http_date_safe(if_modified_since)
            if_unmodified_since = request.META.get("HTTP_IF_UNMODIFIED_SINCE")
            if if_unmodified_since:
                if_unmodified_since = parse_http_date_safe(if_unmodified_since)
            if_none_match = request.META.get("HTTP_IF_NONE_MATCH")
            if_match = request.META.get("HTTP_IF_MATCH")
            etags = []
            if if_none_match or if_match:
                # There can be more than one ETag in the request, so we
                # consider the list of values.
                try:
                    etags = parse_etags(if_none_match or if_match)
                except ValueError:
                    # In case of invalid etag ignore all ETag headers.
                    # Apparently Opera sends invalidly quoted headers at times
                    # (we should be returning a 400 response, but that's a
                    # little extreme) -- this is Django bug #10681.
                    if_none_match = None
                    if_match = None

            # Compute values (if any) for the requested resource.
            def get_last_modified():
                if last_modified_func:
                    dt = last_modified_func(request, *args, **kwargs)
                    if dt:
                        return timegm(dt.utctimetuple())

            res_etag = etag_func(request, *args, **
                                 kwargs) if etag_func else None
            res_last_modified = get_last_modified()

            response = None
            if not ((if_match and if_modified_since) or
                    (if_none_match and if_unmodified_since) or
                    (if_modified_since and if_unmodified_since) or
                    (if_match and if_none_match)):
                # We only get here if no undefined combinations of headers are
                # specified.
                if ((if_none_match and
                     (res_etag in etags or "*" in etags and res_etag))
                        and (not if_modified_since or
                             (res_last_modified and if_modified_since
                              and res_last_modified <= if_modified_since))):
                    if request.method in ("GET", "HEAD"):
                        response = HttpResponseNotModified()
                    else:
                        response = _precondition_failed(request)
                elif (if_match
                      and ((not res_etag and "*" in etags) or
                           (res_etag and res_etag not in etags) or
                           (res_last_modified and if_unmodified_since
                            and res_last_modified > if_unmodified_since))):
                    response = _precondition_failed(request)
                elif (not if_none_match and request.method in ("GET", "HEAD")
                      and res_last_modified and if_modified_since
                      and res_last_modified <= if_modified_since):
                    response = HttpResponseNotModified()
                elif (not if_match and res_last_modified
                      and if_unmodified_since
                      and res_last_modified > if_unmodified_since):
                    response = _precondition_failed(request)

            if response is None:
                response = func(request, *args, **kwargs)

            # Set relevant headers on the response if they don't already exist.
            if res_last_modified and not response.has_header('Last-Modified'):
                response['Last-Modified'] = http_date(res_last_modified)
            if res_etag and not response.has_header('ETag'):
                response['ETag'] = quote_etag(res_etag)

            return response