You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2015/11/09 23:43:51 UTC

allura git commit: [#5694] limit_param_max config option; enforce limit checks in missing places

Repository: allura
Updated Branches:
  refs/heads/db/5694 [created] 7282b402a


[#5694] limit_param_max config option; enforce limit checks in missing places


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/7282b402
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/7282b402
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/7282b402

Branch: refs/heads/db/5694
Commit: 7282b402ae5b84c8f8cab1500e954211bd98cda0
Parents: 9fa2bc0
Author: Dave Brondsema <da...@brondsema.net>
Authored: Mon Nov 9 17:36:54 2015 -0500
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Mon Nov 9 17:43:43 2015 -0500

----------------------------------------------------------------------
 Allura/allura/controllers/discuss.py                  | 14 ++++++--------
 Allura/allura/controllers/repository.py               |  2 ++
 Allura/allura/lib/app_globals.py                      |  2 ++
 Allura/allura/lib/helpers.py                          |  7 ++++---
 Allura/allura/model/artifact.py                       | 14 ++++++--------
 Allura/allura/model/discuss.py                        |  8 +++++---
 Allura/allura/model/project.py                        |  5 ++---
 Allura/allura/tests/test_globals.py                   |  2 ++
 Allura/allura/tests/test_helpers.py                   |  5 ++++-
 Allura/development.ini                                |  3 +++
 Allura/docs/api-rest/api.raml                         |  2 +-
 Allura/docs/api-rest/traits.yaml                      |  2 +-
 ForgeActivity/forgeactivity/main.py                   |  4 ++--
 ForgeBlog/forgeblog/main.py                           |  4 ++--
 ForgeBlog/forgeblog/model/blog.py                     |  4 ++--
 ForgeDiscussion/forgediscussion/controllers/root.py   |  7 +++----
 ForgeSVN/forgesvn/svn_main.py                         |  6 +-----
 ForgeTracker/forgetracker/model/ticket.py             |  7 +++++--
 .../forgetracker/tests/functional/test_rest.py        |  2 +-
 ForgeTracker/forgetracker/tracker_main.py             |  2 +-
 ForgeWiki/forgewiki/model/wiki.py                     |  4 ++--
 ForgeWiki/forgewiki/wiki_main.py                      |  2 +-
 22 files changed, 58 insertions(+), 50 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/Allura/allura/controllers/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index 459caf7..4c0c748 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -440,11 +440,8 @@ class ModerationController(BaseController):
             query['flags'] = {'$gte': int(flag)}
         q = self.PostModel.query.find(query)
         count = q.count()
-        if not page:
-            page = 0
-        page = int(page)
-        limit = int(limit)
-        q = q.skip(page)
+        limit, page, start = g.handle_paging(limit, page or 0, default=50)
+        q = q.skip(start)
         q = q.limit(limit)
         pgnum = (page // limit) + 1
         pages = (count // limit) + 1
@@ -486,7 +483,7 @@ class PostRestController(PostController):
 
     @expose('json:')
     def index(self, **kw):
-        return dict(post=self.post)
+        return dict(post=self.post.__json__())
 
     @h.vardec
     @expose()
@@ -503,8 +500,9 @@ class PostRestController(PostController):
 class ThreadRestController(ThreadController):
 
     @expose('json:')
-    def index(self, **kw):
-        return dict(thread=self.thread)
+    def index(self, limit=25, page=None, **kw):
+        limit, page = h.paging_sanitizer(limit, page)
+        return dict(thread=self.thread.__json__(limit=limit, page=page))
 
     @h.vardec
     @expose()

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/Allura/allura/controllers/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index b51d3c7..85caa59 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -367,6 +367,7 @@ class MergeRequestController(object):
         c.thread = self.thread_widget
         c.log_widget = self.log_widget
         c.mr_dispose_form = self.mr_dispose_form
+        limit, page = h.paging_sanitizer(limit, page)
         with self.req.push_downstream_context():
             downstream_app = c.app
         result = dict(
@@ -613,6 +614,7 @@ class CommitBrowser(BaseController):
         is_file = False
         if path:
             is_file = c.app.repo.is_file(path, self._commit._id)
+        limit, _ = h.paging_sanitizer(limit, 0)
         commits = list(islice(c.app.repo.log(
             revs=self._commit._id,
             path=path,

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index c6b52d3..d63c93f 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -383,6 +383,8 @@ class Globals(object):
 
     def handle_paging(self, limit, page, default=25):
         limit = self.manage_paging_preference(limit, default)
+        limit = max(int(limit), 1)
+        limit = min(limit, asint(config.get('limit_param_max', 500)))
         page = max(int(page), 0)
         start = page * int(limit)
         return (limit, page, start)

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index bf5a580..72c64ad 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -53,7 +53,7 @@ from formencode.variabledecode import variable_decode
 import formencode
 from jinja2 import Markup
 from jinja2.filters import contextfilter, escape
-from paste.deploy.converters import asbool, aslist
+from paste.deploy.converters import asbool, aslist, asint
 
 from webhelpers import date, feedgenerator, html, number, misc, text
 from webob.exc import HTTPUnauthorized
@@ -684,16 +684,17 @@ class log_action(object):
             return result
 
 
-def paging_sanitizer(limit, page, total_count, zero_based_pages=True):
+def paging_sanitizer(limit, page, total_count=sys.maxint, zero_based_pages=True):
     """Return limit, page - both converted to int and constrained to
     valid ranges based on total_count.
 
     Useful for sanitizing limit and page query params.
     """
     limit = max(int(limit), 1)
+    limit = min(limit, asint(tg.config.get('limit_param_max', 500)))
     max_page = (total_count / limit) + (1 if total_count % limit else 0)
     max_page = max(0, max_page - (1 if zero_based_pages else 0))
-    page = min(max(int(page), (0 if zero_based_pages else 1)), max_page)
+    page = min(max(int(page or 0), (0 if zero_based_pages else 1)), max_page)
     return limit, page
 
 

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/Allura/allura/model/artifact.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/artifact.py b/Allura/allura/model/artifact.py
index 67cbf3b..4792f44 100644
--- a/Allura/allura/model/artifact.py
+++ b/Allura/allura/model/artifact.py
@@ -103,7 +103,7 @@ class Artifact(MappedClass, SearchIndexable):
     import_id = FieldProperty(None, if_missing=None)
     deleted = FieldProperty(bool, if_missing=False)
 
-    def __json__(self):
+    def __json__(self, posts_limit=None):
         """Return a JSON-encodable :class:`dict` representation of this
         Artifact.
 
@@ -113,7 +113,7 @@ class Artifact(MappedClass, SearchIndexable):
             mod_date=self.mod_date,
             labels=list(self.labels),
             related_artifacts=[a.url() for a in self.related_artifacts()],
-            discussion_thread=self.discussion_thread.__json__(),
+            discussion_thread=self.discussion_thread.__json__(limit=posts_limit),
             discussion_thread_url=h.absurl('/rest%s' %
                                            self.discussion_thread.url()),
         )
@@ -867,7 +867,7 @@ class Feed(MappedClass):
 
     @classmethod
     def feed(cls, q, feed_type, title, link, description,
-             since=None, until=None, offset=None, limit=None):
+             since=None, until=None, page=None, limit=None):
         "Produces webhelper.feedgenerator Feed"
         d = dict(title=title, link=h.absurl(link),
                  description=description, language=u'en',
@@ -876,6 +876,7 @@ class Feed(MappedClass):
             feed = FG.Atom1Feed(**d)
         elif feed_type == 'rss':
             feed = RssFeed(**d)
+        limit, page = h.paging_sanitizer(limit or 10, page)
         query = defaultdict(dict)
         query.update(q)
         if since is not None:
@@ -884,11 +885,8 @@ class Feed(MappedClass):
             query['pubdate']['$lte'] = until
         cur = cls.query.find(query)
         cur = cur.sort('pubdate', pymongo.DESCENDING)
-        if limit is None:
-            limit = 10
-        query = cur.limit(limit)
-        if offset is not None:
-            query = cur.offset(offset)
+        cur = cur.limit(limit)
+        cur = cur.skip(limit * page)
         for r in cur:
             feed.add_item(title=r.title,
                           link=h.absurl(r.link.encode('utf-8')),

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/Allura/allura/model/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/discuss.py b/Allura/allura/model/discuss.py
index a704da7..a7642a7 100644
--- a/Allura/allura/model/discuss.py
+++ b/Allura/allura/model/discuss.py
@@ -62,14 +62,14 @@ class Discussion(Artifact, ActivityObject):
     threads = RelationProperty('Thread', via='discussion_id')
     posts = RelationProperty('Post', via='discussion_id')
 
-    def __json__(self):
+    def __json__(self, limit=None, posts_limit=None):
         return dict(
             _id=str(self._id),
             shortname=self.shortname,
             name=self.name,
             description=self.description,
-            threads=[t.__json__() for t in self.thread_class().query.find(
-                dict(discussion_id=self._id))]
+            threads=[t.__json__(limit=posts_limit) for t
+                     in self.thread_class().query.find(dict(discussion_id=self._id)).limit(limit or 0)]
         )
 
     @property
@@ -178,6 +178,8 @@ class Thread(Artifact, ActivityObject):
             _id=self._id,
             discussion_id=str(self.discussion_id),
             subject=self.subject,
+            limit=limit,
+            page=page,
             posts=[dict(slug=p.slug,
                         text=p.text,
                         subject=p.subject,

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index cef25bc..7d917f1 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -1091,9 +1091,8 @@ class Project(SearchIndexable, MappedClass, ActivityNode, ActivityObject):
                         for u in self.users_with_role('Developer')],
             tools=[self.app_instance(t) for t in self.app_configs if h.has_access(t, 'read')],
             labels=list(self.labels),
-            categories={
-                n: [t.__json__(
-                ) for t in ts] for n, ts in self.all_troves().items()},
+            categories={n: [t.__json__() for t in ts]
+                        for n, ts in self.all_troves().items()},
             icon_url=h.absurl(self.url() + 'icon') if self.icon else None,
             screenshots=[
                 dict(

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/Allura/allura/tests/test_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_globals.py b/Allura/allura/tests/test_globals.py
index c29cfa2..5d2148b 100644
--- a/Allura/allura/tests/test_globals.py
+++ b/Allura/allura/tests/test_globals.py
@@ -770,6 +770,8 @@ class TestHandlePaging(unittest.TestCase):
         self.assertEqual(g.handle_paging(10, 2), (10, 2, 20))
         # handle paging must not mess up user preferences
         self.assertEqual(c.user.get_pref('results_per_page'), None)
+        # maximum enforced
+        self.assertEqual(g.handle_paging(99999999, 0), (500, 0, 0))
 
     def test_without_limit(self):
         # default limit = 25

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/Allura/allura/tests/test_helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index e9d13d2..8f2c01e 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -227,7 +227,10 @@ def test_paging_sanitizer():
         (5, '-1', 25): (5, 0),
         ('5', -1, 25, False): (5, 1),
         (5, '3', 25): (5, 3),
-        ('5', 3, 25, False): (5, 3)
+        ('5', 3, 25, False): (5, 3),
+        (9999999, 0, 0): (500, 0),
+        (10, None, 0): (10, 0),
+        (10, 0): (10, 0),
     }
     for input, output in test_data.iteritems():
         assert (h.paging_sanitizer(*input)) == output

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index 4c540d5..e524581 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -480,6 +480,9 @@ allow_project_undelete = true
 lcd_thread_chunk_size = 10
 lcd_timeout = 60
 
+; Many URLs support a param like limit=50  This setting controls the max value allowed for that parameter.
+; Allowing exceedingly high values may have a performance impact
+limit_param_max = 500
 
 ;
 ; Settings for the Blog tool

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/Allura/docs/api-rest/api.raml
----------------------------------------------------------------------
diff --git a/Allura/docs/api-rest/api.raml b/Allura/docs/api-rest/api.raml
index 244c5db..21d64ff 100755
--- a/Allura/docs/api-rest/api.raml
+++ b/Allura/docs/api-rest/api.raml
@@ -284,7 +284,7 @@ documentation:
           get:
             description: |
               returns summary information about a thread, including the posts in a thread
-            is: [ bearerAuth ]
+            is: [ bearerAuth, pageable ]
           /{slug}:
             uriParameters:
              slug:

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/Allura/docs/api-rest/traits.yaml
----------------------------------------------------------------------
diff --git a/Allura/docs/api-rest/traits.yaml b/Allura/docs/api-rest/traits.yaml
index ab746f3..d3f17a4 100755
--- a/Allura/docs/api-rest/traits.yaml
+++ b/Allura/docs/api-rest/traits.yaml
@@ -47,7 +47,7 @@
         type: integer
         required: false
         example: 10
-        default: 10
+        default: 25
 - permissionTestable:
     description: |
       **Endpoints**

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/ForgeActivity/forgeactivity/main.py
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/main.py b/ForgeActivity/forgeactivity/main.py
index 845eb9e..d51b0e2 100644
--- a/ForgeActivity/forgeactivity/main.py
+++ b/ForgeActivity/forgeactivity/main.py
@@ -110,8 +110,8 @@ class ForgeActivityController(BaseController):
             actor_only = False
 
         following = g.director.is_connected(c.user, followee)
-        page = asint(kw.get('page', 0))
-        limit = extra_limit = asint(kw.get('limit', 100))
+        limit, page = h.paging_sanitizer(kw.get('limit', 100), kw.get('page', 0))
+        extra_limit = limit
         # get more in case perm check filters some out
         if page == 0 and limit <= 10:
             extra_limit = limit * 20

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/ForgeBlog/forgeblog/main.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index a3483cf..622e036 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -536,7 +536,7 @@ class PostRestController(BaseController):
         else:
             if self.post.state == 'draft':
                 require_access(self.post, 'write')
-            return self.post.__json__()
+            return self.post.__json__(posts_limit=10)
 
     def _update_post(self, **post_data):
         require_access(self.post, 'write')
@@ -552,4 +552,4 @@ class PostRestController(BaseController):
         if 'labels' in post_data:
             self.post.labels = post_data['labels'].split(',')
         self.post.commit()
-        return self.post.__json__()
+        return self.post.__json__(posts_limit=10)

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/ForgeBlog/forgeblog/model/blog.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/model/blog.py b/ForgeBlog/forgeblog/model/blog.py
index 41b9f1b..818e207 100644
--- a/ForgeBlog/forgeblog/model/blog.py
+++ b/ForgeBlog/forgeblog/model/blog.py
@@ -288,8 +288,8 @@ class BlogPost(M.VersionedArtifact, ActivityObject):
             subject='%s discussion' % post.title)
         return post
 
-    def __json__(self):
-        return dict(super(BlogPost, self).__json__(),
+    def __json__(self, posts_limit=None):
+        return dict(super(BlogPost, self).__json__(posts_limit=posts_limit),
                     author=self.author().username,
                     title=self.title,
                     url=h.absurl('/rest' + self.url()),

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/ForgeDiscussion/forgediscussion/controllers/root.py
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/forgediscussion/controllers/root.py b/ForgeDiscussion/forgediscussion/controllers/root.py
index 8fe5d39..cb4b4f8 100644
--- a/ForgeDiscussion/forgediscussion/controllers/root.py
+++ b/ForgeDiscussion/forgediscussion/controllers/root.py
@@ -383,15 +383,14 @@ class ForumRestController(BaseController):
     @expose('json:')
     def index(self, limit=None, page=0, **kw):
         limit, page, start = g.handle_paging(limit, int(page))
-        topics = model.Forum.thread_class().query.find(
-            dict(discussion_id=self.forum._id))
+        topics = model.Forum.thread_class().query.find(dict(discussion_id=self.forum._id))
         topics = topics.sort([('flags', pymongo.DESCENDING),
                               ('last_post_date', pymongo.DESCENDING)])
         topics = topics.skip(start).limit(limit)
         count = topics.count()
         json = {}
-        json['forum'] = self.forum.__json__()
-        # it appears that topics replace threads here
+        json['forum'] = self.forum.__json__(limit=1)  # small limit since we're going to "del" the threads anyway
+        # topics replace threads here
         del json['forum']['threads']
         json['forum']['topics'] = [dict(_id=t._id,
                                         subject=t.subject,

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/ForgeSVN/forgesvn/svn_main.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/svn_main.py b/ForgeSVN/forgesvn/svn_main.py
index e87d106..72968b3 100644
--- a/ForgeSVN/forgesvn/svn_main.py
+++ b/ForgeSVN/forgesvn/svn_main.py
@@ -193,11 +193,7 @@ class SVNCommitBrowserController(BaseController):
             'built_tree': {},
             'next_commit': None,
         }
-        try:
-            limit = asint(limit)
-        except ValueError as e:
-            pass
-        limit = limit or 100
+        limit, _ = h.paging_sanitizer(limit or 100, 0, 0)
         for i, commit in enumerate(c.app.repo.log(revs=start, id_only=False, page_size=limit+1)):
             if i >= limit:
                 data['next_commit'] = str(commit['id'])

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/ForgeTracker/forgetracker/model/ticket.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 20996ff..36fec0b 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -1106,11 +1106,14 @@ class Ticket(VersionedArtifact, ActivityObject, VotableArtifact):
             ticket.discussion_thread.add_post(text=message, notify=notify)
         return ticket
 
-    def __json__(self):
+    def __json__(self, posts_limit=None):
         parents_json = {}
         for parent in reversed(type(self).mro()):
             if parent != type(self) and hasattr(parent, '__json__'):
-                parents_json.update(parent.__json__(self))
+                kwargs = {}
+                if parent == VersionedArtifact:
+                    kwargs['posts_limit'] = posts_limit
+                parents_json.update(parent.__json__(self, **kwargs))
 
         return dict(parents_json,
                     created_date=self.created_date,

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/ForgeTracker/forgetracker/tests/functional/test_rest.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_rest.py b/ForgeTracker/forgetracker/tests/functional/test_rest.py
index a45477e..1b3ba80 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_rest.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_rest.py
@@ -110,7 +110,7 @@ class TestRestUpdateTicket(TestTrackerApiBase):
         args = dict(self.ticket_args, summary='test update ticket', labels='',
                     assigned_to=self.ticket_args['assigned_to_id'] or '')
         for bad_key in ('ticket_num', 'assigned_to_id', 'created_date',
-                        'reported_by', 'reported_by_id', '_id', 'votes_up', 'votes_down'):
+                        'reported_by', 'reported_by_id', '_id', 'votes_up', 'votes_down', 'discussion_thread'):
             del args[bad_key]
         args['private'] = str(args['private'])
         args['discussion_disabled'] = str(args['discussion_disabled'])

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index edd5555..4eec4d5 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -1865,7 +1865,7 @@ class TicketRestController(BaseController):
 
     @expose('json:')
     def index(self, **kw):
-        return dict(ticket=self.ticket)
+        return dict(ticket=self.ticket.__json__(posts_limit=10))
 
     @expose()
     @h.vardec

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/ForgeWiki/forgewiki/model/wiki.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/model/wiki.py b/ForgeWiki/forgewiki/model/wiki.py
index 9ddc7f2..10af425 100644
--- a/ForgeWiki/forgewiki/model/wiki.py
+++ b/ForgeWiki/forgewiki/model/wiki.py
@@ -122,8 +122,8 @@ class Page(VersionedArtifact, ActivityObject):
         d.update(summary=self.title)
         return d
 
-    def __json__(self):
-        return dict(super(Page, self).__json__(),
+    def __json__(self, posts_limit=None):
+        return dict(super(Page, self).__json__(posts_limit=posts_limit),
                     title=self.title,
                     text=self.text,
                     labels=list(self.labels),

http://git-wip-us.apache.org/repos/asf/allura/blob/7282b402/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index cf37ac0..b08d03e 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -833,7 +833,7 @@ class PageRestController(BaseController):
             return self._update_page(self.title, **kw)
         if self.page is None:
             raise exc.HTTPNotFound()
-        return self.page.__json__()
+        return self.page.__json__(posts_limit=10)
 
     def _update_page(self, title, **post_data):
         with h.notifications_disabled(c.project):