[#8381] max limits for file viewing/downloading from a repo
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index 77a4d0f..7ee5e95 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -845,7 +845,12 @@
     @expose('jinja:allura:templates/repo/file.html')
     def index(self, **kw):
         if kw.pop('format', 'html') == 'raw':
-            return self.raw()
+            if self._blob.size > asint(tg.config.get('scm.download.max_file_bytes', 30*1000*1000)):
+                large_size = self._blob.size
+                flash('File is {}.  Too large to download.'.format(h.do_filesizeformat(large_size)), 'warning')
+                raise exc.HTTPForbidden
+            else:
+                return self.raw()
         elif 'diff' in kw:
             tg.decorators.override_template(
                 self.index, 'jinja:allura:templates/repo/diff.html')
@@ -856,11 +861,17 @@
             return self.diff(kw['barediff'], kw.pop('diformat', None), kw.pop('prev_file', None))
         else:
             force_display = 'force' in kw
-            stats = utils.generate_code_stats(self._blob)
+            if self._blob.size > asint(tg.config.get('scm.view.max_file_bytes', 5*1000*1000)):
+                large_size = self._blob.size
+                stats = None
+            else:
+                large_size = False
+                stats = utils.generate_code_stats(self._blob)
             return dict(
                 blob=self._blob,
                 stats=stats,
-                force_display=force_display
+                force_display=force_display,
+                large_size=large_size,
             )
 
     def raw(self, **kw):
diff --git a/Allura/allura/templates/repo/file.html b/Allura/allura/templates/repo/file.html
index 5c54990..8acb678 100644
--- a/Allura/allura/templates/repo/file.html
+++ b/Allura/allura/templates/repo/file.html
@@ -73,7 +73,10 @@
 </script>
 {% endblock %}
 {% block content %}
-  {% if blob.has_image_view %}
+  {% if large_size %}
+    <p><em>File is {{ large_size|filesizeformat}}.  Too large to display.</em></p>
+    <p><a rel="nofollow" href="?format=raw">Download this file</a></p>
+  {% elif blob.has_image_view %}
     <p><a rel="nofollow" href="?format=raw">Download this file</a></p>
     <img src="?format=raw" alt=""/>
   {% elif blob.has_html_view or blob.has_pypeline_view or force_display %}
diff --git a/Allura/development.ini b/Allura/development.ini
index 6bc5cf1..3d21fd4 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -434,6 +434,12 @@
 ; Default limit for when to stop doing syntax highlighting (can take a lot of CPU for large files)
 scm.view.max_syntax_highlight_bytes = 500000
 
+; Max size for viewing a file from a repo, can take a lot of template processing (even with syntax highlighting disabled)
+scm.view.max_file_bytes = 5000000
+
+; Max size for download a raw file from a repo
+scm.download.max_file_bytes = 30000000
+
 ; bulk_export_enabled = true
 ; If you keep bulk_export_enabled, you should set up your server to securely share bulk_export_path with users somehow
 bulk_export_path = /tmp/bulk_export/{nbhd}/{project}
diff --git a/ForgeGit/forgegit/tests/functional/test_controllers.py b/ForgeGit/forgegit/tests/functional/test_controllers.py
index b966fc6..6b6a212 100644
--- a/ForgeGit/forgegit/tests/functional/test_controllers.py
+++ b/ForgeGit/forgegit/tests/functional/test_controllers.py
@@ -32,6 +32,7 @@
 import pkg_resources
 from nose.tools import assert_regexp_matches
 from tg import tmpl_context as c
+import tg
 from ming.orm import ThreadLocalORMSession
 from mock import patch, PropertyMock
 
@@ -312,6 +313,17 @@
         assert_equal(resp.headers.get('Content-Disposition'),
                      'attachment;filename="with%22%26%3Aspecials.txt"')
 
+    def test_file_too_large(self):
+        ci = self._get_ci()
+        with h.push_config(tg.config, **{'scm.view.max_file_bytes': '3'}):
+            resp = self.app.get(ci + 'tree/README')
+        resp.mustcontain('Too large')
+        resp.mustcontain(' 28 Bytes')
+        resp.mustcontain(no='This is readme')
+
+        with h.push_config(tg.config, **{'scm.download.max_file_bytes': '3'}):
+            resp = self.app.get(ci + 'tree/README?format=raw', status=403)
+
     def test_invalid_file(self):
         ci = self._get_ci()
         self.app.get(ci + 'tree/READMEz', status=404)