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)
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()
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
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
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
"""
def test_not_modified_repr(self): response = HttpResponseNotModified() self.assertEqual(repr(response), '<HttpResponseNotModified status_code=304>')
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
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
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
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
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">
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
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
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
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