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

Side by Side Diff: appengine/isolate/handlers_frontend.py

Issue 2441003002: Add helpful error message to isolate UI when downloading big file (Closed)
Patch Set: Created 4 years, 2 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 unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2012 The LUCI Authors. All rights reserved. 1 # Copyright 2012 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 3 # that can be found in the LICENSE file.
4 4
5 """This module defines Isolate Server frontend url handlers.""" 5 """This module defines Isolate Server frontend url handlers."""
6 6
7 import datetime 7 import datetime
8 import json 8 import json
9 import logging
9 import re 10 import re
10 11
11 import webapp2 12 import webapp2
12 13
13 from google.appengine.api import memcache 14 from google.appengine.api import memcache
15 from google.appengine.api import modules
14 from google.appengine.api import users 16 from google.appengine.api import users
15 17
16 import acl 18 import acl
17 import config 19 import config
18 import gcs 20 import gcs
19 import handlers_endpoints_v1 21 import handlers_endpoints_v1
20 import mapreduce_jobs 22 import mapreduce_jobs
21 import model 23 import model
22 import stats 24 import stats
23 import template 25 import template
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 if not raw_data: 224 if not raw_data:
223 stream = gcs.read_file(config.settings().gs_bucket, entity.key.id()) 225 stream = gcs.read_file(config.settings().gs_bucket, entity.key.id())
224 else: 226 else:
225 stream = [raw_data] 227 stream = [raw_data]
226 content = ''.join(model.expand_content(namespace, stream)) 228 content = ''.join(model.expand_content(namespace, stream))
227 229
228 self.response.headers['X-Frame-Options'] = 'SAMEORIGIN' 230 self.response.headers['X-Frame-Options'] = 'SAMEORIGIN'
229 # We delete Content-Type before storing to it to avoid having two (yes, 231 # We delete Content-Type before storing to it to avoid having two (yes,
230 # two) Content-Type headers. 232 # two) Content-Type headers.
231 del self.response.headers['Content-Type'] 233 del self.response.headers['Content-Type']
234
232 # Apparently, setting the content type to text/plain encourages the 235 # Apparently, setting the content type to text/plain encourages the
233 # browser (Chrome, at least) to sniff the mime type and display 236 # browser (Chrome, at least) to sniff the mime type and display
234 # things like images. Images are autowrapped in <img> and text is 237 # things like images. Images are autowrapped in <img> and text is
235 # wrapped in <pre>. 238 # wrapped in <pre>.
236 self.response.headers['Content-Type'] = 'text/plain; charset=utf-8' 239 self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
237 self.response.headers['Content-Disposition'] = str('filename=%s' % digest) 240
238 if content.startswith('{'): 241 # App Engine puts a limit of 33554432 bytes on a request, which includes
239 # Try to format as JSON. 242 # headers. Headers are ~150 bytes. If the content + headers might
240 try: 243 # exceed that limit, we give the user an option to workround getting
241 content = json.dumps( 244 # their file.
242 json.loads(content), sort_keys=True, indent=2, 245 if len(content) > 33554000:
243 separators=(',', ': ')) 246 host = modules.get_hostname(module='default', version='default')
244 # If we don't wrap this in html, browsers will put content in a pre 247 # host is something like default.default.myisolateserver.appspot.com
245 # tag which is also styled with monospace/pre-wrap. We can't use 248 host = host.replace('default.default.','')
246 # anchor tags in <pre>, so we force it to be a <div>, which happily 249 sizeInMib = len(content) / (1024.0 * 1024.0)
247 # accepts links. 250 content = ('Sorry, your file is %1.1f MiB big, which exceeds the 32 MiB'
248 content = ( 251 ' App Engine limit.\nTo work around this, run the following command:\n'
249 '<div style="font-family:monospace;white-space:pre-wrap;">%s</div>' 252 ' python isolateserver.py download -I %s --namespace %s -f %s %s'
250 % content) 253 % (sizeInMib, host, namespace, digest, digest))
251 # Linkify things that look like hashes 254 else:
252 content = re.sub(r'([0-9a-f]{40})', 255 self.response.headers['Content-Disposition'] = str('filename=%s'
253 r'<a target="_blank" href="/browse?namespace=%s' % namespace + 256 % digest)
254 r'&digest=\1">\1</a>', 257 if content.startswith('{'):
255 content) 258 # Try to format as JSON.
256 self.response.headers['Content-Type'] = 'text/html; charset=utf-8' 259 try:
257 except ValueError: 260 content = json.dumps(
258 pass 261 json.loads(content), sort_keys=True, indent=2,
262 separators=(',', ': '))
263 # If we don't wrap this in html, browsers will put content in a pre
264 # tag which is also styled with monospace/pre-wrap. We can't use
265 # anchor tags in <pre>, so we force it to be a <div>, which happily
266 # accepts links.
267 content = (
268 '<div style="font-family:monospace;white-space:pre-wrap;">%s'
269 '</div>' % content)
270 # Linkify things that look like hashes
271 content = re.sub(r'([0-9a-f]{40})',
272 r'<a target="_blank" href="/browse?namespace=%s' % namespace +
273 r'&digest=\1">\1</a>',
274 content)
275 self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
276 except ValueError:
277 pass
259 278
260 self.response.write(content) 279 self.response.write(content)
261 280
262 281
263 class StatsHandler(webapp2.RequestHandler): 282 class StatsHandler(webapp2.RequestHandler):
264 """Returns the statistics web page.""" 283 """Returns the statistics web page."""
265 def get(self): 284 def get(self):
266 """Presents nice recent statistics. 285 """Presents nice recent statistics.
267 286
268 It fetches data from the 'JSON' API. 287 It fetches data from the 'JSON' API.
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 def create_application(debug): 405 def create_application(debug):
387 """Creates the url router. 406 """Creates the url router.
388 407
389 The basic layouts is as follow: 408 The basic layouts is as follow:
390 - /restricted/.* requires being an instance administrator. 409 - /restricted/.* requires being an instance administrator.
391 - /stats/.* has statistics. 410 - /stats/.* has statistics.
392 """ 411 """
393 acl.bootstrap() 412 acl.bootstrap()
394 template.bootstrap() 413 template.bootstrap()
395 return webapp2.WSGIApplication(get_routes(), debug=debug) 414 return webapp2.WSGIApplication(get_routes(), debug=debug)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698