1481: Review Board 500 error if testing done is over 65535 characters (or a bit smaller)

lon***@gmai***** (Google Code) (Is this you? Claim this profile.)
Aug. 29, 2011
1648
What version are you running?
1.5.0.1

What's the URL of the page containing the problem?
private, but can be reproduced easily, by submitting a new request
see: http://demo.reviewboard.org/r/3217/
(or http://demo.reviewboard.org/r/3217/diff as the above reports a 500)

What steps will reproduce the problem?
1. Create a new review request, publish it.
2. Update the review request, filling the testing done field with over
67000 characters (for instance: "".join(map(str,range(1,16000))) )
3. Save
4. Review Board reports a 500 error.

Traceback (most recent call last):

  File
"/opt/software/lib/python2.5/site-packages/Django-1.1.1-py2.5.egg/django/core/handlers/base.py",
line 92, in get_response
    response = callback(request, *callback_args, **callback_kwargs)

  File
"/opt/software/lib/python2.5/site-packages/ReviewBoard-1.0.5.1-py2.5.egg/reviewboard/accounts/decorators.py",
line 25, in _check
    return login_required(view_func)(*args, **kwargs)

  File
"/opt/software/lib/python2.5/site-packages/Djblets-0.5.5-py2.5.egg/djblets/auth/util.py",
line 46, in _checklogin
    return view_func(request, *args, **kwargs)

  File
"/opt/software/lib/python2.5/site-packages/ReviewBoard-1.0.5.1-py2.5.egg/reviewboard/reviews/views.py",
line 188, in review_detail
    for changedesc in changedescs:

  File
"/opt/software/lib/python2.5/site-packages/Django-1.1.1-py2.5.egg/django/db/models/query.py",
line 106, in _result_iter
    self._fill_cache()

  File
"/opt/software/lib/python2.5/site-packages/Django-1.1.1-py2.5.egg/django/db/models/query.py",
line 692, in _fill_cache
    self._result_cache.append(self._iter.next())

  File
"/opt/software/lib/python2.5/site-packages/Django-1.1.1-py2.5.egg/django/db/models/query.py",
line 251, in iterator
    obj = self.model(*row[index_start:aggregate_start])

  File
"/opt/software/lib/python2.5/site-packages/Django-1.1.1-py2.5.egg/django/db/models/base.py",
line 324, in __init__
    signals.post_init.send(sender=self.__class__, instance=self)

  File
"/opt/software/lib/python2.5/site-packages/Django-1.1.1-py2.5.egg/django/dispatch/dispatcher.py",
line 166, in send
    response = receiver(signal=self, sender=sender, **named)

  File
"/opt/software/lib/python2.5/site-packages/Djblets-0.5.5-py2.5.egg/djblets/util/fields.py",
line 174, in post_init
    value = self.loads(value)

  File
"/opt/software/lib/python2.5/site-packages/Djblets-0.5.5-py2.5.egg/djblets/util/fields.py",
line 206, in loads
    val = eval(val)

  File "<string>", line 1

    {"testing_done": {"new":
["12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814....

5264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532

^

SyntaxError: EOL while scanning single-quoted string


What is the expected output? What do you see instead?

The review should be published.  A 500 error is displayed instead.


What operating system are you using? What browser?

Linux for the server.  Firefox/windows for the browser.

Please provide any additional information below.

The issue is that the fields_changed field in changedescs_changedescription
is truncated to 65535 characters as shown below, and the python object is
missing the ']}} termination characters to have a well formed string that
JSON could parse (I'm using simplejson).

mysql> select id, right(fields_changed,100) from
changedescs_changedescription where length(fields_changed)>65000 ;
+-------+------------------------------------------------------------------------------------------------------+
| id    | right(fields_changed,100)                                       
                                    |
+-------+------------------------------------------------------------------------------------------------------+
| 10043 |
3153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532
| 
+-------+------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select id, left(fields_changed,100) from
changedescs_changedescription where length(fields_changed)>65000 ;
+-------+------------------------------------------------------------------------------------------------------+
| id    | left(fields_changed,100)                                        
                                    |
+-------+------------------------------------------------------------------------------------------------------+
| 10043 | {"testing_done": {"new":
["1234567891011121314151617181920212223242526272829303132333435363738394041 | 
+-------+------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select length(fields_changed) from changedescs_changedescription 
where length(fields_changed)>65000 ;
+------------------------+
| length(fields_changed) |
+------------------------+
|                  65535 | 
+------------------------+
1 row in set (0.00 sec)

mysql> select id, right(testing_done, 100) from reviews_reviewrequest where
length(testing_done)>65000 ;
+------+------------------------------------------------------------------------------------------------------+
| id   | right(testing_done, 100)                                         
                                   |
+------+------------------------------------------------------------------------------------------------------+
| 4246 |
091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815A
| 
+------+------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select id, length(testing_done) from reviews_reviewrequest where
length(testing_done)>65000 ;
+------+----------------------+
| id   | length(testing_done) |
+------+----------------------+
| 4246 |                65537 | 
+------+----------------------+
1 row in set (0.01 sec)



Clearly, it's not very reasonable to have such a large data set, but I
think we need to protect from it.  As the fields_changed can contain
several fields, the problem could be recreated using different combination
of old and new fields as well.
#1 lon***@gmai***** (Google Code) (Is this you? Claim this profile.)
I reproduced the issue on the demo server 1.1 alpha 3 (dev), but I'm getting an
additional error at submission time.  It's a bit better, but the review is still not
accessible:
http://demo.reviewboard.org/r/3217/


Warning at /api/json/reviewrequests/3217/publish/

Data truncated for column 'fields_changed' at row 1

Request Method: 	POST
Request URL: 	http://demo.reviewboard.org/api/json/reviewrequests/3217/publish/
Exception Type: 	Warning
Exception Value: 	

Data truncated for column 'fields_changed' at row 1

Exception Location: 	/usr/lib/python2.5/warnings.py in warn_explicit, line 102
Python Executable: 	/usr/bin/python
Python Version: 	2.5.2
Python Path: 	['/var/www/demo.reviewboard.org/conf',
'/usr/lib/python2.5/site-packages/python_memcached-1.40-py2.5.egg',
'/usr/lib/python2.5/site-packages/BuildBatter-0.1-py2.5.egg',
'/usr/lib/python2.5/site-packages/virtualenv-1.3-py2.5.egg',
'/usr/lib/python2.5/site-packages/django_evolution-0.0.0-py2.5.egg',
'/usr/lib/python2.5/site-packages/flup-1.0.1-py2.5.egg',
'/usr/lib/python2.5/site-packages/docutils-0.5-py2.5.egg',
'/usr/lib/python2.5/site-packages/Jinja2-2.1.1-py2.5-linux-i686.egg',
'/usr/lib/python2.5/site-packages/setuptools-0.6c9-py2.5.egg',
'/usr/lib/python2.5/site-packages/JCC-2.1-py2.5-linux-i686.egg',
'/usr/lib/python2.5/site-packages/pytz-2009f-py2.5.egg',
'/usr/lib/python2.5/site-packages/gitosis-0.2-py2.5.egg',
'/usr/lib/python2.5/site-packages/buildbot-0.7.10p1-py2.5.egg',
'/usr/lib/python2.5/site-packages/Django-1.1.1-py2.5.egg',
'/usr/lib/python2.5/site-packages/Sphinx-0.6.3-py2.5.egg',
'/usr/lib/python2.5/site-packages/recaptcha_client-1.0.5-py2.5.egg',
'/usr/lib/python2.5/site-packages/paramiko-1.7.6-py2.5.egg',
'/usr/lib/python2.5/site-packages/Pygments-1.1.1-py2.5.egg',
'/usr/lib/python2.5/site-packages/pycrypto-2.0.1-py2.5-linux-i686.egg',
'/usr/lib/python2.5/site-packages/ReviewBoard-1.1alpha3.dev_20100113-py2.5.egg',
'/usr/lib/python2.5/site-packages/Djblets-0.5.7alpha0.dev_20100113-py2.5.egg',
'/usr/lib/python25.zip', '/usr/lib/python2.5', '/usr/lib/python2.5/plat-linux2',
'/usr/lib/python2.5/lib-tk', '/usr/lib/python2.5/lib-dynload',
'/usr/local/lib/python2.5/site-packages', '/usr/lib/python2.5/site-packages',
'/usr/lib/python2.5/site-packages/PIL', '/var/lib/python-support/python2.5']
Server time: 	Mon, 1 Feb 2010 12:05:04 -0800
Traceback Switch to copy-and-paste view

    *
/usr/lib/python2.5/site-packages/Django-1.1.1-py2.5.egg/django/core/handlers/base.py
in get_response
        85. # Apply view middleware
        86. for middleware_method in self._view_middleware:
        87. response = middleware_method(request, callback, callback_args,
callback_kwargs)
        88. if response:
        89. return response
        90.
        91. try:
        92. response = callback(request, *callback_args, **callback_kwargs) ...
        93. except Exception, e:
        94. # If the view raised an exception, run it through exception
        95. # middleware, and if the exception middleware returns a
        96. # response, use that. Otherwise, reraise the exception.
        97. for middleware_method in self._exception_middleware:
        98. response = middleware_method(request, e)
      ? Local vars
      Variable 	Value
      callback 	
      <function review_request_publish at 0x9733a04>
      callback_args 	
      ()
      callback_kwargs 	
      {'api_format': u'json', 'review_request_id': u'3217'}
      e 	
      Warning(u"Data truncated for column 'fields_changed' at row 1",)
      exc_info 	
      (<class '_mysql_exceptions.Warning'>, Warning(u"Data truncated for column
'fields_changed' at row 1",), <traceback object at 0xa4f0d24>)
      exceptions 	
      <module 'django.core.exceptions' from
'/usr/lib/python2.5/site-packages/Django-1.1.1-py2.5.egg/django/core/exceptions.pyc'>
      middleware_method 	
      <bound method LoggingMiddleware.process_exception of
<djblets.log.middleware.LoggingMiddleware object at 0xa16718c>>
      receivers 	
      [(<function _rollback_on_exception at 0x8f59a04>, None)]
      request 	
      <ModPythonRequest path:/api/json/reviewrequests/3217/publish/, GET:<QueryDict:
{}>, POST:<QueryDict: {u'dummy': [u'']}>, COOKIES:{'__utma':
'78002967.1485541389.1255497952.1264623807.1265052397.42', '__utmb':
'78002967.3.10.1265052397', '__utmc': '78002967', '__utmz':
'78002967.1264623807.41.24.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=reviewboard%20admin',
'collapsediffs': 'True', 'rbsessionid': '15e22e0f7022de794508d3159bedfbb9'},
META:{'AUTH_TYPE': None, 'CONTENT_LENGTH': '6', 'CONTENT_TYPE':
'application/x-www-form-urlencoded; charset=UTF-8', 'GATEWAY_INTERFACE': 'CGI/1.1',
'HTTP_ACCEPT': 'application/json, text/javascript, */*', 'HTTP_ACCEPT_CHARSET':
'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'HTTP_ACCEPT_ENCODING': 'gzip,deflate',
'HTTP_ACCEPT_LANGUAGE': 'en-us,en;q=0.5', 'HTTP_CACHE_CONTROL': 'no-cache',
'HTTP_CONNECTION': 'keep-alive', 'HTTP_CONTENT_LENGTH': '6', 'HTTP_CONTENT_TYPE':
'application/x-www-form-urlencoded; charset=UTF-8', 'HTTP_COOKIE':
'__utma=78002967.1485541389.1255497952.1264623807.1265052397.42;
__utmz=78002967.1264623807.41.24.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=reviewboard%20admin;
__utmc=78002967; __utmb=78002967.3.10.1265052397;
rbsessionid=15e22e0f7022de794508d3159bedfbb9; collapsediffs=True', 'HTTP_HOST':
'demo.reviewboard.org', 'HTTP_PRAGMA': 'no-cache', 'HTTP_REFERER':
'http://demo.reviewboard.org/r/3217/', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows; U;
Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7', 'HTTP_VIA': '1.1
nc-corpse (NetCache NetApp/6.0.3)', 'HTTP_X_FORWARDED_FOR': '10.34.25.33',
'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest', 'PATH_INFO':
u'/api/json/reviewrequests/3217/publish/', 'PATH_TRANSLATED': None, 'QUERY_STRING':
None, 'REMOTE_ADDR': '198.95.226.224', 'REMOTE_HOST': None, 'REMOTE_IDENT': None,
'REMOTE_USER': None, 'REQUEST_METHOD': 'POST', 'SCRIPT_NAME': '', 'SERVER_NAME':
'demo.reviewboard.org', 'SERVER_PORT': 80, 'SERVER_PROTOCOL': 'HTTP/1.1',
'SERVER_SOFTWARE': 'mod_python'}>
      resolver 	
      <RegexURLResolver djblets.util.rooturl (None:None) ^/>
      response 	
      None
      self 	
      <django.core.handlers.modpython.ModPythonHandler object at 0xa21eecc>
      settings 	
      <django.conf.LazySettings object at 0x8d1386c>
      urlconf 	
      'djblets.util.rooturl'
      urlresolvers 	
      <module 'django.core.urlresolvers' from
'/usr/lib/python2.5/site-packages/Django-1.1.1-py2.5.egg/django/core/urlresolvers.pyc'>
    *
#2 lon***@gmai***** (Google Code) (Is this you? Claim this profile.)
Attaching the complete traceback on submission.
  • +
    I reproduced the issue on the demo server 1.1 alpha 3 (dev), but I'm getting an
    additional error at submission time.  It's a bit better, but the review is still not
    accessible:
    http://demo.reviewboard.org/r/3217/
    Warning at /api/json/reviewrequests/3217/publish/
    Data truncated for column 'fields_changed' at row 1
    Request Method: 	POST
    Request URL: 	http://demo.reviewboard.org/api/json/reviewrequests/3217/publish/
    Exception Type: 	Warning
    Exception Value: 	
    Data truncated for column 'fields_changed' at row 1
    Exception Location: 	/usr/lib/python2.5/warnings.py in warn_explicit, line 102
    Python Executable: 	/usr/bin/python
    Python Version: 	2.5.2
    Python Path: 	['/var/www/demo.reviewboard.org/conf',
    '/usr/lib/python2.5/site-packages/python_memcached-1.40-py2.5.egg',
    '/usr/lib/python2.5/site-packages/BuildBatter-0.1-py2.5.egg',
    '/usr/lib/python2.5/site-packages/virtualenv-1.3-py2.5.egg',
    '/usr/lib/python2.5/site-packages/django_evolution-0.0.0-py2.5.egg',
    '/usr
#3 m.mil*****@gmai***** (Google Code) (Is this you? Claim this profile.)
We've experienced this recently on a couple of reviews.  Contemplating changing fields_changed in relation changedescs_changedescription from MySQL 'text' type to 'mediumtext' or 'longtext' but curious what others have done or if there is recommended solution besides telling users not to post so much content in description.
#5 ledmo*****@gmai***** (Google Code) (Is this you? Claim this profile.)
It's a problem of djblets' JSONField. 
Please remove 'db_type' method from JSONField, and everything goes well, because TextField uses 'longtext' in default.


class JSONField(models.TextField):
    """
    A field for storing JSON-encoded data. The data is accessible as standard
    Python data types and is transparently encoded/decoded to/from a JSON
    string in the database.
    """
    serialize_to_string = True

    def __init__(self, verbose_name=None, name=None,
                 encoder=DjangoJSONEncoder(), **kwargs):
        models.TextField.__init__(self, verbose_name, name, blank=True,
                                  **kwargs)
        self.encoder = encoder

-     def db_type(self, connection=None):
-         return "text"


Django TextField's mysql type is defined at django.db.backends.mysql.creation

Related issue (Django): https://code.djangoproject.com/ticket/489
#6 ledmo*****@gmai***** (Google Code) (Is this you? Claim this profile.)
sorry, diff above is invalid. new one here:


diff --git a/djblets/util/fields.py b/djblets/util/fields.py
index 33b901b..30671fc 100644
--- a/djblets/util/fields.py
+++ b/djblets/util/fields.py
@@ -149,8 +149,8 @@ class JSONField(models.TextField):
                                   **kwargs)
         self.encoder = encoder
 
-    def db_type(self, connection=None):
-        return "text"
+    def get_internal_type(self):
+        return "TextField"
 
     def contribute_to_class(self, cls, name):
         def get_json(model_instance):
chipx86
#7 chipx86
Why is the get_internal_type needed? We should automatically get this from TextField.get_internal_type.
#9 ledmo*****@gmai***** (Google Code) (Is this you? Claim this profile.)
You are right. I misunderstood something. We don't need get_internal_type here.
Related changeset: https://code.djangoproject.com/changeset/7133
Sorry for confusing post.
#10 ledmo*****@gmai***** (Google Code) (Is this you? Claim this profile.)
Fixed on Djblets 0.6.10 (a04eae9).
david
#11 david
  • +Fixed