#1071: let the controller handler define response header Content-Type
----------------------+-----------------------------------------------------
 Reporter:  dalke     |        Owner:  anonymous
     Type:  defect    |       Status:  new      
 Priority:  normal    |    Milestone:  1.0      
Component:  CherryPy  |      Version:  0.9a5    
 Severity:  normal    |   Resolution:           
 Keywords:            |  
----------------------+-----------------------------------------------------
Changes (by jorge.vargas):

  * milestone:  => 1.0

Old description:

> As mentioned in ticket 1070, I have controllers which can respond in a
> format selected by a URL parameter.  (This parameter is named "format"
> and cannot be changed to use "tg_format" or con-neg.)
>
> Sometimes it's plain text.  In that case I do something like
>

> {{{
> def format_as_raw_text():
>   cherrypy.response.headers["Content-Type"] = "text/plain"
>   def response():
>       yield "Perhaps this is over kill.  Doing it this way "
>       yield "so I know the header is set before I return anything.\n"
>       yield "I should read the cherrypy docs on this.\n"
>   return response()
> }}}
>
> I expected that I could do the same when I choose to respond via XML
>
> {{{
> def format_as_das2xml():
>   cherrypy.response.headers["Content-Type"] =
> "application/x-das2text+xml"
>   return dict(question="What's the capital of Florida?",
>               answer="Umm.... 'F'!",
>               tg_format="xml",
>               tg_template="das2.templates.q_and_a")
> }}}
>
> With patch 1070 the "tg_format" works so the returned template is
> correct.  Rather, it generates a correct byte stream in the HTTP payload.
> The header is not correct.
> It shows a content-type of "text/xml; charset='utf-8'".
>
> In more details, the content-type before calling my handler is
> "text/html".  My handler sets it to "application/x-...+xml".  Then
> turbogears.view.base.render looks as the @expose setting, sees there is
> no "content_type", and the response header to the "text/html;
> charset='utf-8'".
>
> This is annoying.  I didn't set the @expose content_type because there is
> no meaningful value at that point, but I do have one later on.
>
> I came up with two solutions.  First, I could use the approach of
> "tg_template" (and "tg_format" in patch 1070) and return a
> "tg_content_type" in the dictionary.  I rejected this because it's
> different than what I would do with the plain text solution, where I set
> the response header myself.  I want the two to be structurally similar so
> if one sets cherrypy.headers[...] then the other should as well.
>
> Second I could set the initial response Content-Type to None.  If after
> calling the user-defined controller handler the Content-Type is set then
> use the new value.  Here's the relevant change to
> controller.py:_execute_func
>

> {{{
>     old_content_type = cherrypy.response.headers["Content-Type"]
>     cherrypy.response.headers["Content-Type"] = None
>     output = errorhandling.try_call(func, *args, **kw)
>     if cherrypy.response.headers["Content-Type"] is not None:
>         content_type = cherrypy.response.headers["Content-Type"]
>     else:
>         content_type = old_content_type
>
> }}}
>
> I think of this as a hack.  If this is the right approach then I think
> TurboGears should set "server.default_content_type" to None (is that
> possible?) so CherryPy's response header starts off being None instead of
> "text/html".  Only after the controller handler is run should TG check
> the content-type and if it's still None then set it based on the various
> other settings.
>
> Or not.  Who gets to override whom?  Does the controller function
> override the @expose or vice versa?  In my case the @expose's
> content_type is None so it doesn't matter.

New description:

 As mentioned in ticket #1070, I have controllers which can respond in a
 format selected by a URL parameter.  (This parameter is named "format" and
 cannot be changed to use "tg_format" or con-neg.)

 Sometimes it's plain text.  In that case I do something like


 {{{
 def format_as_raw_text():
   cherrypy.response.headers["Content-Type"] = "text/plain"
   def response():
       yield "Perhaps this is over kill.  Doing it this way "
       yield "so I know the header is set before I return anything.\n"
       yield "I should read the cherrypy docs on this.\n"
   return response()
 }}}

 I expected that I could do the same when I choose to respond via XML

 {{{
 def format_as_das2xml():
   cherrypy.response.headers["Content-Type"] = "application/x-das2text+xml"
   return dict(question="What's the capital of Florida?",
               answer="Umm.... 'F'!",
               tg_format="xml",
               tg_template="das2.templates.q_and_a")
 }}}

 With patch 1070 the "tg_format" works so the returned template is correct.
 Rather, it generates a correct byte stream in the HTTP payload.  The
 header is not correct.
 It shows a content-type of "text/xml; charset='utf-8'".

 In more details, the content-type before calling my handler is
 "text/html".  My handler sets it to "application/x-...+xml".  Then
 turbogears.view.base.render looks as the @expose setting, sees there is no
 "content_type", and the response header to the "text/html;
 charset='utf-8'".

 This is annoying.  I didn't set the @expose content_type because there is
 no meaningful value at that point, but I do have one later on.

 I came up with two solutions.  First, I could use the approach of
 "tg_template" (and "tg_format" in patch 1070) and return a
 "tg_content_type" in the dictionary.  I rejected this because it's
 different than what I would do with the plain text solution, where I set
 the response header myself.  I want the two to be structurally similar so
 if one sets cherrypy.headers[...] then the other should as well.

 Second I could set the initial response Content-Type to None.  If after
 calling the user-defined controller handler the Content-Type is set then
 use the new value.  Here's the relevant change to
 controller.py:_execute_func


 {{{
     old_content_type = cherrypy.response.headers["Content-Type"]
     cherrypy.response.headers["Content-Type"] = None
     output = errorhandling.try_call(func, *args, **kw)
     if cherrypy.response.headers["Content-Type"] is not None:
         content_type = cherrypy.response.headers["Content-Type"]
     else:
         content_type = old_content_type

 }}}

 I think of this as a hack.  If this is the right approach then I think
 TurboGears should set "server.default_content_type" to None (is that
 possible?) so CherryPy's response header starts off being None instead of
 "text/html".  Only after the controller handler is run should TG check the
 content-type and if it's still None then set it based on the various other
 settings.

 Or not.  Who gets to override whom?  Does the controller function override
 the @expose or vice versa?  In my case the @expose's content_type is None
 so it doesn't matter.

Comment:

 if you take this to the mailing list it may get more replies :)

-- 
Ticket URL: <http://trac.turbogears.org/turbogears/ticket/1071>
TurboGears <http://www.turbogears.org/>
TurboGears front-to-back web development
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"TurboGears Tickets" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/turbogears-tickets
-~----------~----~----~----~------~----~------~--~---

Reply via email to