Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2321)

Unified Diff: appengine/isolate/handlers_frontend.py

Issue 1866753008: Add ability to linkify hashes on isolate server (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@master
Patch Set: Also add content sniffing Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | appengine/isolate/templates/browse.html » ('j') | appengine/isolate/templates/browse.html » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: appengine/isolate/handlers_frontend.py
diff --git a/appengine/isolate/handlers_frontend.py b/appengine/isolate/handlers_frontend.py
index 63c8853c14d2e7866c0b1c84a7b0d98cf2fd2128..ac2a5d1e98eff4f9bd4c4d9bff6a6cd024039a7d 100644
--- a/appengine/isolate/handlers_frontend.py
+++ b/appengine/isolate/handlers_frontend.py
@@ -6,6 +6,7 @@
import datetime
import json
+import re
import webapp2
@@ -151,6 +152,34 @@ class BrowseHandler(auth.AuthenticatingHandler):
namespace = self.request.get('namespace', 'default-gzip')
# Support 'hash' for compatibility with old links. To remove eventually.
digest = self.request.get('digest', '') or self.request.get('hash', '')
+ params = {
+ u'digest': unicode(digest),
+ u'namespace': unicode(namespace),
+ # TODO(maruel): Add back once Web UI authentication is switched to OAuth2.
M-A Ruel 2016/04/13 20:32:09 Remove this while at it, not needed.
kjlubick 2016/04/14 13:18:43 Done.
kjlubick 2016/04/14 13:18:43 Done.
+ #'onload': 'update()' if digest else '',
+ u'onload': '',
+ }
+ # Check for existence of element, so we can 400/404
+ if digest and namespace:
+ # TODO(maruel): Refactor into a function.
M-A Ruel 2016/04/13 20:32:09 Can you make it a function now that it is used at
kjlubick 2016/04/14 13:18:43 I put it in model.py and used it twice here. I co
+ memcache_entry = memcache.get(digest, namespace='table_%s' % namespace)
+ if memcache_entry is None:
+ try:
+ key = model.get_entry_key(namespace, digest)
+ except ValueError:
+ self.abort(400, 'Invalid key')
+ entity = key.get()
+ if entity is None:
+ self.abort(404, 'Unable to retrieve the entry')
+ self.response.write(template.render('isolate/browse.html', params))
+
M-A Ruel 2016/04/13 20:32:09 2 empty lines between file level symbols
kjlubick 2016/04/14 13:18:43 Done.
+class ContentHandler(auth.AuthenticatingHandler):
+ @auth.autologin
+ @auth.require(acl.isolate_readable)
+ def get(self):
+ namespace = self.request.get('namespace', 'default-gzip')
+ digest = self.request.get('digest', '')
+
content = None
if digest and namespace:
# TODO(maruel): Refactor into a function.
@@ -171,24 +200,34 @@ class BrowseHandler(auth.AuthenticatingHandler):
else:
stream = [raw_data]
content = ''.join(model.expand_content(namespace, stream))
+
+ self.response.headers['X-Frame-Options'] = 'SAMEORIGIN'
+ del self.response.headers['Content-Type']
+ # Apparently, setting the content type to text/plain encourages the
+ # browser (Chrome, at least) to sniff the mime type and display
+ # things like images. Images are autowrapped in <img> and text is
+ # wrapped in <pre>.
+ self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
+ self.response.headers['Content-Disposition'] = str('filename=%s' % digest)
if content.startswith('{'):
# Try to format as JSON.
try:
content = json.dumps(
json.loads(content), sort_keys=True, indent=2,
separators=(',', ': '))
+ content = (
+ '<div style="font-family:monospace;white-space:pre-wrap;">%s</div>'
M-A Ruel 2016/04/13 20:32:09 Looks like this is not strictly necessary from wha
kjlubick 2016/04/14 13:18:43 I'll add a comment that mirrors this, but I don't
+ % content)
+ # Linkify things that look like hashes
+ content = re.sub(r'([0-9a-f]{40})',
+ r"""<a target="_blank" href="browse?namespace=default-gzip
+ &digest=\1">\1</a>""",
+ content)
+ self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
except ValueError:
pass
- content = content.decode('utf8', 'replace')
- params = {
- u'content': content,
- u'digest': unicode(digest),
- u'namespace': unicode(namespace),
- # TODO(maruel): Add back once Web UI authentication is switched to OAuth2.
- #'onload': 'update()' if digest else '',
- u'onload': '',
- }
- self.response.write(template.render('isolate/browse.html', params))
+
+ self.response.write(content)
class StatsHandler(webapp2.RequestHandler):
@@ -298,6 +337,7 @@ def get_routes():
# User web pages.
webapp2.Route(r'/browse', BrowseHandler),
+ webapp2.Route(r'/content', ContentHandler),
webapp2.Route(r'/stats', StatsHandler),
webapp2.Route(r'/isolate/api/v1/stats/days', StatsGvizDaysHandler),
webapp2.Route(r'/isolate/api/v1/stats/hours', StatsGvizHoursHandler),
« no previous file with comments | « no previous file | appengine/isolate/templates/browse.html » ('j') | appengine/isolate/templates/browse.html » ('J')

Powered by Google App Engine
This is Rietveld 408576698