Răsfoiți Sursa

HUE-51. Hue needs a 500 template

bc Wong 15 ani în urmă
părinte
comite
59dd976926

+ 3 - 0
desktop/conf.dist/hue.ini

@@ -30,6 +30,9 @@ time_zone=America/Los_Angeles
 # Turn off debug
 # Turn off debug
 django_debug_mode=0
 django_debug_mode=0
 
 
+# Turn off backtrace for server error
+http_500_debug_mode=0
+
 # Webserver runs as this user
 # Webserver runs as this user
 ## server_user=hue
 ## server_user=hue
 ## server_group=hue
 ## server_group=hue

+ 9 - 0
desktop/core/src/desktop/conf.py

@@ -238,3 +238,12 @@ DJANGO_DEBUG_MODE = Config(
   type=coerce_bool,
   type=coerce_bool,
   default=True
   default=True
 )
 )
+
+HTTP_500_DEBUG_MODE = Config(
+  key='http_500_debug_mode',
+  help='Enable or disable debugging information in the 500 internal server error response. '
+       'Note that the debugging information may contain sensitive data. '
+       'If django_debug_mode is True, this is automatically enabled.',
+  type=coerce_bool,
+  default=True
+)

+ 32 - 0
desktop/core/src/desktop/templates/404.html

@@ -0,0 +1,32 @@
+{% comment %}
+Licensed to Cloudera, Inc. under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  Cloudera, Inc. licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+{% endcomment %}
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html> <head>
+<title>Page Not Found</title>
+</head>
+<body>
+
+<h2>Page Not Found</h2>
+
+<p>We're sorry, but the requested page could not be found:
+<br/>
+{{uri}}
+</p>
+
+</body>
+</html>

+ 28 - 0
desktop/core/src/desktop/templates/500.html

@@ -0,0 +1,28 @@
+{% comment %}
+Licensed to Cloudera, Inc. under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  Cloudera, Inc. licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+{% endcomment %}
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html> <head>
+<title>Internal Server Error</title>
+</head>
+<body>
+  <h2>Server Error (500)</h2>
+  <p>There's been an error. It's been reported to the site administrators
+  via e-mail and should be fixed shortly. Thanks for your patience.</p>
+  <a href="/">Home</a>
+</body>
+</html>

+ 45 - 0
desktop/core/src/desktop/tests.py

@@ -18,6 +18,7 @@ from desktop.lib import django_mako
 
 
 from nose.tools import assert_true, assert_equal
 from nose.tools import assert_true, assert_equal
 from desktop.lib.django_test_util import make_logged_in_client
 from desktop.lib.django_test_util import make_logged_in_client
+from django.conf.urls.defaults import patterns, url
 from django.http import HttpResponse
 from django.http import HttpResponse
 from django.db.models import query, CharField, SmallIntegerField
 from django.db.models import query, CharField, SmallIntegerField
 from desktop.lib.paginator import Paginator
 from desktop.lib.paginator import Paginator
@@ -194,3 +195,47 @@ def test_truncating_model():
 
 
   a.non_string_field = 10**10
   a.non_string_field = 10**10
   assert_true(a.non_string_field == 10**10, 'non-string fields are not truncated')
   assert_true(a.non_string_field == 10**10, 'non-string fields are not truncated')
