On Fri, Jul 31, 2009 at 2:33 PM, Jeff Hammel<[email protected]> wrote:
>
> On Fri, Jul 31, 2009 at 01:01:21PM -0500, Olemis Lang wrote:
>>
>> Is there any helper function in Trac I can use to clone an HTTP
>> Request object (i.e. instances of trac.web.api.Request) ?
>>
>> I already have a «real» request object provided by Trac and what I
>> really need is to obtain a Request object identical to that one, in
>> order to modify it later on.
>
> Hah!  I had need of this very thing recently.  I ended up just making a 
> generic object and then setting the attrs I needed from the real request, but 
> admittedly its a cheap hack and I'd much prefer a better solution.  You can 
> see what I did here:
>
> http://trac-hacks.org/browser/sharedcookieauthplugin/0.11/sharedcookieauth/sharedcookieauth.py#L22
>

Hi Jeff ! Thnx for the pointer. However I need more than that. I
really need a completely identical request, which includes «lazy»
attributes using callbacks, and so on.

I discarded the idea of using clones and I came up with a solution
based on Proxy objects (GoF pattern , yes I'm still a puritan ...),
since I realized (the third bottle of Vodka is the good one ...) that
what I really needed was to intercept and «override» the access to
attributes of the request object.

The basic intercept object looks like this :

{{{
#!python

class ObjectIntercept:
  def __init__(self, obj, basecls):
    self._target = obj
    self._basecls = basecls
  def __getattr__(self, attrnm):
    val = getattr(self._target, attrnm)
    if isinstance(val, types.MethodType) and val.im_class is self._basecls:
      val = val.im_func.__get__(self, self.__class__)
      setattr(self, attrnm, val)
    return val
}}}

The next step was to implement a wrapper used to redirect the request
so that it could be processed by another IRequestHandler.

{{{
class RedirectIntercept(ObjectIntercept):
  def __init__(self, reqi, env, **params):
    super(RedirectIntercept, self).__init__(reqi, Request)
    self.__params = params
    self.__env = env
  def redirect(self, url, permanent=False):
    uobj = urlparse(url)
    self.path_info = uobj.path
    self.args = parse_qs(uobj.query)
    self.args.update(self.__params)

    # Needed because Trac built-in protection against CSRF attacks
    self.args['__FORM_TOKEN'] = self._target.args.get('__FORM_TOKEN')
    try:
      RequestDispatcher(self.__env).dispatch(self)
    except (RequestDone, TracError):
      raise
    except Exception, exc:
      raise TracError("Error %s : %s" % (exc.__class__.__name__, \
                                          exc.message))

# Return the contents provided by a different IRequestHandler
reqi = RedirectIntercept(req, env)
reqi.redirect('/path/to/new/request/handler?x=1')
}}}

This way I was able to simulate HTTP redirection without sending an
HTTP response. This is just the first part because what I really
needed was to perform such redirection and save the body of the HTTP
response using an StringIO stream. To do that I just needed to do the
following :

{{{
#!python

class IoIntercept(ObjectIntercept):
  def __init__(self, reqi, strm):
    super(IoIntercept, self).__init__(reqi, Request)
    self.__strm = strm
  def _start_response(self, status, headers):
    if status.lower() != '200 ok':
      self.raise_status_failed(status)
    return self.__strm.write
  def send_header(self, name, value):
    pass
  def raise_status_failed(self, code):
    raise TracError('Request failed with status %s' % (code,))

}}}

I solved my problem this way :

{{{
#!python

def save_response(...):
      strm = StringIO()
      try:
        reqi = IoIntercept(req, strm)
        reqi = RedirectIntercept(reqi, self.env, **params)
        try:
          reqi.redirect(path)
        except RequestDone:
          pass
        return strm.getvalue()
      except TracError:
        raise
      except Exception, exc:
        raise TracError("Error %s : %s" % (exc.__class__.__name__, \
                            exc.message))
      finally:
        strm.close()

}}}

and it works !

PS: I send the full code in here because my svn client doesnt work yet :-/

-- 
Regards,

Olemis.

Blog ES: http://simelo-es.blogspot.com/
Blog EN: http://simelo-en.blogspot.com/

Featured article:

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Trac 
Users" 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/trac-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to