Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Ticket #2351 (closed defect: fixed)

Opened 10 years ago

Last modified 9 years ago

KeyError: '' in expose if Accept header doesn't match controller content-type

Reported by: corvus Owned by:
Priority: high Milestone: 2.1b1
Component: TurboGears Version: 2.0.1
Severity: normal Keywords:


If a poorly behaved client (like a bot) sends an Accept header that does not include the content type you have specified that a controller outputs via the expose decorator, TurboGears throws an exception. Erroring out is reasonable, however, not handling the exception subjects the developer to unwanted notices without informing him or the the operator of the user agent of the problem.

Instead, TG should probably return a 500 with a descriptive text indicating the problem.

To reproduce, create a controller like:

    def rss2_0(self, **kw):
        return 'test'


$ telnet localhost 8080
Connected to localhost.localdomain.
Escape character is '^]'.
GET /rss2_0 HTTP/1.1
Accept: text/html

And you'll get an exception like:

File '/usr/local/env/lib/python2.5/site-packages/WebError-0.10.1-py2.5.egg/weberror/errormiddleware.py', line 162 in __call__
  app_iter = self.application(environ, sr_checker)
File '/usr/local/env/lib/python2.5/site-packages/TurboGears2-2.0.1-py2.5.egg/tg/configuration.py', line 643 in wrapper
  return app(environ, start_response)
File '/usr/local/env/lib/python2.5/site-packages/TurboGears2-2.0.1-py2.5.egg/tg/configuration.py', line 543 in remover
  return app(environ, start_response)
File '/usr/local/env/lib/python2.5/site-packages/repoze.tm2-1.0a4-py2.5.egg/repoze/tm/__init__.py', line 19 in __call__
  result = self.application(environ, save_status_and_headers)
File '/usr/local/env/lib/python2.5/site-packages/repoze.who-1.0.10-py2.5.egg/repoze/who/middleware.py', line 107 in __call__
  app_iter = app(environ, wrapper.wrap_start_response)
File '/usr/local/env/lib/python2.5/site-packages/ToscaWidgets-', line 36 in __call__
  return self.wsgi_app(environ, start_response)
File '/usr/local/env/lib/python2.5/site-packages/ToscaWidgets-', line 59 in wsgi_app
  resp = req.get_response(self.application)
File 'build/bdist.linux-i686/egg/webob/__init__.py', line 1325 in get_response
File 'build/bdist.linux-i686/egg/webob/__init__.py', line 1293 in call_application
File '/usr/local/env/lib/python2.5/site-packages/ToscaWidgets-', line 67 in _injector
  resp = req.get_response(app)
File 'build/bdist.linux-i686/egg/webob/__init__.py', line 1325 in get_response
File 'build/bdist.linux-i686/egg/webob/__init__.py', line 1293 in call_application
File '/usr/local/env/lib/python2.5/site-packages/Beaker-1.3-py2.5.egg/beaker/middleware.py', line 81 in __call__
  return self.app(environ, start_response)
File '/usr/local/env/lib/python2.5/site-packages/Beaker-1.3-py2.5.egg/beaker/middleware.py', line 160 in __call__
  return self.wrap_app(environ, session_start_response)
File '/usr/local/env/lib/python2.5/site-packages/Routes-1.10.3-py2.5.egg/routes/middleware.py', line 130 in __call__
  response = self.app(environ, start_response)
File '/usr/local/env/lib/python2.5/site-packages/Pylons-0.9.7-py2.5.egg/pylons/wsgiapp.py', line 125 in __call__
  response = self.dispatch(controller, environ, start_response)
File '/usr/local/env/lib/python2.5/site-packages/Pylons-0.9.7-py2.5.egg/pylons/wsgiapp.py', line 324 in dispatch
  return controller(environ, start_response)
File '/usr/local/env/app/app/lib/base.py', line 32 in __call__
  return TGController.__call__(self, environ, start_response)
File '/usr/local/env/lib/python2.5/site-packages/Pylons-0.9.7-py2.5.egg/pylons/controllers/core.py', line 221 in __call__
  response = self._dispatch_call()
File '/usr/local/env/lib/python2.5/site-packages/Pylons-0.9.7-py2.5.egg/pylons/controllers/core.py', line 172 in _dispatch_call
  response = self._inspect_call(func)
File '/usr/local/env/lib/python2.5/site-packages/Pylons-0.9.7-py2.5.egg/pylons/controllers/core.py', line 107 in _inspect_call
  result = self._perform_call(func, args)
File '/usr/local/env/lib/python2.5/site-packages/TurboGears2-2.0.1-py2.5.egg/tg/controllers.py', line 836 in _perform_call
  self, controller, params, remainder=remainder)
File '/usr/local/env/lib/python2.5/site-packages/TurboGears2-2.0.1-py2.5.egg/tg/controllers.py', line 182 in _perform_call
  response = self._render_response(controller, output)
File '/usr/local/env/lib/python2.5/site-packages/TurboGears2-2.0.1-py2.5.egg/tg/controllers.py', line 294 in _render_response
File '/usr/local/env/lib/python2.5/site-packages/TurboGears2-2.0.1-py2.5.egg/tg/decorators.py', line 138 in lookup_template_engine
  engine, template, exclude_names = self.engines[content_type]
KeyError: ''

Change History

comment:1 Changed 10 years ago by corvus

It also appears that "Accept: image/*" will not match a controller exposed as "image/jpeg", only an "Accept: */*" works for that.

comment:2 Changed 10 years ago by corvus

The malformed header 'Accept: */* Accept-Language: zh-cn' triggers this as well.

comment:3 Changed 10 years ago by jorge.vargas

I was able to see this before with #2232 now this seems like a solid lead.

comment:4 Changed 10 years ago by jorge.vargas

  • Milestone set to 2.1

Could you please test this out with the 2.1 branch? the content-type code has been refractored and fixed as it was honestly very messy.

comment:5 Changed 9 years ago by percious

  • Priority changed from normal to high
  • Milestone changed from 2.1 to 2.1b1

comment:6 Changed 9 years ago by percious

  • Status changed from new to closed
  • Resolution set to fixed

I remember fixing this a while back when we were trying to sort out the testing problems with content_types (json wasnt working right). In any event, a test has been added to prove this still works okay, and I tested it on a 2.1 application to double check. Time to close.

Note: See TracTickets for help on using tickets.