def _update_response_headers(self, request, response, headers): """ Combine all headers that were set by the different content types We are interested in Cache-Control, Last-Modified, Expires """ from django.utils.http import http_date # Ideally, for the Cache-Control header, we'd want to do some intelligent # combining, but that's hard. Let's just collect and unique them and let # the client worry about that. cc_headers = set() for x in (cc.split(",") for cc in headers.get('Cache-Control', ())): cc_headers |= set((s.strip() for s in x)) if len(cc_headers): response['Cache-Control'] = ", ".join(cc_headers) else: # Default value response['Cache-Control'] = 'no-cache, must-revalidate' # Check all Last-Modified headers, choose the latest one lm_list = [parsedate(x) for x in headers.get('Last-Modified', ())] if len(lm_list) > 0: response['Last-Modified'] = http_date(mktime(max(lm_list))) # Check all Expires headers, choose the earliest one lm_list = [parsedate(x) for x in headers.get('Expires', ())] if len(lm_list) > 0: response['Expires'] = http_date(mktime(min(lm_list)))
def put_object_headers(response, meta, restricted=False, token=None): response['ETag'] = meta['checksum'] response['Content-Length'] = meta['bytes'] response.override_serialization = True response['Content-Type'] = meta.get('type', 'application/octet-stream') response['Last-Modified'] = http_date(int(meta['modified'])) if not restricted: response['X-Object-Hash'] = meta['hash'] response['X-Object-UUID'] = meta['uuid'] if TRANSLATE_UUIDS: meta['modified_by'] = \ retrieve_displayname(token, meta['modified_by']) response['X-Object-Modified-By'] = smart_str( meta['modified_by'], strings_only=True) response['X-Object-Version'] = meta['version'] response['X-Object-Version-Timestamp'] = http_date( int(meta['version_timestamp'])) for k in [x for x in meta.keys() if x.startswith('X-Object-Meta-')]: response[smart_str( k, strings_only=True)] = smart_str(meta[k], strings_only=True) for k in ( 'Content-Encoding', 'Content-Disposition', 'X-Object-Manifest', 'X-Object-Sharing', 'X-Object-Shared-By', 'X-Object-Allowed-To', 'X-Object-Public'): if k in meta: response[k] = smart_str(meta[k], strings_only=True) else: for k in ('Content-Encoding', 'Content-Disposition'): if k in meta: response[k] = smart_str(meta[k], strings_only=True)
def send_file(request, filepath, last_modified=None, filename=None): fullpath = filepath # Respect the If-Modified-Since header. statobj = os.stat(fullpath) if filename: mimetype, encoding = mimetypes.guess_type(filename) else: mimetype, encoding = mimetypes.guess_type(fullpath) mimetype = mimetype or 'application/octet-stream' response = HttpResponse(open(fullpath, 'rb').read(), mimetype=mimetype) if not last_modified: response["Last-Modified"] = http_date(statobj.st_mtime) else: if isinstance(last_modified, datetime): last_modified = float(dateformat.format(last_modified, 'U')) response["Last-Modified"] = http_date(epoch_seconds=last_modified) response["Content-Length"] = statobj.st_size if encoding: response["Content-Encoding"] = encoding # TODO: Escape filename if filename: response["Content-Disposition"] = "attachment; filename=%s" % filename.encode('utf-8') return response
def serve(request, path, **kwargs): if not settings.DEBUG and not kwargs.get("insecure"): raise ImproperlyConfigured( "The gears view can only be used in debug mode or if the " "--insecure option of 'runserver' is used." ) # It is only required check because we generate # version arg for each file if "HTTP_IF_MODIFIED_SINCE" in request.META: response = HttpResponse() response["Expires"] = http_date(time.time() + MAX_AGE) response.status_code = 304 return response normalized_path = posixpath.normpath(parse.unquote(path)).lstrip("/") try: asset = build_asset(environment, normalized_path) except FileNotFound: return staticfiles_serve(request, path, **kwargs) last_modified = asset.mtime if request.GET.get("body"): asset = asset.processed_source mimetype, encoding = mimetypes.guess_type(normalized_path) mimetype = mimetype or "application/octet-stream" response = HttpResponse(asset, mimetype=mimetype) if encoding: response["Content-Encoding"] = encoding response["Last-Modified"] = http_date(last_modified) return response
def test_cache_conditional_get_last_modified_expired(self, mock_requests): """ Tests that the cache performs a conditional GET request when asked to update the response for a URL with a Last-Modified header, which has since expired. """ last_modified = http_date(time.time() - 3600) self.set_mock_response(mock_requests, headers={ 'Last-Modified': last_modified }) cache = HttpCache(self.cache_directory) url = 'http://example.com' cache.update(url) # Set a new Last-Modified and content value new_last_modified = http_date(time.time()) self.response_content = b'Response' self.set_mock_response(mock_requests, headers={ 'Last-Modified': new_last_modified }) # Run the update again response, updated = cache.update(url) self.assertTrue(updated) self.assertEqual(200, response.status_code) # The new content is found in the cache self.assertEqual(self.response_content, cache.get_content(url)) # The new Last-Modified is found in the headers cache self.assertEqual( new_last_modified, cache.get_headers(url)['Last-Modified'] )
def qrcode(req, width): import qr url = req.GET.get('url') if url is None: raise Http404 try: data = url.encode('ascii') except UnicodeError: # only supports URLs properly urlencoded raise Http404 if width == "480": magnify = 8 else: magnify = 4 buf = StringIO() try: qr.qrcode(data, buf, format=qr.GIF, magnify=magnify) except ValueError: # qr module wasn't be compiled with GD library raise Http404 content = buf.getvalue() CACHE_TIMEOUT = 86400 res = HttpResponse(content, content_type='image/gif') res['Content-Length'] = str(len(content)) res['ETag'] = '"%s"' % md5(content).hexdigest() res['Last-Modified'] = http_date() res['Expires'] = http_date(time.time() + CACHE_TIMEOUT) patch_cache_control(res, max_age=CACHE_TIMEOUT) return res
def border(req, style, rgb): import gd rgb = tuple(map(lambda x: int(x, 16), (rgb[0:2], rgb[2:4], rgb[4:6]))) try: width = int(req.GET.get('w', 228)) except (ValueError, TypeError): width = 228 try: height = int(req.GET.get('h', 1)) except (ValueError, TypeError): height = 1 if width < 1 or height < 1: raise Http404 if rgb != (0, 0, 0): # if line is black, then use white(#FFFFF) as background color backcolor = (255, 255, 255) else: backcolor = (0, 0, 0) # TODO # check display width img = gd.image((width, height)) back = img.colorAllocate(backcolor) img.colorTransparent(back) color = img.colorAllocate(rgb) if style == 'dotted': pattern = (color, color, back, back) elif style == 'dashed': pattern = (color, color, color, back, back, back) else: # solid pattern = (color,) img.setStyle(pattern) for y in xrange(height): img.line((0, y), (width, y), gd.gdStyled) fp = StringIO() img.writeGif(fp) content = fp.getvalue() fp.close() content_type = 'image/gif' res = HttpResponse(content, content_type=content_type) res['Content-Type'] = content_type res['Content-Length'] = str(len(content)) res['ETag'] = '"%s"' % md5(content).hexdigest() res['Last-Modified'] = http_date() res['Expires'] = http_date(time.time() + CACHE_TIMEOUT) patch_cache_control(res, max_age=CACHE_TIMEOUT) return res
def test_should_regenerate(self, mocktime): now = 1319128343 mocktime.time.return_value = now cm = CachingMixin() response = HttpResponse() response['Last-Modified'] = http_date(now) self.assertFalse(cm.should_regenerate(response)) response['Last-Modified'] = http_date(now - (100 + settings.BETTERCACHE_LOCAL_POSTCHECK)) self.assertTrue(cm.should_regenerate(response))
def _image_response(image): response = HttpResponse( image.render(), image.mimetype ) response['Last-Modified'] = http_date(image.modified) expire_time = getattr(settings, 'IMAGEFIT_EXPIRE_HEADER', 3600*24*30) response['Expires'] = http_date(time.time() + expire_time) return response
def media(request, path): fullpath = os.path.join(settings.STATIC_MEDIA_ROOT, path) mimetype = mimetypes.guess_type(fullpath)[0] or 'application/octet-stream' # Rendering directory listing if os.path.isdir(fullpath): return directory_index(path, fullpath) # Render single file if not os.path.isdir('%s.d' % fullpath): try: modified = os.stat(fullpath)[stat.ST_MTIME] except OSError: raise Http404() if not was_modified_since( request.META.get('HTTP_IF_MODIFIED_SINCE'), modified, ): return HttpResponseNotModified(content_type=mimetype) contents = render_file(fullpath) response = HttpResponse(contents, content_type=mimetype) response['Last-Modified'] = http_date(modified) response['Content-Length'] = len(contents) return response # Render .d directory latest = -1 filenames = [] for root, _, files in os.walk('%s.d' % fullpath, followlinks=True): for filename in [os.path.join(root, x) for x in files]: if filename.endswith('~'): continue filenames.append(filename) latest = max(latest, os.stat(filename)[stat.ST_MTIME]) if not was_modified_since( request.META.get('HTTP_IF_MODIFIED_SINCE'), latest, ): return HttpResponseNotModified(content_type=mimetype) contents = "" for filename in sorted(filenames): contents += render_file(filename) response = HttpResponse(contents, content_type=mimetype) response['Last-Modified'] = http_date(latest) response['Content-Length'] = len(contents) return response
def wrapper(*args, **kwargs): response = another_view_func(*args, **kwargs) if isinstance(response, http.HttpResponse) \ and not settings.DEBUG: expiry = time.time() + cache_duration response['Expires'] = http_date(expiry) response['X-Cache-Expires'] = http_date(expiry) response['X-Cache-Time'] = http_date() response['X-Cache'] = 'Miss' patch_cache_control(response, max_age=cache_duration) return response
def cache_headers(response, request, exercise, flag=False): if ( not flag and request.method == 'GET' and not exercise.get('personalized', False) and exercise.get('cacheable', True) ): response['Last-Modified'] = http_date(exercise['mtime']) expiry = exercise.get('expiry_minutes', settings.DEFAULT_EXPIRY_MINUTES) if expiry > 0: response['Expires'] = http_date(time.time() + expiry * 60) return response
def _process_request(self, request): # We won't to refresh dev names for static requests. # So once static content generated it becomes cached # on the browser until changed if request.path.startswith(DEV_MEDIA_URL) and 'HTTP_IF_MODIFIED_SINCE' in request.META: response = HttpResponse() response['Expires'] = http_date(time.time() + self.MAX_AGE) response.status_code = 304 return response # We refresh the dev names only once for the whole request, so all # media_url() calls are cached. # _refresh_dev_names() if not self.names_generated: _refresh_dev_names() self.names_generated = True if not request.path.startswith(DEV_MEDIA_URL): return filename = request.path[len(DEV_MEDIA_URL):] try: backend = _backend_mapping[filename] except KeyError: raise Http404('The mediagenerator could not find the media file "%s"' % filename) content, mimetype = backend.get_dev_output(filename) print "MIME", mimetype, filename if not mimetype: if filename.endswith('.woff'): mimetype = 'application/x-font-woff' else: mimetype = 'application/octet-stream' if isinstance(content, unicode): content = content.encode('utf-8') if mimetype.startswith('text/') or mimetype in TEXT_MIME_TYPES: mimetype += '; charset=utf-8' response = HttpResponse(content, content_type=mimetype) response['Content-Length'] = len(content) # Cache manifest files MUST NEVER be cached or you'll be unable to update # your cached app!!! if response['Content-Type'] != 'text/cache-manifest' and \ response.status_code == 200: patch_cache_control(response, public=True, max_age=self.MAX_AGE) response['Expires'] = http_date(time.time() + self.MAX_AGE) response['Last-Modified'] = http_date(time.time()) return response
def http_date(timestamp): """ A wrapper around Django's http_date that accepts DateFields and datetime objects directly. """ from django.utils.http import http_date if isinstance(timestamp, (DateField, datetime)): return http_date(time.mktime(timestamp.timetuple())) elif isinstance(timestamp, basestring): return timestamp else: return http_date(timestamp)
def serialize_items(self, request, language, queryset): default_host = settings.XMPP_HOSTS[settings.DEFAULT_XMPP_HOST] base_url = default_host['CANONICAL_BASE_URL'] title = self.get_feed_title(request) feed_url = request.build_absolute_uri(reverse('blog:home')) # see: http://www.feedvalidator.org/docs/warning/MissingAtomSelfLink.html href = request.build_absolute_uri(request.get_full_path()) root = etree.Element("rss", version="2.0", nsmap={ 'atom': self.atom_ns, }) channel = self.sub(root, 'channel') self.sub(channel, 'title', title) self.sub(channel, 'link', feed_url) self.sub(channel, 'description', _('Follow recent updates for %s') % request.site['BRAND']) self.sub(channel, 'language', language) self.sub(channel, 'lastBuildDate', http_date()) skipHours = self.sub(channel, 'skipHours') for i in range(0, 7): self.sub(skipHours, 'hour', text=str(i)) # add image image = self.sub(channel, 'image') self.sub(image, 'title', title) self.sub(image, 'link', feed_url) self.sub(image, 'url', request.build_absolute_uri(static('feed/rss.png'))) self.sub(image, 'width', '120') self.sub(image, 'height', '120') # add url (NOTE: This does not have anything to do with the Atom standard) self.sub(channel, '{%s}link' % self.atom_ns, rel='self', type='application/rss+xml', href=href) for post in queryset: canonical_url = post.get_canonical_url() content = absolutify_html(post.get_html_summary(request), base_url) item = self.sub(channel, 'item') self.sub(item, 'title', post.title.current) self.sub(item, 'description', content) self.sub(item, 'link', canonical_url) self.sub(item, 'guid', canonical_url, isPermaLink='true') self.sub(item, 'pubDate', http_date(post.created.timestamp())) # We do not add an author element, because this *requires* an email address. #self.sub(item, 'author', post.author.node) return root
def test_precondition_failed_last_modified(self): "Test precondition using last-modified dates." from datetime import datetime, timedelta from django.utils.http import http_date last_modified_date = datetime.now() class PreconditionResource(Resource): use_etags = False use_last_modified = True def put(self, request): pass def get(self, request): return {} def get_last_modified(self, request, *args, **kwargs): return last_modified_date resource = PreconditionResource() # Send non-safe request with a old last-modified date.. fail if_modified_since = http_date(timegm((last_modified_date - timedelta(seconds=10)).utctimetuple())) request = self.factory.put( "/", data='{"message": "hello world"}', content_type="application/json", HTTP_IF_UNMODIFIED_SINCE=if_modified_since, ) response = resource(request) self.assertEqual(response.status_code, codes.precondition_failed) self.assertEqual(response["Content-Type"], "application/json") self.assertTrue("no-cache" in response["Cache-Control"]) self.assertTrue("must-revalidate" in response["Cache-Control"]) self.assertTrue("max-age=0" in response["Cache-Control"]) # Old last-modified on GET, updated content is returned if_modified_since = http_date(timegm((last_modified_date - timedelta(seconds=10)).utctimetuple())) request = self.factory.get("/", HTTP_IF_MODIFIED_SINCE=if_modified_since) response = resource(request) self.assertEqual(response.status_code, codes.ok) self.assertEqual(response["Content-Type"], "application/json") # Mimic future request on GET, resource not modified if_modified_since = http_date(timegm((last_modified_date + timedelta(seconds=20)).utctimetuple())) request = self.factory.get("/", HTTP_IF_MODIFIED_SINCE=if_modified_since) response = resource(request) self.assertEqual(response.status_code, codes.not_modified) self.assertEqual(response["Content-Type"], "application/json")
def patch_cache_headers(response, timestamp=None, cache_timeout=None): if timestamp is None: timestamp = time.time() * 1000 timestamp = int(timestamp) response['Last-Modified'] = http_date(timestamp / 1000) response['ETag'] = '"' + str(timestamp) + '"' if cache_timeout != None and cache_timeout > 0: timeout_str = str(cache_timeout) response['Cache-Control'] = 'private, max-age=' + timeout_str response['Expires'] = http_date(time.time() + cache_timeout) else: response['Cache-Control'] = 'private, max-age=0, post-check=0, pre-check=0, must-revalidate'
def inner(request, *args, **kwargs): # 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 = get_conditional_response( request, etag=res_etag, last_modified=res_last_modified, ) 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 download(request, path): """ Downloads a file. This is inspired by django.views.static.serve. ?disposition={attachment, inline} """ if not request.fs.exists(path): raise Http404(_("File not found: %(path)s.") % {'path': escape(path)}) if not request.fs.isfile(path): raise PopupException(_("'%(path)s' is not a file.") % {'path': path}) mimetype = mimetypes.guess_type(path)[0] or 'application/octet-stream' stats = request.fs.stats(path) mtime = stats['mtime'] size = stats['size'] if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'), mtime, size): return HttpResponseNotModified() # TODO(philip): Ideally a with statement would protect from leaks, # but tricky to do here. fh = request.fs.open(path) response = HttpResponse(_file_reader(fh), mimetype=mimetype) response["Last-Modified"] = http_date(stats['mtime']) response["Content-Length"] = stats['size'] response['Content-Disposition'] = request.GET.get('disposition', 'attachment') return response
def patch_response_headers(response, cache_timeout=None): """ Add HTTP caching headers to the given HttpResponse: Expires and Cache-Control. Each header is only added if it isn't already set. cache_timeout is in seconds. The CACHE_MIDDLEWARE_SECONDS setting is used by default. """ if cache_timeout is None: cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS if cache_timeout < 0: cache_timeout = 0 # Can't have max-age negative if settings.USE_ETAGS and not response.has_header('ETag'): warnings.warn( "The USE_ETAGS setting is deprecated in favor of " "ConditionalGetMiddleware which sets the ETag regardless of the " "setting. patch_response_headers() won't do ETag processing in " "Django 2.1.", RemovedInDjango21Warning ) if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback(set_response_etag) else: response = set_response_etag(response) if not response.has_header('Expires'): response['Expires'] = http_date(time.time() + cache_timeout) patch_cache_control(response, max_age=cache_timeout)
def process_request(self, request): if not MEDIA_DEV_MODE: return # We refresh the dev names only once for the whole request, so all # media_url() calls are cached. _refresh_dev_names() if not request.path.startswith(DEV_MEDIA_URL): return filename = request.path[len(DEV_MEDIA_URL):] try: backend = _backend_mapping[filename] except KeyError: raise Http404('No such media file "%s"' % filename) content, mimetype = backend.get_dev_output(filename) response = HttpResponse(content, content_type=mimetype) response['Content-Length'] = len(content) # Cache manifest files MUST NEVER be cached or you'll be unable to update # your cached app!!! if response['Content-Type'] != 'text/cache-manifest' and \ response.status_code == 200: patch_cache_control(response, public=True, max_age=self.MAX_AGE) response['Expires'] = http_date(time.time() + self.MAX_AGE) return response
def _image_response(image): response = HttpResponse( image.render(), image.mimetype ) response['Last-Modified'] = http_date(image.modified) return response
def sitemap(request, sitemaps, section=None, template_name='sitemap.xml', content_type='application/xml'): req_protocol = request.scheme req_site = get_current_site(request) if section is not None: if section not in sitemaps: raise Http404("No sitemap available for section: %r" % section) maps = [sitemaps[section]] else: maps = list(six.itervalues(sitemaps)) page = request.GET.get("p", 1) urls = [] for site in maps: try: if callable(site): site = site() urls.extend(site.get_urls(page=page, site=req_site, protocol=req_protocol)) except EmptyPage: raise Http404("Page %s empty" % page) except PageNotAnInteger: raise Http404("No page '%s'" % page) response = TemplateResponse(request, template_name, {'urlset': urls}, content_type=content_type) if hasattr(site, 'latest_lastmod'): # if latest_lastmod is defined for site, set header so as # ConditionalGetMiddleware is able to send 304 NOT MODIFIED response['Last-Modified'] = http_date( timegm(site.latest_lastmod.utctimetuple())) return response
def list(self, request, **kwargs): if_modified_since = request.headers.get('If-Modified-Since') if if_modified_since: if_modified_since = parse_http_date_safe(if_modified_since) if_unmodified_since = request.headers.get('If-Unmodified-Since') if if_unmodified_since: if_unmodified_since = parse_http_date_safe(if_unmodified_since) if not hasattr(request, 'event'): return super().list(request, **kwargs) lmd = request.event.logentry_set.filter( content_type__model=self.queryset.model._meta.model_name, content_type__app_label=self.queryset.model._meta.app_label, ).aggregate( m=Max('datetime') )['m'] if lmd: lmd_ts = timegm(lmd.utctimetuple()) if if_unmodified_since and lmd and lmd_ts > if_unmodified_since: return HttpResponse(status=412) if if_modified_since and lmd and lmd_ts <= if_modified_since: return HttpResponse(status=304) resp = super().list(request, **kwargs) if lmd: resp['Last-Modified'] = http_date(lmd_ts) return resp
def patch_headers(self, response): """Set the headers we want for caching.""" # Remove Vary:Cookie if we want to cache non-anonymous if not getattr(settings, 'BETTERCACHE_ANONYMOUS_ONLY', False): vdict = get_header_dict(response, 'Vary') try: vdict.pop('cookie') except KeyError: pass else: set_header_dict(response, 'Vary', vdict) # Set max-age, post-check and pre-check cc_headers = get_header_dict(response, 'Cache-Control') try: timeout = cc_headers['max-age'] except KeyError: timeout = settings.BETTERCACHE_CACHE_MAXAGE cc_headers['max-age'] = timeout # This should never happen but let's be safe if timeout is 0: return response if not 'pre-check' in cc_headers: cc_headers['pre-check'] = timeout if not 'post-check' in cc_headers: cc_headers['post-check'] = int(timeout * settings.BETTERCACHE_EDGE_POSTCHECK_RATIO) set_header_dict(response, 'Cache-Control', cc_headers) # this should be the main/first place we're setting edge control so we can just set what we want ec_dict = {'cache-maxage' : settings.BETTERCACHE_EDGE_MAXAGE} set_header_dict(response, 'Edge-Control', ec_dict) response['Last-Modified'] = http_date() return response
def process_response(self, request, response): response['Date'] = http_date() if not response.has_header('Content-Length'): response['Content-Length'] = str(len(response.content)) if response.has_header('ETag'): if_none_match = request.META.get('HTTP_IF_NONE_MATCH') if if_none_match == response['ETag']: # Setting the status is enough here. The response handling path # automatically removes content for this status code (in # http.conditional_content_removal()). response.status_code = 304 if response.has_header('Last-Modified'): if_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE') if if_modified_since is not None: try: # IE adds a length attribute to the If-Modified-Since header separator = if_modified_since.index(';') if_modified_since = if_modified_since[0:separator] except: pass if_modified_since = parse_http_date_safe(if_modified_since) if if_modified_since is not None: last_modified = parse_http_date_safe(response['Last-Modified']) if last_modified is not None and last_modified <= if_modified_since: # Setting the status code is enough here (same reasons as # above). response.status_code = 304 return response
def GET(self, request, spot_id, image_id, thumb_width, thumb_height): try: img = SpotImage.objects.get(pk=image_id) spot = img.spot if int(spot.pk) != int(spot_id): raise Exception("Image Spot ID doesn't match spot id in url") thumb_width = int(thumb_width) thumb_height = int(thumb_height) except Exception as e: response = HttpResponse('{"error":"Bad Image URL"}') response.status_code = 404 return response if thumb_height <= 0 or thumb_width <= 0: response = HttpResponse('{"error":"Bad Image URL"}') response.status_code = 404 return response image = img.image im = Image.open(image.path) thumb = im.resize((thumb_width, thumb_height), Image.ANTIALIAS) tmp = StringIO() thumb.save(tmp, im.format) tmp.seek(0) response = HttpResponse(tmp.getvalue()) # 7 day timeout? response['Expires'] = http_date(time.time() + 60 * 60 * 24 * 7) response["Content-type"] = img.content_type return response
def test_was_modified_since_fp(self): """ A floating point mtime does not disturb was_modified_since (#18675). """ mtime = 1343416141.107817 header = http_date(mtime) self.assertFalse(was_modified_since(header, mtime))
def get(self, request, fid, cid): cf = get_object_or_404(ContactField, pk=fid) if not perms.c_can_view_fields_cg(request.user.id, cf.contact_group_id): raise PermissionDenied fullpath = os.path.join(settings.MEDIA_ROOT, 'fields', fid, cid) if not os.path.exists(fullpath): raise Http404(_('"{path}" does not exist').format(path=fullpath)) # Respect the If-Modified-Since header. statobj = os.stat(fullpath) if not static.was_modified_since( request.META.get('HTTP_IF_MODIFIED_SINCE'), statobj.st_mtime, statobj.st_size): return HttpResponseNotModified() # START OF content_type detection cfv = get_object_or_404(ContactFieldValue, contact_id=cid, contact_field_id=fid) fileinfo = json.loads(cfv.value) content_type = fileinfo['content_type'] # END OF content_type detection 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 response['Content-Disposition'] = 'inline; filename="{0}"'.format( header_encode(fileinfo['filename'].encode('utf-8'), 'utf-8')) return response
def process_response(self, request, response): response['Date'] = http_date() if not response.streaming and not response.has_header('Content-Length'): response['Content-Length'] = str(len(response.content)) if response.has_header('ETag'): if_none_match = request.META.get('HTTP_IF_NONE_MATCH') if if_none_match == response['ETag']: # Setting the status is enough here. The response handling path # automatically removes content for this status code (in # http.conditional_content_removal()). response.status_code = 304 # Last-Modified 用于指示最后修改的时间 if response.has_header('Last-Modified'): if_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE') if if_modified_since is not None: if_modified_since = parse_http_date_safe(if_modified_since) if if_modified_since is not None: last_modified = parse_http_date_safe(response['Last-Modified']) if last_modified is not None and last_modified <= if_modified_since: # Setting the status code is enough here (same reasons as # above). response.status_code = 304 return response
def __call__( self, environ, start_response ): def done( status, headers, output ): # a good place for debug loging # e.g. logger.debug('done from self.static_file_root: %s' %self.static_file_root, status, headers) start_response( status, headers.items() ) return output path_info = environ['PATH_INFO'] if path_info[0] == '/': path_info = path_info[1:] file_path = os.path.normpath( os.path.join( self.static_file_root, path_info ) ) # prevent escaping out of paths below media root (e.g. via "..") if not file_path.startswith( self.static_file_root ): status = '401 UNAUTHORIZED' headers = {'Content-type': 'text/plain'} output = ['Permission denied. illegal path'] return done( status, headers, output ) # only allow GET or HEAD requests e.g. not PUT, DELETE, POST, etc. if not (environ['REQUEST_METHOD'] == 'GET' or environ['REQUEST_METHOD'] == 'HEAD'): status = '405 METHOD NOT ALLOWED' headers = {'Content-type': 'text/plain'} output = SimpleResponse(['405 method not allowed']) output.status_code = 405 return done(status, headers, output) if not os.path.exists( file_path ): status = '404 NOT FOUND' headers = {'Content-type': 'text/plain'} output = SimpleResponse(['Page not found: %s' % file_path]) output.status_code = 404 return done( status, headers, output ) try: fp = open( file_path, 'rb' ) except IOError: status = '401 UNAUTHORIZED' headers = {'Content-type': 'text/plain'} output = SimpleResponse(['Permission denied: %s' % file_path]) output.status_code = 401 return done( status, headers, output ) # This is a very simple implementation of conditional GET with # the Last-Modified header. It makes media files a bit speedier # because the files are only read off disk for the first request # (assuming the browser/client supports conditional GET). # mtime needs to be ascii not unicode as django is all unicode need to do conversion mtime = http_date( os.stat(file_path)[stat.ST_MTIME] ).encode('ascii', 'ignore') headers = {'Last-Modified': mtime} if environ.get('HTTP_IF_MODIFIED_SINCE', None) == mtime: status = '304 NOT MODIFIED' output = SimpleResponse() output.status_code = 304 else: status = '200 OK' mime_type = mimetypes.guess_type(file_path)[0] if mime_type: headers['Content-Type'] = mime_type # naive version with whole file read as a string place in a list # output = [fp.read()] # fp.close() # use BlockIteratorResponse for larger file/network efficiency output = BlockIteratorResponse(fp) return done( status, headers, output )
def list_actions(request): can_add = request.user.has_perm('actions.add_action') if request.method == 'POST' and can_add: form = ActionForm(request.POST) if form.is_valid(): action = form.save() return redirect(action.get_absolute_url()) else: print(form.errors) qset, ctx = _get_actions(request, include_future=False) if not ctx.get('is_cal'): actions = Action.objects.for_user(request.user).filter(when__gte=now()) ctx['upcoming'] = actions[:6] else: actions = None current_date = ctx['current_date'] ctx['next_month'] = current_date + timedelta(days=31) ctx['last_month'] = current_date + timedelta(days=-1) cal_days = list( calendar.Calendar(firstweekday=6).itermonthdates( current_date.year, current_date.month)) this_month = [] this_week = [] month_actions = defaultdict(list) for action in qset: # Convert day to local day so actions land in the right day for current view. day = action.when.astimezone(tz.tzlocal()).date() month_actions[day].append(action) event_colors = { 'talk': 'xr-bg-pink', 'action': 'xr-bg-green', 'ally': 'xr-bg-light-green', 'meeting': 'xr-bg-lemon', 'orientation': 'xr-bg-purple', 'art': 'xr-bg-warm-yellow', 'nvda': 'xr-bg-light-blue', 'regen': 'xr-warm-yellow xr-bg-dark-blue', } for daynum, mdate in enumerate(cal_days, 1): todays_actions = month_actions[mdate] obj = { 'day': mdate, 'events': todays_actions, 'bg': '', } if mdate.month == current_date.month: for a in todays_actions: tagnames = a.tags.names() for t in a.tags.names(): color = event_colors.get(t, None) if color: obj['bg'] = color break else: # previous month obj['bg'] = 'bg-light' if mdate == ctx['today']: obj['today'] = True this_week.append(obj) if daynum % 7 == 0: this_month.append(this_week) this_week = [] if this_week: this_month.append(this_week) ctx['month'] = this_month ctx['can_add'] = can_add if ctx['can_add']: ctx['form'] = ActionForm() calendar_link = 'webcal://{}/action/ical/XR%20Mass%20Events'.format( request.get_host()) link_pars = {} if request.user.is_authenticated: link_pars['token'] = signing.Signer().sign(request.user.id) if ctx.get('current_tag'): link_pars['tag'] = ctx.get('current_tag') ctx['calendar_link'] = calendar_link + '?' + urlencode(link_pars) resp = render(request, 'list_actions.html', ctx) resp['Vary'] = 'Cookie' if request.user.is_authenticated: resp['Cache-Control'] = 'private' if actions: resp['Last-Modified'] = http_date(actions.last().when.timestamp()) return resp
def test_correct_signature(self): now = http_date() signature = make_signature(self.mouse, self.rat.inbox, now) return self.send_follow(self.mouse, signature, now).status_code == 200
def render_file(request, path): """ Returns a resized version of the given photo. """ path = clean_path(path) # check input form = PhotoForm(request.GET) if not form.is_valid(): return HttpResponseBadRequest() # check permissions if not has_permission(posixpath.dirname(path), 'can_read', request.user): return HttpResponseForbidden() # check file exists filepath = os.path.join(settings.COCONUTS_DATA_ROOT, url2path(path)) if not os.path.exists(filepath): raise Http404 def create_cache_dir(cachefile): cachedir = os.path.dirname(cachefile) if not os.path.exists(cachedir): try: os.makedirs(cachedir) except OSError: # FIXME: checking then creating creates a race condition, # the directory can be created between these two steps pass mimetype = mimetypes.guess_type(filepath)[0] ratio = 0.75 size = form.cleaned_data['size'] cachesize = size, int(size * ratio) if mimetype in IMAGE_TYPES: # check thumbnail cachefile = os.path.join(settings.COCONUTS_CACHE_ROOT, str(size), url2path(path)) if not os.path.exists(cachefile): create_cache_dir(cachefile) img = Image.open(filepath) # rotate if needed orientation = get_image_exif(img).get(EXIF_ORIENTATION) if orientation: img = img.rotate(ORIENTATIONS[orientation][2], Image.NEAREST, True) img.thumbnail(cachesize, Image.ANTIALIAS) img.save(cachefile, quality=90) elif mimetype in VIDEO_TYPES: mimetype = 'image/jpeg' path += '.jpg' cachefile = os.path.join(settings.COCONUTS_CACHE_ROOT, str(size), url2path(path)) if not os.path.exists(cachefile): create_cache_dir(cachefile) info = get_video_info(filepath) pic_ratio = float(info['height']) / float(info['width']) if pic_ratio > ratio: width = int(cachesize[1] / pic_ratio) height = cachesize[1] else: width = cachesize[0] height = int(cachesize[0] * pic_ratio) subprocess.check_call([ 'avconv', '-loglevel', 'quiet', '-i', filepath, '-s', '%sx%s' % (width, height), '-vframes', '1', cachefile ]) else: # unhandled file type return HttpResponseBadRequest() # serve the photo if hasattr(settings, 'COCONUTS_CACHE_ACCEL'): response = HttpResponse() response['X-Accel-Redirect'] = posixpath.join( settings.COCONUTS_CACHE_ACCEL, str(size), path) else: response = django.views.static.serve( request, posixpath.join(str(size), path), document_root=settings.COCONUTS_CACHE_ROOT) response['Content-Type'] = mimetype response['Expires'] = http_date(time.time() + 3600 * 24 * 365) 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 dispatch(self, request, *args, **kwargs): response = super().dispatch(request, *args, **kwargs) if not self.is_modified(request): return HttpResponseNotModified() response['Last-Modified'] = http_date(self.last_timestamp) return response
def wrapper(request, *args, **kwargs): response = func(request, *args, **kwargs) response['Last-Modified'] = http_date() return response
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 view_summary(request, period='month', year=None, month=None): reference = datetime.now() year = reference.year if year is None else int(year) month = reference.month if month is None else int(month) reference = datetime(int(year), int(month), 1) if period == 'month': start_time = get_start_of_period(reference, request.user) end_time = get_end_of_period(start_time, request.user) elif period == 'year': if 'start_time' in request.GET and 'end_time' in request.GET: # allow start/end time to be overwritten by URL start_time = datetime_from_string(request.GET['start_time']) end_time = datetime_from_string(request.GET['end_time']) else: start_time = get_start_of_period(datetime(int(year), 1, 1), request.user) end_time = datetime(start_time.year + 1, start_time.month, start_time.day) start_time, end_time = adjust_start_end_times( request, start_time, end_time) else: raise Exception('Invalid period') last_period_start_time = get_start_of_period( reference - timedelta(days=15), request.user) last_period_end_time = get_end_of_period(last_period_start_time, request.user) summary, transactions, total = create_summary(request, start_time, end_time, request.user) projected_transactions = [] last_month = False # calculate projections for the current unfinished month only if period == 'month' and year == datetime.now( ).year and month == datetime.now().month: last_month = True last_period_transactions = transactions_for_period( request, last_period_start_time, last_period_end_time) transaction_descriptions = set([x.description for x in transactions]) for last_period_transaction in last_period_transactions: if last_period_transaction.category and last_period_transaction.category.period == 1 and last_period_transaction.description not in transaction_descriptions: projected_transactions.append(last_period_transaction) if period == 'month': prev = first_of_previous_month(end_time) previous_year, previous_month = prev.year, prev.month next_url = first_of_next_month(end_time) next_year, next_month = next_url.year, first_of_next_month( end_time).month if not last_month else None, next_period = next_month elif period == 'year': previous_year, previous_month = year - 1, None next_year, next_month = year + 1, None next_period = year < datetime.now().year else: assert False resp = render_to_response( 'money/view_period.html', RequestContext( request, { 'lossgain': 'loss' if total < 0 else 'gain', 'summary': summary, 'total': total, 'year': year, 'month': month, 'period': period, 'monthly_average_divisor': (end_time - start_time).days / 30, 'projected_transactions': projected_transactions, 'projected_sum': sum( [x.amount for x in projected_transactions]), 'previous_year': previous_year, 'previous_month': previous_month, 'next_year': next_year, 'next_month': next_month, 'start_time': start_time, 'end_time': end_time, 'next_period': next_period, 'transactions': transactions, 'categories': Category.objects.filter(user=request.user), })) import time resp['Expires'] = http_date(time.time() + 1000) return resp
def get_modified_date(self): return http_date(mktime(self.modified.timetuple()))
def get_uploaded_date(self): return http_date(mktime(self.uploaded.timetuple()))
def process_response(self, request: HttpRequest, response: HttpResponse) -> HttpResponse: if getattr(response, "asynchronous", False): # This special Tornado "asynchronous" response is # discarded after going through this code path as Tornado # intends to block, so we stop here to avoid unnecessary work. return response try: request.get_host() except DisallowedHost: # If we get a DisallowedHost exception trying to access # the host, (1) the request is failed anyway and so the # below code will do nothing, and (2) the below will # trigger a recursive exception, breaking things, so we # just return here. return response if (not request.path.startswith("/static/") and not request.path.startswith("/api/") and not request.path.startswith("/json/")): subdomain = get_subdomain(request) if subdomain != Realm.SUBDOMAIN_FOR_ROOT_DOMAIN: try: get_realm(subdomain) except Realm.DoesNotExist: return render(request, "zerver/invalid_realm.html", status=404) """ If request.session was modified, or if the configuration is to save the session every time, save the changes and set a session cookie or delete the session cookie if the session has been emptied. """ try: accessed = request.session.accessed modified = request.session.modified empty = request.session.is_empty() except AttributeError: pass else: # First check if we need to delete this cookie. # The session should be deleted only if the session is entirely empty if settings.SESSION_COOKIE_NAME in request.COOKIES and empty: response.delete_cookie( settings.SESSION_COOKIE_NAME, path=settings.SESSION_COOKIE_PATH, domain=settings.SESSION_COOKIE_DOMAIN, ) else: if accessed: patch_vary_headers(response, ('Cookie', )) if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty: if request.session.get_expire_at_browser_close(): max_age = None expires = None else: max_age = request.session.get_expiry_age() expires_time = time.time() + max_age expires = http_date(expires_time) # Save the session data and refresh the client cookie. # Skip session save for 500 responses, refs #3881. if response.status_code != 500: try: request.session.save() except UpdateError: raise SuspiciousOperation( "The request's session was deleted before the " "request completed. The user may have logged " "out in a concurrent request, for example.") host = request.get_host().split(':')[0] # The subdomains feature overrides the # SESSION_COOKIE_DOMAIN setting, since the setting # is a fixed value and with subdomains enabled, # the session cookie domain has to vary with the # subdomain. session_cookie_domain = host response.set_cookie( settings.SESSION_COOKIE_NAME, request.session.session_key, max_age=max_age, expires=expires, domain=session_cookie_domain, path=settings.SESSION_COOKIE_PATH, secure=settings.SESSION_COOKIE_SECURE or None, httponly=settings.SESSION_COOKIE_HTTPONLY or None, samesite=settings.SESSION_COOKIE_SAMESITE, ) 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. res_last_modified, res_etag = get_last_modified_and_etag_func(last_modified_and_etag_func, request, *args, **kwargs) 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) # refresh last_modified and res_etag if needed if (request.method in ("PUT", "POST", "PATCH")) and ( (res_last_modified and not response.has_header('Last-Modified')) or (res_etag and not response.has_header('ETag'))): # refresh last_modified and res_etag! res_last_modified, res_etag = get_last_modified_and_etag_func(last_modified_and_etag_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 staticfiles_handler_serve(self, request): import time resp = serve(request, self.file_path(request.path), insecure=True) if resp.status_code == 200: resp["Expires"] = http_date(time.time() + 24 * 3600) return resp
def prop_dav_creationdate(dav, request, resource): return http_date(int(resource.created_at.strftime('%s')))
def convert_date_for_last_modified(date): return http_date(timegm(date.utctimetuple()))
def prop_dav_getlastmodified(dav, request, resource): return http_date(int(resource.updated_at.strftime('%s')))
def getFormatLastModified(lastmodified): return http_date(time.mktime(lastmodified.timetuple()))
def test_http_date(self): t = 1167616461.0 self.assertEqual(http_date(t), 'Mon, 01 Jan 2007 01:54:21 GMT')
def gzip_compressor(request): plugins = split_commas(request.GET.get("plugins", "")) languages = split_commas(request.GET.get("languages", "")) themes = split_commas(request.GET.get("themes", "")) files = split_commas(request.GET.get("files", "")) source = request.GET.get("src", "") == "true" isJS = request.GET.get("js", "") == "true" compress = request.GET.get("compress", "true") == "true" content = [] response = HttpResponse() response["Content-Type"] = "text/javascript" if not isJS: response.write( render_to_string( "tinymce/tiny_mce_gzip.js", {"base_url": tinymce.settings.JS_BASE_URL} ) ) return response patch_vary_headers(response, ["Accept-Encoding"]) now = datetime.utcnow() response["Date"] = now.strftime("%a, %d %b %Y %H:%M:%S GMT") cacheKey = "|".join(plugins + languages + themes) cacheData = cache.get(cacheKey) if cacheData is not None: if "ETag" in cacheData: if_none_match = request.META.get("HTTP_IF_NONE_MATCH") if if_none_match == cacheData["ETag"]: response.status_code = 304 response.content = "" response["Content-Length"] = "0" return response if "Last-Modified" in cacheData: if_modified_since = request.META.get("HTTP_IF_MODIFIED_SINCE") if if_modified_since == cacheData["Last-Modified"]: response.status_code = 304 response.content = "" response["Content-Length"] = "0" return response tinyMCEPreInit = { "base": tinymce.settings.JS_BASE_URL, "suffix": "", } content.append(f"var tinyMCEPreInit={json.dumps(tinyMCEPreInit)};") # Add core files = ["tinymce"] # Add core languages for lang in languages: files.append(f"langs/{lang}") # Add plugins for plugin in plugins: files.append(f"plugins/{plugin}/plugin") for lang in languages: files.append(f"plugins/{plugin}/langs/{lang}") # Add themes for theme in themes: files.append(f"themes/{theme}/theme") for lang in languages: files.append(f"themes/{theme}/langs/{lang}") for f in files: # Check for unsafe characters if not safe_filename_re.match(f): continue content.append(get_file_contents(f, source=source)) # Restore loading functions content.append( 'tinymce.each("{}".split(",")'.format(",".join(files)) + ', function(f){tinymce.ScriptLoader.markDone(tinyMCE.baseURL+"/"+f+".js");});' ) # Compress if compress: content = compress_string(b"".join([c.encode("utf-8") for c in content])) response["Content-Encoding"] = "gzip" response["Content-Length"] = str(len(content)) response.write(content) timeout = 3600 * 24 * 10 patch_response_headers(response, timeout) if not response.has_header("Last-Modified"): response["Last-Modified"] = http_date() cache.set( cacheKey, {"Last-Modified": response["Last-Modified"], "ETag": response.get("ETag", "")}, ) return response
def gzip_compressor(request): plugins = split_commas(request.GET.get('plugins', '')) languages = split_commas(request.GET.get('languages', '')) themes = split_commas(request.GET.get('themes', '')) isJS = request.GET.get('js', '') == 'true' compress = request.GET.get('compress', 'true') == 'true' suffix = request.GET.get('suffix', '') == '_src' and '_src' or '' content = [] response = HttpResponse() response['Content-Type'] = 'text/javascript' if not isJS: response.write(render_to_string('tinymce/tiny_mce_gzip.js', { 'base_url': tinymce.settings.JS_BASE_URL, })) return response patch_vary_headers(response, ['Accept-Encoding']) now = datetime.utcnow() response['Date'] = now.strftime('%a, %d %b %Y %H:%M:%S GMT') cacheKey = '|'.join(plugins + languages + themes) cacheData = cache.get(cacheKey) if cacheData is not None: if 'ETag' in cacheData: if_none_match = request.META.get('HTTP_IF_NONE_MATCH') if if_none_match == cacheData['ETag']: response.status_code = 304 response.content = '' response['Content-Length'] = '0' return response if 'Last-Modified' in cacheData: if_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE') if if_modified_since == cacheData['Last-Modified']: response.status_code = 304 response.content = '' response['Content-Length'] = '0' return response tinyMCEPreInit = { 'base': tinymce.settings.JS_BASE_URL, 'suffix': '', } content.append('var tinyMCEPreInit={!s};'.format( json.dumps(tinyMCEPreInit) )) # Add core files = ['tiny_mce'] # Add core languages for lang in languages: files.append('langs/{!s}'.format(lang)) # Add plugins for plugin in plugins: files.append('plugins/{!s}/editor_plugin{!s}'.format(plugin, suffix)) for lang in languages: files.append('plugins/{!s}/langs/{!s}'.format(plugin, lang)) # Add themes for theme in themes: files.append('themes/{!s}/editor_template{!s}'.format(theme, suffix)) for lang in languages: files.append('themes/{!s}/langs/{!s}'.format(theme, lang)) for f in files: # Check for unsafe characters if not safe_filename_re.match(f): continue content.append(get_file_contents('{!s}.js'.format(f))) # Restore loading functions content.append('tinymce.each("{!s}".split(","), function(f){{' 'tinymce.ScriptLoader.markDone(tinyMCE.baseURL+' '"/"+f+".js");}});'.format(','.join(files))) unicode_content = [] for i, c in enumerate(content): try: unicode_content.append(c.decode('latin-1')) except AttributeError: # python 3 way unicode_content.append(smart_text(c)) except UnicodeDecodeError: try: unicode_content.append(c.decode('utf-8')) except Exception: print('{!s} is nor latin-1 nor utf-8.'.format(files[i])) raise # Compress if compress: content = compress_string(b''.join([c.encode('utf-8') for c in unicode_content])) response['Content-Encoding'] = 'gzip' response['Content-Length'] = str(len(content)) response.write(content) timeout = 3600 * 24 * 10 patch_response_headers(response, timeout) if not response.has_header('Last-Modified'): # Last-Modified not set since Django 1.11 response['Last-Modified'] = http_date() cache.set(cacheKey, { 'Last-Modified': response['Last-Modified'], 'ETag': response.get('ETag', ''), }) return response
def last_modified_http(self): """ Return last modified date as a properly formatted string suitable for HTTP headers. """ return http_date(mktime(self.last_modified.timetuple()))
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 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 process_response(self, request, response): for url in self.IGNORE_URLS: if (request.path_info.startswith(url) and settings.SESSION_COOKIE_NAME not in request.COOKIES and self.cookie_name_fallback not in request.COOKIES): return response # Most of the code below is taken directly from Django's SessionMiddleware. # Some changes (marked with NOTE:) were added to support the fallback cookie. try: accessed = request.session.accessed modified = request.session.modified empty = request.session.is_empty() except AttributeError: pass else: # First check if we need to delete this cookie. # The session should be deleted only if the session is entirely empty # NOTE: This was changed to support both cookies if (settings.SESSION_COOKIE_NAME in request.COOKIES or self.cookie_name_fallback in request.COOKIES) and empty: for cookie_name in (settings.SESSION_COOKIE_NAME, self.cookie_name_fallback): if cookie_name in request.COOKIES: response.delete_cookie( cookie_name, path=settings.SESSION_COOKIE_PATH, domain=settings.SESSION_COOKIE_DOMAIN, ) else: if accessed: patch_vary_headers(response, ('Cookie', )) if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty: if request.session.get_expire_at_browser_close(): max_age = None expires = None else: max_age = request.session.get_expiry_age() expires_time = time.time() + max_age expires = http_date(expires_time) # Save the session data and refresh the client cookie. # Skip session save for 500 responses, refs #3881. if response.status_code != 500: try: request.session.save() except UpdateError: raise SuspiciousOperation( "The request's session was deleted before the " "request completed. The user may have logged " "out in a concurrent request, for example.") response.set_cookie( settings.SESSION_COOKIE_NAME, request.session.session_key, max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, path=settings.SESSION_COOKIE_PATH, secure=settings.SESSION_COOKIE_SECURE or None, httponly=settings.SESSION_COOKIE_HTTPONLY or None, samesite=settings.SESSION_COOKIE_SAMESITE, ) # NOTE: This was added to support the fallback cookie if not settings.SESSION_COOKIE_SAMESITE: # Forcibly set the session cookie to SameSite=None # This isn't supported in Django<3.1 # https://github.com/django/django/pull/11894 response.cookies[settings.SESSION_COOKIE_NAME][ "samesite"] = "None" # Set the fallback cookie in case the above cookie is rejected response.set_cookie( self.cookie_name_fallback, request.session.session_key, max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, path=settings.SESSION_COOKIE_PATH, secure=settings.SESSION_COOKIE_SECURE or None, httponly=settings.SESSION_COOKIE_HTTPONLY or None, samesite=settings.SESSION_COOKIE_SAMESITE, ) return response
def download_translation_file( request, translation: Translation, fmt: Optional[str] = None, query_string: Optional[str] = None, ): if fmt is not None: try: exporter_cls = EXPORTERS[fmt] except KeyError: raise Http404("File format not supported") if not exporter_cls.supports(translation): raise Http404("File format not supported") exporter = exporter_cls(translation=translation) units = translation.unit_set.prefetch_full().order_by("position") if query_string: units = units.search(query_string).distinct() exporter.add_units(units) response = exporter.get_response( "{{project}}-{0}-{{language}}.{{extension}}".format( translation.component.slug)) else: # Force flushing pending units try: translation.commit_pending("download", None) except WeblateLockTimeout: report_error(cause="Download commit") filenames = translation.filenames if len(filenames) == 1: extension = ( os.path.splitext(translation.filename)[1] or f".{translation.component.file_format_cls.extension()}") if not os.path.exists(filenames[0]): raise Http404("File not found") # Create response response = FileResponse( open(filenames[0], "rb"), content_type=translation.component.file_format_cls.mimetype(), ) else: extension = ".zip" response = zip_download( translation.get_filename(), filenames, translation.full_slug.replace("/", "-"), ) # Construct filename (do not use real filename as it is usually not # that useful) project_slug = translation.component.project.slug component_slug = translation.component.slug language_code = translation.language.code filename = f"{project_slug}-{component_slug}-{language_code}{extension}" # Fill in response headers response["Content-Disposition"] = f"attachment; filename={filename}" if translation.stats.last_changed: response["Last-Modified"] = http_date( mktime(translation.stats.last_changed.timetuple())) return response
def to_http_date(dt): return http_date(calendar.timegm(dt.utctimetuple()))
def FeedResponse(request, data, feed_type): feedgen = populate_feed(request, data, feed_type) response = HttpResponse(content_type=feedgen.content_type) response['Last-Modified'] = http_date(time()) feedgen.write(response, 'utf-8') return response
def get(self, request, zipped_filename, embedded_filepath): """ Handles GET requests and serves a static file from within the zip file. """ assert VALID_STORAGE_FILENAME.match( zipped_filename ), "'{}' is not a valid content storage filename".format( zipped_filename) storage = default_storage # calculate the local file path to the zip file filename, ext = os.path.splitext(zipped_filename) zipped_path = generate_object_storage_name(filename, zipped_filename) # file size file_size = 0 # if the zipfile does not exist on disk, return a 404 if not storage.exists(zipped_path): return HttpResponseNotFound( '"%(filename)s" does not exist in storage' % {'filename': zipped_path}) # if client has a cached version, use that (we can safely assume nothing has changed, due to MD5) if request.META.get('HTTP_IF_MODIFIED_SINCE'): return HttpResponseNotModified() zf_obj = storage.open(zipped_path) with zipfile.ZipFile(zf_obj) as zf: # if no path, or a directory, is being referenced, look for an index.html file if not embedded_filepath or embedded_filepath.endswith("/"): embedded_filepath += "index.html" # get the details about the embedded file, and ensure it exists try: info = zf.getinfo(embedded_filepath) except KeyError: return HttpResponseNotFound( '"{}" does not exist inside "{}"'.format( embedded_filepath, zipped_filename)) # try to guess the MIME type of the embedded file being referenced content_type = mimetypes.guess_type( embedded_filepath)[0] or 'application/octet-stream' if not os.path.splitext(embedded_filepath)[1] == '.json': # generate a streaming response object, pulling data from within the zip file response = FileResponse(zf.open(info), content_type=content_type) file_size = info.file_size else: # load the stream from json file into memory, replace the path_place_holder. content = zf.open(info).read() str_to_be_replaced = ('$' + exercises.IMG_PLACEHOLDER).encode() zipcontent = ('/' + request.resolver_match.url_name + "/" + zipped_filename).encode() content_with_path = content.replace(str_to_be_replaced, zipcontent) response = HttpResponse(content_with_path, content_type=content_type) file_size = len(content_with_path) # set the last-modified header to the date marked on the embedded file if info.date_time: response["Last-Modified"] = http_date( time.mktime(datetime.datetime(*info.date_time).timetuple())) #cache these resources forever; this is safe due to the MD5-naming used on content files response["Expires"] = "Sun, 17-Jan-2038 19:14:07 GMT" # set the content-length header to the size of the embedded file if file_size: response["Content-Length"] = file_size # ensure the browser knows not to try byte-range requests, as we don't support them here response["Accept-Ranges"] = "none" _add_access_control_headers(request, response) # restrict CSP to only allow resources to be loaded from the Studio host, to prevent info leakage # (e.g. via passing user info out as GET parameters to an attacker's server), or inadvertent data usage host = request.build_absolute_uri('/').strip("/") response[ "Content-Security-Policy"] = "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: " + host return response
def action(request, mode, ticket): mod_path, cls_name = settings.TICKET_CLASS.rsplit('.', 1) mod_path = mod_path.split('.').pop(0) tic = apps.get_model(mod_path, cls_name).objects.get(pk=ticket) if hasattr(settings, 'KEEP_IT_SIMPLE') and settings.KEEP_IT_SIMPLE: keep_it_simple = True else: keep_it_simple = False if mode == 'view': if request.method == 'POST': form = CommentForm(request.POST) if form.is_valid(): com = tickets_comments() com.comment = form.cleaned_data['comment'] com.ticket_id = ticket com.action = 6 com.save(user=request.user) check_references(request, com) touch_ticket(request.user, ticket) add_history(request, tic, 6, com.comment) mail_comment(request, com.pk) jabber_comment(request, com.pk) else: if 'resolution' in request.POST: if request.POST['resolution'] and int( request.POST['resolution']) > 0: tic.resolution_id = request.POST['resolution'] tic.closed = True tic.close_date = timezone.now() tic.state = get_flow_end() tic.save(user=request.user) com = tickets_comments() com.comment = _( 'ticket closed - resolution: %(resolution)s\n\n%(comment)s' ) % { 'resolution': ticket_resolution.objects.get( pk=request.POST['resolution']).name, 'comment': request.POST.get('close_comment', '') } com.ticket_id = ticket com.action = 1 com.save(user=request.user) check_references(request, com) touch_ticket(request.user, ticket) add_history(request, tic, 1, request.POST.get('close_comment', '')) mail_comment(request, com.pk) jabber_comment(request, com.pk) else: messages.add_message(request, messages.ERROR, _('no resolution selected')) else: messages.add_message(request, messages.ERROR, _('comment invalid')) # reload ticket => last_action date has changed tic = apps.get_model(mod_path, cls_name).objects.get(pk=ticket) excludes = [] form = TicketsForm(exclude_list=excludes, is_stuff=request.user.is_staff, user=request.user, instance=tic, customer=request.organisation.id, view_only=True) close = TicketCloseForm() reassign = TicketReassignForm(initial={ 'assigned': tic.assigned_id, 'state': tic.state }) flows = list( ticket_flow_edges.objects.select_related('next').filter( now=tic.state).exclude(next__type=2).values_list('next', flat=True)) flows.append(tic.state_id) reassign.fields['state'].queryset = reassign.fields[ 'state'].queryset.filter(id__in=flows) participants = tickets_participants.objects.select_related( 'user').filter(ticket=ticket) comments = tickets_comments.objects.select_related('c_user').filter( ticket=ticket).order_by('c_date') close_allowed = ticket_flow_edges.objects.select_related( 'next').filter(now=tic.state, next__type=2).count() > 0 files = tickets_files.objects.filter(ticket=ticket, active_record=True) paginator = Paginator(files, 10) page = request.GET.get('page') try: files_lines = paginator.page(page) except PageNotAnInteger: # If page is not an integer, deliver first page. files_lines = paginator.page(1) except EmptyPage: # If page is out of range (e.g. 9999), deliver last page of results. files_lines = paginator.page(paginator.num_pages) add_breadcrumbs(request, ticket, '#', caption=tic.caption[:20]) if 'YATSE' in request.GET and 'isUsingYATSE' not in request.session: request.session['isUsingYATSE'] = True return render( request, 'tickets/view.html', { 'layout': 'horizontal', 'ticket': tic, 'form': form, 'close': close, 'reassign': reassign, 'files': files_lines, 'comments': comments, 'participants': participants, 'close_allowed': close_allowed, 'keep_it_simple': keep_it_simple, 'last_action_date': http_date(time.mktime(tic.last_action_date.timetuple())) }) elif mode == 'gallery': images = tickets_files.objects.filter(ticket=ticket, active_record=True) return render(request, 'tickets/gallery.html', { 'layout': 'horizontal', 'ticket': tic, 'images': images }) elif mode == 'history': history = tickets_history.objects.filter(ticket=ticket) return render( request, 'tickets/history.html', { 'layout': 'horizontal', 'ticket': tic, 'history': history, 'keep_it_simple': keep_it_simple }) elif mode == 'reopen': if tic.closed: tic.closed = False tic.state = get_flow_start() tic.resolution = None tic.close_date = None tic.save(user=request.user) com = tickets_comments() com.comment = _('ticket reopend - resolution deleted') com.ticket_id = ticket com.action = 2 com.save(user=request.user) check_references(request, com) touch_ticket(request.user, ticket) add_history(request, tic, 2, None) mail_comment(request, com.pk) jabber_comment(request, com.pk) return HttpResponseRedirect('/tickets/view/%s/' % ticket) elif mode == 'move': if not tic.closed: old_state = tic.state tic.state = ticket_flow.objects.get(pk=request.POST['state']) tic.save(user=request.user) touch_ticket(request.user, ticket) oldUser = str(User.objects.get( pk=tic.assigned_id)) if tic.assigned_id else None history_data = { 'old': { 'comment': '', 'assigned': oldUser, 'state': str(old_state) }, 'new': { 'comment': _('ticket moved'), 'assigned': oldUser, 'state': str(tic.state) } } add_history(request, tic, 7, history_data) return HttpResponse('OK') elif mode == 'reassign': if not tic.closed: if 'assigned' in request.POST: if request.POST['assigned'] and int( request.POST['assigned']) > 0: old_assigned_user = tic.assigned old_state = tic.state tic.assigned_id = request.POST['assigned'] tic.state = ticket_flow.objects.get( pk=request.POST['state']) tic.save(user=request.user) newUser = User.objects.get(pk=request.POST['assigned']) com = tickets_comments() com.comment = _( 'ticket reassigned to %(user)s\nstate now: %(state)s\n\n%(comment)s' ) % { 'user': newUser, 'comment': request.POST.get('reassign_comment', ''), 'state': tic.state } com.ticket_id = ticket com.action = 7 com.save(user=request.user) check_references(request, com) touch_ticket(request.user, ticket) if request.POST['assigned']: touch_ticket(newUser, ticket) mail_comment(request, com.pk) jabber_comment(request, com.pk) history_data = { 'old': { 'comment': '', 'assigned': str(old_assigned_user), 'state': str(old_state) }, 'new': { 'comment': request.POST.get('reassign_comment', ''), 'assigned': str(User.objects.get(pk=request.POST['assigned'])), 'state': str(tic.state) } } add_history(request, tic, 7, history_data) else: messages.add_message(request, messages.ERROR, _('missing assigned user')) return HttpResponseRedirect('/tickets/view/%s/' % ticket) elif mode == 'edit' or (mode == 'simple' and (not tic.keep_it_simple or tic.closed) and keep_it_simple): excludes = ['resolution'] if request.method == 'POST': form = TicketsForm(request.POST, exclude_list=excludes, is_stuff=request.user.is_staff, user=request.user, instance=tic, customer=request.organisation.id) if form.is_valid(): tic = form.save() if tic.keep_it_simple: tic.keep_it_simple = False tic.save(user=request.user) assigned = form.cleaned_data.get('assigned') if assigned: touch_ticket(assigned, tic.pk) mail_ticket(request, tic.pk, form) jabber_ticket(request, tic.pk, form) remember_changes(request, form, tic) touch_ticket(request.user, tic.pk) return HttpResponseRedirect('/tickets/view/%s/' % ticket) else: form = TicketsForm(exclude_list=excludes, is_stuff=request.user.is_staff, user=request.user, instance=tic, customer=request.organisation.id) if 'state' in form.fields: form.fields['state'].queryset = form.fields[ 'state'].queryset.exclude(type=2) return render(request, 'tickets/edit.html', { 'ticket': tic, 'layout': 'horizontal', 'form': form }) elif mode == 'simple': if request.method == 'POST': form = SimpleTickets(request.POST, initial={ 'caption': tic.caption, 'description': tic.description, 'priority': tic.priority, 'assigned': tic.assigned }) if form.is_valid(): cd = form.cleaned_data tic.caption = cd['caption'] tic.description = cd['description'].replace(u"\u00A0", " ") tic.priority = cd['priority'] tic.assigned = cd['assigned'] tic.deadline = cd['deadline'] tic.show_start = cd['show_start'] tic.component = cd['component'] tic.save(user=request.user) if cd['assigned']: touch_ticket(cd['assigned'], tic.pk) remember_changes(request, form, tic) touch_ticket(request.user, tic.pk) mail_ticket(request, tic.pk, form) jabber_ticket(request, tic.pk, form) return HttpResponseRedirect('/tickets/view/%s/' % ticket) else: form = SimpleTickets( initial={ 'caption': tic.caption, 'description': tic.description, 'priority': tic.priority, 'assigned': tic.assigned, 'deadline': tic.deadline, 'show_start': tic.show_start, 'component': tic.component, }) return render(request, 'tickets/edit.html', { 'ticket': tic, 'layout': 'horizontal', 'form': form, 'mode': mode }) elif mode == 'download': fileid = request.GET.get('file', -1) file_data = tickets_files.objects.get(id=fileid, ticket=ticket) src = '%s%s.dat' % (settings.FILE_UPLOAD_PATH, fileid) content_type = file_data.content_type if request.GET.get('preview') == 'yes' and os.path.isfile( '%s%s.preview' % (settings.FILE_UPLOAD_PATH, fileid)): src = '%s%s.preview' % (settings.FILE_UPLOAD_PATH, fileid) content_type = 'imgae/png' if request.GET.get( 'resize', 'no') == 'yes' and ('image' in file_data.content_type or 'pdf' in file_data.content_type): img = resize_image('%s' % (src), (200, 150), 75) output = io.BytesIO() img.save(output, 'PNG') output.seek(0) response = StreamingHttpResponse(output, content_type='image/png') else: response = StreamingHttpResponse(open('%s' % (src), "rb"), content_type=content_type) if 'noDisposition' not in request.GET: if request.GET.get('preview') == 'yes' and os.path.isfile( '%s%s.preview' % (settings.FILE_UPLOAD_PATH, fileid)): response[ 'Content-Disposition'] = 'attachment;filename="%s"' % content_type else: response[ 'Content-Disposition'] = 'attachment;filename="%s"' % smart_str( file_data.name) return response elif mode == 'upload': if request.method == 'POST': form = UploadFileForm(request.POST, request.FILES) if form.is_valid(): if tickets_files.objects.filter( active_record=True, ticket=ticket, checksum=request.FILES['file'].hash).count() > 0: messages.add_message( request, messages.ERROR, _('File already exists: %s') % request.FILES['file'].name) if request.GET.get('Ajax') == '1': return HttpResponse('OK') return HttpResponseRedirect('/tickets/view/%s/' % ticket) f = tickets_files() f.name = request.FILES['file'].name f.size = request.FILES['file'].size f.checksum = request.FILES['file'].hash f.content_type = request.FILES['file'].content_type f.ticket_id = ticket f.public = True f.save(user=request.user) touch_ticket(request.user, ticket) add_history(request, tic, 5, request.FILES['file'].name) mail_file(request, f.pk) jabber_file(request, f.pk) dest = settings.FILE_UPLOAD_PATH if not os.path.exists(dest): os.makedirs(dest) with open('%s%s.dat' % (dest, f.id), 'wb+') as destination: for chunk in request.FILES['file'].chunks(): destination.write(chunk) if 'pdf' in f.content_type: convertPDFtoImg('%s/%s.dat' % (dest, f.id), '%s/%s.preview' % (dest, f.id)) else: if 'image' not in f.content_type and isPreviewable( f.content_type): tmp = convertOfficeTpPDF('%s/%s.dat' % (dest, f.id)) convertPDFtoImg(tmp, '%s/%s.preview' % (dest, f.id)) if os.path.isfile(tmp): os.unlink(tmp) return HttpResponseRedirect('/tickets/view/%s/' % tic.pk) else: msg = unicode(form.errors['file']) msg = re.sub('<[^<]+?>', '', msg) messages.add_message(request, messages.ERROR, msg) if request.GET.get('Ajax') == '1': return HttpResponse('OK') return HttpResponseRedirect('/tickets/view/%s/' % ticket) elif request.method == 'PUT': # /tickets/upload/XXX/?filename=test1.txt upload_handlers = request.upload_handlers content_type = str(request.META.get('CONTENT_TYPE', "")) content_length = int(request.META.get('CONTENT_LENGTH', 0)) if content_type == "": return HttpResponse('missing ContentType', status=400) if content_length == 0: # both returned 0 return HttpResponse('missing ContentLength', status=400) content_type = content_type.split(";")[0].strip() try: charset = content_type.split(";")[1].strip() except IndexError: charset = "" # we can get the file name via the path, we don't actually file_name = request.GET['filename'] field_name = file_name counters = [0] * len(upload_handlers) for handler in upload_handlers: result = handler.handle_raw_input("", request.META, content_length, "", "") from django.core.files.uploadhandler import StopFutureHandlers for handler in upload_handlers: try: handler.new_file(field_name, file_name, content_type, content_length, charset) except StopFutureHandlers: break for i, handler in enumerate(upload_handlers): while True: chunk = request.read(handler.chunk_size) if chunk: handler.receive_data_chunk(chunk, counters[i]) counters[i] += len(chunk) else: # no chunk break for i, handler in enumerate(upload_handlers): file_obj = handler.file_complete(counters[i]) if file_obj: if settings.FILE_UPLOAD_VIRUS_SCAN and pyclamd: # virus scan try: if not hasattr(pyclamd, 'scan_stream'): cd = pyclamd.ClamdUnixSocket() else: pyclamd.init_network_socket('localhost', 3310) cd = pyclamd # We need to get a file object for clamav. We might have a path or we might # have to read the data into memory. if hasattr(file_obj, 'temporary_file_path'): os.chmod(file_obj.temporary_file_path(), 0664) result = cd.scan_file( file_obj.temporary_file_path()) else: if hasattr(file_obj, 'read'): result = cd.scan_stream(file_obj.read()) else: result = cd.scan_stream( file_obj['content']) except: from socket import gethostname raise Exception( _(u'unable to initialize scan engine on host %s' ) % gethostname()) if result: msg = ' '.join(result[result.keys()[0]]).replace( 'FOUND ', '') raise Exception( _(u"file is infected by virus: %s") % msg) hasher = hashlib.md5() # We need to get a file object for clamav. We might have a path or we might # have to read the data into memory. if hasattr(file_obj, 'temporary_file_path'): with open(file_obj.temporary_file_path(), 'rb') as afile: buf = afile.read() hasher.update(buf) hash = hasher.hexdigest() else: if hasattr(file_obj, 'read'): file_obj.seek(0) buf = file_obj.read() hasher.update(buf) else: hasher.update(file_obj['content'].read()) hash = hasher.hexdigest() if tickets_files.objects.filter(active_record=True, ticket=ticket, checksum=hash).count() > 0: raise Exception( 'duplicate hash value - file already exists in this ticket %s' % ticket) # todo: virusscan f = tickets_files() f.name = file_obj.name f.size = file_obj.size f.checksum = hash f.content_type = content_type f.ticket_id = ticket f.public = True f.save(user=request.user) touch_ticket(request.user, ticket) add_history(request, tic, 5, file_obj.name) mail_file(request, f.pk) jabber_file(request, f.pk) dest = settings.FILE_UPLOAD_PATH if not os.path.exists(dest): os.makedirs(dest) with open('%s%s.dat' % (dest, f.id), 'wb+') as destination: for chunk in file_obj.chunks(): destination.write(chunk) if 'pdf' in f.content_type: convertPDFtoImg('%s/%s.dat' % (dest, f.id), '%s/%s.preview' % (dest, f.id)) else: if 'image' not in f.content_type and isPreviewable( f.content_type): try: tmp = convertOfficeTpPDF('%s/%s.dat' % (dest, f.id)) convertPDFtoImg(tmp, '%s/%s.preview' % (dest, f.id)) if os.path.isfile(tmp): os.unlink(tmp) except: pass if 'audio' in f.content_type: try: # https://realpython.com/python-speech-recognition/ import speech_recognition as sr AUDIO_FILE = '%s%s.dat' % (dest, f.id) r = sr.Recognizer() with sr.AudioFile(AUDIO_FILE) as source: audio = r.record( source) # read the entire audio file text = r.recognize_google(audio, language='de-DE') if text: com = tickets_comments() com.comment = text com.ticket_id = ticket com.action = 6 com.save(user=request.user) except: pass return HttpResponse(status=201) else: # some indication this didn't work? return HttpResponse(status=500) else: form = UploadFileForm() return render(request, 'tickets/file.html', { 'ticketid': ticket, 'layout': 'horizontal', 'form': form }) elif mode == 'delfile': file = tickets_files.objects.get(pk=request.GET['fileid'], ticket=ticket) file.delete(user=request.user) touch_ticket(request.user, ticket) add_history(request, tic, 8, file.name) return HttpResponseRedirect('/tickets/view/%s/#files' % tic.pk) elif mode == 'notify': tickets_participants.objects.filter( ticket=tic, user=request.user).update(seen=True) return HttpResponse('OK') elif mode == 'sleep': interval = request.GET.get('interval') if interval in ['1', '2', '3', '4', '5', '6', '7', '14', '21', '30']: old = tic.show_start tic.show_start = timezone.now() + datetime.timedelta( days=int(interval)) tic.save(user=request.user) touch_ticket(request.user, ticket) add_history(request, tic, 10, (tic.show_start, old)) return HttpResponse('OK') else: raise Exception('no interval given') elif mode == 'ignore': ig = tickets_ignorants() ig.ticket = tic ig.user = request.user ig.save() return HttpResponse('OK') elif mode == 'todo': class local: counter = 0 def ToDoDone(match): local.counter += 1 group = match.groups() if local.counter == pos: return u'[X]' else: return u'[%s]' % group[0] def ToDoUnDone(match): local.counter += 1 group = match.groups() if local.counter == pos: return u'[ ]' else: return u'[%s]' % group[0] form = ToDo(request.POST) if form.is_valid(): desc = tic.description cd = form.cleaned_data text = cd['text'] pos = cd['item'] set = cd['set'] if set: tic.description = re.sub(r'\[([ Xx])\]', ToDoDone, desc) old = _('undone: %s') % text new = _('done: %s') % text else: tic.description = re.sub(r'\[([ Xx])\]', ToDoUnDone, desc) new = _('undone: %s') % text old = _('done: %s') % text tic.save(user=request.user) touch_ticket(request.user, ticket) add_history(request, tic, 9, (new, old)) data = { 'set': set, 'item': pos, 'text': text, } return JsonResponse(data, safe=False) elif mode == 'update_comment': if request.method == 'POST': comment_id = request.GET.get("comment_id") comment = tickets_comments.objects.get(pk=comment_id) if comment.c_user == request.user: comment.comment = request.POST.get("comment_body", "") comment.edited = True comment.save(user=request.user) return HttpResponseRedirect("/tickets/view/%s/#comment_id-%s" % (ticket, comment_id)) elif mode == 'last_modified': 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 time.mktime( tic.last_action_date.timetuple()) > if_modified_since: return HttpResponse('outdated', status=200) else: return HttpResponse('not modified', status=304) else: return HttpResponse('unknown', status=412)