+
+
+def test_500_handling():
+  restore_django_debug = desktop.conf.DJANGO_DEBUG_MODE.set_for_testing(False)
+  restore_500_debug = desktop.conf.HTTP_500_DEBUG_MODE.set_for_testing(False)
+
+  exc_msg = "error_raising_view: Test 500 handling"
+  def error_raising_view(request, *args, **kwargs):
+    raise Exception(exc_msg)
+
+  # Add an error view
+  error_url_pat = patterns('', url('^500_internal_error$', error_raising_view))[0]
+  desktop.urls.urlpatterns.append(error_url_pat)
+  try:
+    def store_exc_info(*args, **kwargs):
+      pass
+    # Disable the test client's exception forwarding
+    c = make_logged_in_client()
+    c.store_exc_info = store_exc_info
+
+    response = c.get('/500_internal_error')
+    assert_equal(response.template.name, '500.html')
+    assert_true('should be fixed shortly. Thanks for your patience' in response.content)
+    assert_true(exc_msg not in response.content)
+
+    # Now test the 500 handler with backtrace
+    desktop.conf.HTTP_500_DEBUG_MODE.set_for_testing(True)
+    response = c.get('/500_internal_error')
+    assert_equal(response.template.name, 'Technical 500 template')
+    assert_true(exc_msg in response.content)
+  finally:
+    # Restore the world
+    desktop.urls.urlpatterns.remove(error_url_pat)
+    restore_django_debug()
+    restore_500_debug()
+
+
+def test_404_handling():
+  view_name = '/the-view-that-is-not-there'
+  c = make_logged_in_client()
+  response = c.get(view_name)
+  assert_equal(response.template.name, '404.html')
+  assert_true('Page Not Found' in response.content)
+  assert_true(view_name in response.content)

+ 9 - 4
desktop/core/src/desktop/urls.py

@@ -19,14 +19,19 @@ import logging
 import os
 import os
 import re
 import re
 
 
-# The "*" import below is important.  
-# Django expects, for example, handler500 and handler404
-# to be defined.  See http://code.djangoproject.com/ticket/5350
-from django.conf.urls.defaults import *
+from django.conf.urls.defaults import include, patterns, url
 from django.contrib import admin
 from django.contrib import admin
+
 from desktop import appmanager
 from desktop import appmanager
 import depender.urls
 import depender.urls
 
 
+# Django expects handler404 and handler500 to be defined.
+# django.conf.urls.defaults provides them. But we want to override them.
+# Also see http://code.djangoproject.com/ticket/5350
+handler404 = 'desktop.views.serve_404_error'
+handler500 = 'desktop.views.serve_500_error'
+
+
 # Set up /appname/static mappings for any apps that have static directories
 # Set up /appname/static mappings for any apps that have static directories
 def static_pattern(urlprefix, root):
 def static_pattern(urlprefix, root):
   """
   """

+ 18 - 3
desktop/core/src/desktop/views.py

@@ -16,20 +16,22 @@
 # limitations under the License.
 # limitations under the License.
 
 
 import logging
 import logging
-import zipfile
+import sys
 import tempfile
 import tempfile
 import time
 import time
-import sys
 import traceback
 import traceback
+import zipfile
 
 
 from django.shortcuts import render_to_response
 from django.shortcuts import render_to_response
 from django.http import HttpResponse
 from django.http import HttpResponse
 from django.core.servers.basehttp import FileWrapper
 from django.core.servers.basehttp import FileWrapper
+import django.views.debug
 
 
 from desktop.lib.django_util import login_notrequired, render_json, render
 from desktop.lib.django_util import login_notrequired, render_json, render
-from desktop.log.access import access_log_level
+from desktop.log.access import access_log_level, access_warn
 from desktop.models import UserPreferences
 from desktop.models import UserPreferences
 from desktop import appmanager
 from desktop import appmanager
+import desktop.conf
 import desktop.log.log_buffer
 import desktop.log.log_buffer
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
@@ -196,3 +198,16 @@ def index(request):
   return render("index.mako", request, dict(
   return render("index.mako", request, dict(
     feedback_url=desktop.conf.FEEDBACK_URL.get()
     feedback_url=desktop.conf.FEEDBACK_URL.get()
   ))
   ))
+
+def serve_404_error(request, *args, **kwargs):
+  """Registered handler for 404. We just return a simple error"""
+  access_warn(request, "404 not found")
+  return render_to_response("404.html", dict(uri=request.build_absolute_uri()))
+  return HttpResponse('Page not found. You are trying to access %s' % (request.build_absolute_uri(),),
+                      content_type="text/plain")
+
+def serve_500_error(request, *args, **kwargs):
+  """Registered handler for 500. We use the debug view to make debugging easier."""
+  if desktop.conf.HTTP_500_DEBUG_MODE.get():
+    return django.views.debug.technical_500_response(request, *sys.exc_info())
+  return render_to_response("500.html")