def serve_protected_file(request, path, document_root=None, show_indexes=False): user_file = get_object_or_404(File, file=path) if user_file.user_id != request.user.id: raise Http404 path = posixpath.normpath(path).lstrip('/') fullpath = Path(safe_join(document_root, path)) if fullpath.is_dir(): if show_indexes: return directory_index(path, fullpath) raise Http404("Directory indexes are not allowed here.") if not fullpath.exists(): raise Http404('“%(path)s” does not exist' % {'path': fullpath}) # Respect the If-Modified-Since header. statobj = fullpath.stat() 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(str(fullpath)) content_type = content_type or 'application/octet-stream' response = FileResponse(fullpath.open('rb'), content_type=content_type) response["Last-Modified"] = http_date(statobj.st_mtime) if encoding: response["Content-Encoding"] = encoding return response
def get(self, request, *args, **kwargs): filename = self.get_filename().format( filename=self.kwargs.get('filename', ''), media=settings.MEDIA_ROOT, static=settings.STATIC_ROOT, ) if not os.path.exists(filename) or os.path.isdir(filename): raise Http404(_('No file found matching the query')) filestats = os.stat(filename) if not self.was_modified(filename, filestats): return HttpResponseNotModified() charset = self.get_charset(filename, filestats) mimetype = self.get_mimetype(filename, filestats) encoding = self.get_encoding(filename, filestats) try: fileobj = open(filename, 'rb') except IOError: raise Http404(_('No file found matching the query')) if not charset and mimetype and not mimetype.startswith('text'): content_type = mimetype or 'application/octet-stream' else: content_type = '{0}; charset={1}'.format( mimetype or settings.DEFAULT_CONTENT_TYPE, charset or settings.DEFAULT_CHARSET, ) response = FileResponse(fileobj, content_type=content_type) response['Last-Modified'] = http_date(filestats.st_mtime) if stat.S_ISREG(filestats.st_mode): response['Content-Length'] = filestats.st_size if encoding: response['Content-Encoding'] = encoding return response
def serve(request, path, document_root=None, show_indexes=False): """ Serve static files below a given point in the directory structure. To use, put a URL pattern such as:: from django.views.static import serve path('<path:path>', 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``. """ path = posixpath.normpath(path).lstrip("/") fullpath = Path(safe_join(document_root, path)) if fullpath.is_dir(): if show_indexes: return directory_index(path, fullpath) raise Http404(_("Directory indexes are not allowed here.")) if not fullpath.exists(): raise Http404(_("“%(path)s” does not exist") % {"path": fullpath}) # Respect the If-Modified-Since header. statobj = fullpath.stat() 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(str(fullpath)) content_type = content_type or "application/octet-stream" response = FileResponse(fullpath.open("rb"), content_type=content_type) response.headers["Last-Modified"] = http_date(statobj.st_mtime) if encoding: response.headers["Content-Encoding"] = encoding return response
def get(self, request, *args, **kwargs): exporter = self.get_exporter(request) lang_code = request.GET.get("lang") if lang_code and lang_code in request.event.locales: activate(lang_code) elif "lang" in request.GET: activate(request.event.locale) with suppress(Exception): exporter.schedule = self.schedule exporter.is_orga = getattr(self.request, "is_orga", False) file_name, file_type, data = exporter.render() etag = hashlib.sha1(str(data).encode()).hexdigest() if "If-None-Match" in request.headers: if request.headers["If-None-Match"] == etag: return HttpResponseNotModified() response = HttpResponse(data, content_type=file_type) response["ETag"] = etag if file_type not in ["application/json", "text/xml"]: response[ "Content-Disposition"] = f'attachment; filename="{safe_filename(file_name)}"' if exporter.cors: response["Access-Control-Allow-Origin"] = exporter.cors return response raise Http404()
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 get_host_detail(request, host_name=""): ret = {'html': {}, 'value': {}} if host_name not in base.db.distinct('common', 'hosts', 'hostname'): return HttpResponseNotModified() doc = base.db.get_host_setting(host_name) ret['value']['sysmon_timer'] = doc['sysmon_timer'] default = doc['default'] ret['value']['host_name'] = host_name ret['html'][ 'grafana'] = f'http://10.4.73.172:3000/d/WzsbkBwWk/system-mon?refresh=5s&kiosk=tv&var-hostname={host_name}' ret['html']['host_legend'] = host_name ret['html']['default_table'] = '<tr><td colspan="2">Default</td></tr>' for sensor in default: ret['html']['default_table'] += f'<tr><td>{sensor}</td>' ret['html'][ 'default_table'] += f'<td><input type="checkbox" name="checkbox_{sensor}" value="{sensor}" checked></td></tr>' unmonitored = base.db.get_unmonitored_sensors() ret['html'][ 'unmonitored_table'] = '<tr><td colspan="2">Unmonitored</td></tr>' for sensor in unmonitored: ret['html']['unmonitored_table'] += f'<tr><td>{sensor}</td>' ret['html'][ 'unmonitored_table'] += f'<td><input type="checkbox" name="checkbox_{sensor}" value="{sensor}"></td></tr>' return JsonResponse(ret)
def get(self, request, *args, **kwargs): host = self.get_object() if 'secret' not in request.GET \ or not hmac.compare_digest(request.GET['secret'], host.secret): return HttpResponseForbidden() if 'version' in request.GET: version_str = request.GET['version'] if not version_str.isnumeric(): return HttpResponseBadRequest() version = int(version_str) if version >= host.config_version: return HttpResponseNotModified() if config_tar.is_empty_config(host): return HttpResponse(status=204) # All good, return generate and return the config # Use the response as file-like object to write the tar filename = '{host}_v{version}.tar.gz'.format( host=host.path_str(), version=host.config_version) resp = HttpResponseAttachment(filename=filename, content_type='application/gzip') config_tar.generate_host_config_tar(host, resp) return resp
def get(self, request, *args, **kwargs): id = kwargs.get('id', None) if id is not None: query = IconData.objects.filter(icon__id=kwargs['id']) else: collection = kwargs.get('collection') icon = kwargs.get('icon') query = IconData.objects.filter(icon__collection__slug=collection).filter(icon__slug=icon) params = request.GET.copy() version = params.pop('version', None) if version: icon = query.filter(version=version)[0] else: icon = query.latest('version') stale = request.META.get('HTTP_IF_MODIFIED_SINCE', None) if stale: if icon.modified.replace(microsecond=0, tzinfo=None) <= datetime.strptime(stale, _date_fmt): return HttpResponseNotModified() svg = icon.svg if params: svg = process_svg(svg, params) resp = HttpResponse(svg, content_type='image/svg+xml') resp['Last-Modified'] = icon.modified.strftime(_date_fmt) return resp
def serve(self, request, relative_path): # the following code is largely borrowed from `django.views.static.serve` # and django-filetransfers: filetransfers.backends.default full_path = self.get_full_path(relative_path) if not os.path.exists(full_path): raise Http404('"{0}" does not exist'.format(full_path)) # Respect the If-Modified-Since header. content_type = self.get_mimetype(relative_path) statobj = os.stat(full_path) if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'), statobj[stat.ST_MTIME], statobj[stat.ST_SIZE]): response = HttpResponseNotModified(content_type=content_type) else: response = HttpResponse(open(full_path, 'rb').read(), content_type=content_type) response["Last-Modified"] = http_date(statobj[stat.ST_MTIME]) response = self.prepare_response(request, response, relative_path) return response
def send_file_response(request, path, name, content_type, attachment=True): # Based on: django.views.static.serve # FIXME: If running on real Apache server, we should use "X-SENDFILE" header to let Apache # serve the file. It's much faster. Possibly will be fixed in Django 1.8. # See: http://django.readthedocs.org/en/latest/ref/request-response.html#django.http.FileResponse # FIXME: "Content-Disposition" filename is very fragile if contains non-ASCII characters. # Current implementation works on Firefox, but probably fails on other browsers. We should test # and fix it for them and/or sanitize and normalize file names. statobj = os.stat(path) if not stat.S_ISREG(statobj.st_mode): raise OSError(u'Not a regular file: {}'.format(path)) http_header = request.META.get(u'HTTP_IF_MODIFIED_SINCE') if not was_modified_since(http_header, statobj.st_mtime, statobj.st_size): return HttpResponseNotModified() response = FileResponse(open(path, u'rb'), content_type=content_type) response[u'Last-Modified'] = http_date(statobj.st_mtime) response[u'Content-Length'] = statobj.st_size if attachment: response[ u'Content-Disposition'] = "attachment; filename*=UTF-8''{}".format( urlquote(name)) return response
def _get_drops(self, drop_id): """Return (response, drops) for a request. response are errors and no-content/not-modified, otherwise None.""" if not check_drop_id(drop_id): return error('Invalid drop id'), None drops = Drop.objects.filter(drop_id=drop_id) try: have_since, since = self.get_if_modified_since() except ValueError as value_error: logger.warning('Could not parse modified-since header pack: %s', value_error) have_since, since = False, None if have_since: drops = drops.filter(created_at__gt=since) if not drops.exists(): if have_since: return HttpResponseNotModified(), None else: return HttpResponse(status=status.HTTP_204_NO_CONTENT), None return None, list(drops)
def dynamic_css(request, css): if not _dynamic_cssmap.has_key(css): raise Http404('CSS not found') files = _dynamic_cssmap[css] resp = HttpResponse(content_type='text/css') # We honor if-modified-since headers by looking at the most recently # touched CSS file. latestmod = 0 for fn in files: try: stime = os.stat(fn).st_mtime if latestmod < stime: latestmod = stime except OSError: # If we somehow referred to a file that didn't exist, or # one that we couldn't access. raise Http404('CSS (sub) not found') if request.META.has_key('HTTP_IF_MODIFIED_SINCE'): # This code is mostly stolen from django :) matches = re.match(r"^([^;]+)(; length=([0-9]+))?$", request.META.get('HTTP_IF_MODIFIED_SINCE'), re.IGNORECASE) header_mtime = parse_http_date(matches.group(1)) # We don't do length checking, just the date if int(latestmod) <= header_mtime: return HttpResponseNotModified(content_type='text/css') resp['Last-Modified'] = http_date(latestmod) for fn in files: with open(fn) as f: resp.write("/* %s */\n" % fn) resp.write(f.read()) resp.write("\n") return resp
def static_serve(request): path = request.GET.get('p') or '' file_path = posixpath.normpath(path) if not os.path.exists(file_path): raise Http404('"%s" does not exist' % file_path) if os.path.isdir(file_path): raise Http404('"%s" is dir' % file_path) statobj = os.stat(file_path) 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(file_path) content_type = content_type or 'application/octet-stream' response = FileResponse(open(file_path, '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
def serve(private_file): # Support If-Last-Modified if sys.version_info >= (3, ): mtime = private_file.modified_time.timestamp() else: mtime = time.mktime(private_file.modified_time.timetuple()) size = private_file.size if not was_modified_since( private_file.request.META.get('HTTP_IF_MODIFIED_SINCE'), mtime, size): return HttpResponseNotModified() # As of Django 1.8, FileResponse triggers 'wsgi.file_wrapper' in Django's WSGIHandler. # This uses efficient file streaming, such as sendfile() in uWSGI. # When the WSGI container doesn't provide 'wsgi.file_wrapper', it submits the file in 4KB chunks. if private_file.request.method == 'HEAD': # Avoid reading the file at all response = HttpResponse() else: response = FileResponse(private_file.open()) response['Content-Type'] = private_file.content_type response['Content-Length'] = size response["Last-Modified"] = http_date(mtime) return response
def get(self, request, download_target, filename): """ The view class for downloading files 2019-04-09 :param request: :return: HttpResponse """ if download_target == 'file': path = UPLOAD_DIR + filename else: path = PDF_DIR + filename if not os.path.isfile(path): raise Http404('"%s" does not exist' % path) stat = os.stat(path) content_type, encoding = mimetypes.guess_type(path) content_type = content_type or 'application/octet-stream' if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'), stat.st_mtime, stat.st_size): return HttpResponseNotModified(content_type=content_type) response = HttpResponse(open(path, 'rb').read(), content_type=content_type) response['Last-Modified'] = http_date(stat.st_mtime) response['Content-Length'] = stat.st_size if encoding: response['Content-Encoding'] = encoding return response
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') 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: 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( self.patch_error_template_name, RequestContext( request, { '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), }))) except FileNotFoundError as e: return HttpResponseServerError( render_to_string( self.error_template_name, RequestContext(request, { 'error': e, 'file': diff_info_or_response['diff_file'], }))) 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_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 = 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: 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 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 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 from six.moves.urllib.request import unquote 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(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(content_type=mimetype) contents = open(fullpath, 'rb').read() response = HttpResponse(contents, content_type=mimetype) response["Last-Modified"] = http_date(statobj[stat.ST_MTIME]) response["Content-Length"] = len(contents) return response
def test_not_modified_repr(self): response = HttpResponseNotModified() self.assertEqual(repr(response), '<HttpResponseNotModified status_code=304>')
def process_request(self, request): """Process the given request""" if self.is_asset_request(request): # Make sure we can convert this request into a location. if AssetLocator.CANONICAL_NAMESPACE in request.path: request.path = request.path.replace('block/', 'block@', 1) try: loc = StaticContent.get_location_from_path(request.path) except (InvalidLocationError, InvalidKeyError): return HttpResponseBadRequest() # Try and load the asset. content = None try: content = self.load_asset_from_location(loc) except (ItemNotFoundError, NotFoundError): return HttpResponseNotFound() # Set the basics for this request. newrelic.agent.add_custom_parameter('course_id', loc.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', True if is_from_cdn else False) # Check if this content is locked or not. locked = self.is_content_locked(content) newrelic.agent.add_custom_parameter('contentserver.locked', True if locked else False) # 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 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) range_len = last - first + 1 response['Content-Length'] = str(range_len) response.status_code = 206 # Partial Content newrelic.agent.add_custom_parameter( 'contentserver.range_len', range_len) 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 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 # 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_file_response(request, path): """ 返回下载文件流, 此处path为服务器上文件实际存储的位置 """ # 注释原因, 没看懂原代码是否有其他的安全考虑 Baixu 2020-07-08 # # 防止目录遍历漏洞 # path = posixpath.normpath(path).lstrip('/') # full_path = safe_join(document_root, path) full_path = path if os.path.isdir(full_path): raise Http404('Directory indexes are not allowed here.') if not os.path.exists(full_path): raise Http404('"%(path)s" does not exist' % {'path': full_path}) stat_obj = os.stat(full_path) # 判断下载过程中文件是否被修改过 if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'), stat_obj.st_mtime, stat_obj.st_size): return HttpResponseNotModified() # 获取文件的content_type content_type, encoding = mimetypes.guess_type(full_path) # content_type = content_type or 'application/octet-stream' content_type = 'application/octet-stream' # 计算读取文件的起始位置 start_bytes = re.search(r'bytes=(\d+)-', request.META.get('HTTP_RANGE', ''), re.S) print(request.META.get('HTTP_RANGE', '')) start_bytes = int(start_bytes.group(1)) if start_bytes else 0 # 打开文件并移动下标到起始位置,客户端点击继续下载时,从上次断开的点继续读取 the_file = open(full_path, 'rb') the_file.seek(start_bytes, os.SEEK_SET) # status=200表示下载开始,status=206表示下载暂停后继续,为了兼容火狐浏览器而区分两种状态 # 关于django的response对象,参考:https://www.cnblogs.com/scolia/p/5635546.html # 关于response的状态码,参考:https://www.cnblogs.com/DeasonGuan/articles/Hanami.html # FileResponse默认block_size = 4096,因此迭代器每次读取4KB数据 response = FileResponse(the_file, content_type=content_type, status=206 if start_bytes > 0 else 200) # 'Accept-Ranges' 设为 'bytes' 告诉客户端服务器支持按字节获取部分文件,以实现断点续传 response['Accept-Ranges'] = 'bytes' # 'Last-Modified'表示文件修改时间,与'HTTP_IF_MODIFIED_SINCE'对应使用,参考:https://www.jianshu.com/p/b4ecca41bbff response['Last-Modified'] = http_date(stat_obj.st_mtime) # 这里'Content-Length'表示剩余待传输的文件字节长度 if stat.S_ISREG(stat_obj.st_mode): response['Content-Length'] = stat_obj.st_size - start_bytes if encoding: response['Content-Encoding'] = encoding # 'Content-Range'的'/'之前描述响应覆盖的文件字节范围,起始下标为0,'/'之后描述整个文件长度,与'HTTP_RANGE'对应使用 # 参考:http://liqwei.com/network/protocol/2011/886.shtml response['Content-Range'] = 'bytes %s-%s/%s' % ( start_bytes, stat_obj.st_size - 1, stat_obj.st_size) # 'Cache-Control'控制浏览器缓存行为,此处禁止浏览器缓存,参考:https://blog.csdn.net/cominglately/article/details/77685214 response['Cache-Control'] = 'no-cache, no-store, must-revalidate' return response
def not_modified_response(self, *response_args, **response_kwargs): """Return :class:`django.http.HttpResponseNotModified` instance.""" return HttpResponseNotModified(*response_args, **response_kwargs)
def complete_task(request): data = request.POST Task.objects.filter(id=data[u'task_id']).update( completed=data[u'completed']) return HttpResponseNotModified()
def static_media(request, module, path, root=None): """ Serve static files below a given point in the directory structure. """ from django.utils.http import http_date from django.views.static import was_modified_since import mimetypes import os.path import posixpath import stat import urllib if root: document_root = root elif module == 'sentry': document_root = os.path.join(settings.MODULE_ROOT, 'static', module) elif module == dj_settings.COMPRESS_OUTPUT_DIR: document_root = os.path.join(dj_settings.STATIC_ROOT, module) elif module not in dj_settings.INSTALLED_APPS: raise Http404('Invalid module provided.') else: if module not in STATIC_PATH_CACHE: try: mod = __import__(module) except ImportError: raise Http404('Import error raised while fetching module') STATIC_PATH_CACHE[module] = os.path.normpath( os.path.join( os.path.dirname(mod.__file__), 'static', module, )) document_root = STATIC_PATH_CACHE[module] 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): 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 review_detail(request, review_request_id, local_site_name=None, template_name="reviews/review_detail.html"): """ Main view for review requests. This covers the review request information and all the reviews on it. """ # If there's a local_site passed in the URL, we want to look up the review # request based on the local_id instead of the pk. This allows each # local_site configured to have its own review request ID namespace # starting from 1. review_request, response = \ _find_review_request(request, review_request_id, local_site_name) if not review_request: return response reviews = review_request.get_public_reviews() review = review_request.get_pending_review(request.user) review_timestamp = 0 last_visited = 0 starred = False if request.user.is_authenticated(): # If the review request is public and pending review and if the user # is logged in, mark that they've visited this review request. if review_request.public and review_request.status == "P": visited, visited_is_new = ReviewRequestVisit.objects.get_or_create( user=request.user, review_request=review_request) last_visited = visited.timestamp visited.timestamp = datetime.now() visited.save() starred = review_request in \ request.user.get_profile().starred_review_requests.all() # Unlike review above, this covers replies as well. try: last_draft_review = Review.objects.filter( review_request=review_request, user=request.user, public=False).latest() review_timestamp = last_draft_review.timestamp except Review.DoesNotExist: pass draft = review_request.get_draft(request.user) # Find out if we can bail early. Generate an ETag for this. last_activity_time, updated_object = review_request.get_last_activity() if draft: draft_timestamp = draft.last_updated else: draft_timestamp = "" etag = "%s:%s:%s:%s:%s:%s" % (request.user, last_activity_time, draft_timestamp, review_timestamp, int(starred), settings.AJAX_SERIAL) if etag_if_none_match(request, etag): return HttpResponseNotModified() changedescs = review_request.changedescs.filter(public=True) try: latest_changedesc = changedescs.latest('timestamp') latest_timestamp = latest_changedesc.timestamp except ChangeDescription.DoesNotExist: latest_timestamp = None entries = [] for temp_review in reviews: temp_review.ordered_comments = \ temp_review.comments.order_by('filediff', 'first_line') state = '' # Mark as collapsed if the review is older than the latest change if latest_timestamp and temp_review.timestamp < latest_timestamp: state = 'collapsed' try: latest_reply = temp_review.public_replies().latest( 'timestamp').timestamp except Review.DoesNotExist: latest_reply = None # Mark as expanded if there is a reply newer than last_visited if latest_reply and last_visited and last_visited < latest_reply: state = '' entries.append({ 'review': temp_review, 'timestamp': temp_review.timestamp, 'class': state, }) for changedesc in changedescs: fields_changed = [] for name, info in changedesc.fields_changed.items(): multiline = False if 'added' in info or 'removed' in info: change_type = 'add_remove' # We don't hard-code URLs in the bug info, since the # tracker may move, but we can do it here. if (name == "bugs_closed" and review_request.repository.bug_tracker): bug_url = review_request.repository.bug_tracker for field in info: for i, buginfo in enumerate(info[field]): try: full_bug_url = bug_url % buginfo[0] info[field][i] = (buginfo[0], full_bug_url) except TypeError: logging.warning( "Invalid bugtracker url format") elif 'old' in info or 'new' in info: change_type = 'changed' multiline = (name == "description" or name == "testing_done") # Branch text is allowed to have entities, so mark it safe. if name == "branch": if 'old' in info: info['old'][0] = mark_safe(info['old'][0]) if 'new' in info: info['new'][0] = mark_safe(info['new'][0]) elif name == "screenshot_captions": change_type = 'screenshot_captions' else: # No clue what this is. Bail. continue fields_changed.append({ 'title': fields_changed_name_map.get(name, name), 'multiline': multiline, 'info': info, 'type': change_type, }) # Expand the latest review change state = '' # Mark as collapsed if the change is older than a newer change if latest_timestamp and changedesc.timestamp < latest_timestamp: state = 'collapsed' entries.append({ 'changeinfo': fields_changed, 'changedesc': changedesc, 'timestamp': changedesc.timestamp, 'class': state, }) entries.sort(key=lambda item: item['timestamp']) response = render_to_response( template_name, RequestContext( request, _make_review_request_context( review_request, { 'draft': draft, 'review_request_details': draft or review_request, 'entries': entries, 'last_activity_time': last_activity_time, 'review': review, 'request': request, 'PRE_CREATION': PRE_CREATION, }))) set_etag(response, etag) return response
def serve(request, path, document_root=None, show_indexes=False, insecure=False): """ Serve static files below a given point in the directory structure or from locations inferred from the static files finders. To use, put a URL pattern such as:: (r'^(?P<path>.*)$', 'django.contrib.staticfiles.views.serve') in your URLconf. If you provide the ``document_root`` parameter, the file won't be looked up with the staticfiles finders, but in the given filesystem path, e.g.:: (r'^(?P<path>.*)$', 'django.contrib.staticfiles.views.serve', {'document_root' : '/path/to/my/files/'}) 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``. """ if not settings.DEBUG and not insecure: raise ImproperlyConfigured("The view to serve static files can only " "be used if the DEBUG setting is True or " "the --insecure option of 'runserver' is " "used") if not document_root: absolute_path = finders.find(path) if not absolute_path: raise Http404('"%s" could not be found' % path) document_root, path = os.path.split(absolute_path) # 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, encoding = mimetypes.guess_type(fullpath) mimetype = mimetype 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) if encoding: response["Content-Encoding"] = encoding return response
def serve_private_media(request, path): """Serve a private media file with the webserver's "sendfile" if possible. Here's an example of how to use this function. The 'Document' model tracks files. It provides a 'get_file_path' method returning the absolute path to the actual file. The following view serves file only to users having the 'can_download' permission:: @permission_required('documents.can_download') def download_document(request, document_id): path = Document.objects.get(pk=document_id).get_file_path() return serve_private_media(request, path) If ``DEBUG`` is ``False`` and ``settings.GALLERY_SENDFILE_HEADER`` is set, this function sets a header and doesn't send the actual contents of the file. Use ``'X-Accel-Redirect'`` for nginx and ``'X-SendFile'`` for Apache with mod_xsendfile. Otherwise, this function behaves like Django's static serve view. ``path`` must be an absolute path. Depending on your webserver's configuration, you might want a full path or a relative path in the header's value. ``settings.GALLERY_SENDFILE_ROOT`` will be stripped from the beginning of the path to create the header's value. """ if not os.path.exists(path): # Don't reveal the file name on the filesystem. raise Http404("Requested file doesn't exist.") # begin copy-paste from django.views.static.serve statobj = os.stat(path) content_type, encoding = mimetypes.guess_type(path) content_type = content_type or 'application/octet-stream' if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'), statobj.st_mtime, statobj.st_size): # pragma: no cover return HttpResponseNotModified() # pause copy-paste from django.views.static.serve sendfile_header = getattr(settings, 'GALLERY_SENDFILE_HEADER', '') sendfile_root = getattr(settings, 'GALLERY_SENDFILE_ROOT', '') if settings.DEBUG or not sendfile_header: response = StreamingHttpResponse(open(path, 'rb'), content_type=content_type) else: response = HttpResponse('', content_type=content_type) if sendfile_root: if not path.startswith(sendfile_root): raise ValueError( "Requested file isn't under GALLERY_SENDFILE_ROOT.") path = path[len(sendfile_root):] response[sendfile_header] = path.encode(sys.getfilesystemencoding()) # resume copy-paste from django.views.static.serve response["Last-Modified"] = http_date(statobj.st_mtime) if stat.S_ISREG(statobj.st_mode): # pragma: no cover response["Content-Length"] = statobj.st_size if encoding: # pragma: no cover response["Content-Encoding"] = encoding # end copy-paste from django.views.static.serve return response
def get(self, request, *args, **kwargs): """Returns the last update made to the review request. This shows the type of update that was made, the user who made the update, and when the update was made. Clients can use this to inform the user that the review request was updated, or automatically update it in the background. This does not take into account changes to a draft review request, as that's generally not update information that the owner of the draft is interested in. Only public updates are represented. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST if not resources.review_request.has_access_permissions( request, review_request): return self.get_no_access_error(request) info = review_request.get_last_activity_info() timestamp = info['timestamp'] updated_object = info['updated_object'] changedesc = info['changedesc'] etag = encode_etag('%s:%s' % (timestamp, updated_object.pk)) if etag_if_none_match(request, etag): return HttpResponseNotModified() summary = None update_type = None if isinstance(updated_object, ReviewRequest): if updated_object.status == ReviewRequest.SUBMITTED: summary = _('Review request submitted') elif updated_object.status == ReviewRequest.DISCARDED: summary = _('Review request discarded') else: summary = _('Review request updated') update_type = 'review-request' elif isinstance(updated_object, DiffSet): summary = _('Diff updated') update_type = 'diff' elif isinstance(updated_object, Review): if updated_object.is_reply(): summary = _('New reply') update_type = 'reply' else: summary = _('New review') update_type = 'review' else: # Should never be able to happen. The object will always at least # be a ReviewRequest. assert False if changedesc: user = changedesc.get_user(review_request) else: # There is no changedesc which means this review request hasn't # been changed since it was first published, so this change must # be due to the original submitter. user = review_request.submitter return 200, { self.item_result_key: { 'timestamp': timestamp, 'user': user, 'summary': summary, 'type': update_type, } }, { 'ETag': etag, }
def not_modified(self, data=''): return HttpResponseNotModified(data)
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