[Grok-dev] Re: HTTP PUT and HTTP DELETE security support

Philipp von Weitershausen philipp at weitershausen.de
Wed May 23 06:07:58 EDT 2007


Martijn Faassen wrote:
> Hey Philipp,
> 
> Thanks for the feedback!
> 
> Before I go into your reply, I must remark that there's another issue 
> surrounding this I just found out I need your guidance on: our Grok 
> traversers don't work in the case of PUT, because they're registered for 
> IBrowserRequest. Changing them to work for IHTTPRequest fixes this in my 
> case, but can you think of any problems with that?

Well, traversers are also responsible for looking up views in case 
object graph traversal (e.g. container[subitem]) doesn't yield anything. 
This looking up views is different in the HTTP-only world than in the 
browser world.

> Philipp von Weitershausen wrote:
>> Martijn Faassen wrote:
> [snip]
>> [snip discussion of various approaches to implementing a PUT view]
>>
>> I would suggest introducing a grok.REST class:
>>
>>   class MammothREST(grok.REST):
>>
>>       def PUT(self):
>>           pass
>>
>>       def DELETE(self):
>>           pass
>>
>>       def ANY_HTTP_VERB(self):
>>           pass
> 
> Doing this makes it harder to have one bit of code that adds PUT to an 
> object, and another bit of code that adds DELETE. I don't think this is 
> a problem though - something that's going to support PUT probably should 
> support DELETE right along anyway.

Yes. Also, it's not said that you couldn't override DELETE. You would 
just implement a new grok.REST subclass with just a DELETE method:

   class NewMammothREST(grok.REST):

       def DELETE(self):
           # new implementation of DELETE, the rest from the old
           # implementation stays

How's that possible? Because each HTTP verb handler is its own adapter. 
So that grok.REST subclass would be registered once for each verb method 
that it implements.

>> Naturally, we'll have to come up with a decent interpretation of the 
>> GET/POST case. By default, GET/POST are interpreted as browser 
>> requests and the browser publication looks up a default view ('index') 
>> when your GETting or POSTing to a resource (/herd/manfred ends up 
>> really being /herd/manfred/index). Perhaps if there's no such 'index' 
>> view, Grok's browser publication will fall back to the REST adapter 
>> and lookup the "GET" view (or "POST view, respectively):
> 
> Actually both PUT and POST are supposed to return something as well. 
> While POST will likely do something special, PUT, as far as I understand 
> is, actually is defined to return whatever GET would return. This means 
> you'd like an index view to be there that PUT falls back on when it's 
> done PUTting.

Ok.

> The alternative would be to say that people should just implement a GET 
> method in this case.
> 
>>   class Herd(grok.Container):
>>       pass
>>
>>   class HerdREST(grok.REST):
>>
>>       def POST(self, item_name, name='Manfred'):
>>           self.context[item_name] = mammoth = Mammoth(name)
>>           self.redirect(self.url(mammoth))
>>
>> We could also do it the other way around, like you suggest, and look 
>> for the REST handlers for GET/POST first, before falling back to 
>> 'index' browser pages.
> 
> Let's summarize this idea as it stands now:
> 
> GET - use REST handler, otherwise fall back on index view
> POST - use REST handler, otherwise fall back on index view
> PUT - use REST handler, for results then run normal index view (as with GET)

Unless the PUT method returns something other that None. In that case 
that return value is returned to the client.

> DELETE - use REST handler. Need to research what result is expected, but 
> I think that's a special HTTP status.

Sounds good otherwise. We could also think about a default fallback. 
Let's say I want my POST handler to become active only in a certain 
case, otherwise I want to fall back on the index view. We could indicate 
this by returning None or non-None:

   class MammothREST(grok.REST):

       def POST(self, body=''):
           if body:
               self.context.body = body
               return something_thats_not_None # or redirect
           return None  # not necessary

So, if body is missing from the request or empty, this method will 
return None and the publication will proceed to the index view.


By the way, I've been wondering... grok.JSON, grok.XMLRPC, grok.REST are 
all views. grok.View is a browser page and also a view. Perhaps it 
should be grok.Page or even grok.BrowserPage instead of grok.View, just 
for the symmetry of things?

>>> It will take a bit of work to make this happen though, as I don't 
>>> think the zope 3 publisher supports doing this out of the box.
>>
>> The Zope 3 publisher supports everything out-of-the-box :). That is to 
>> say that the actual policy is in the publication (what happens when, 
>> which views to look up, etc.).
> 
> Okay, I should say the Zope 3 publication doesn't support this out of 
> the box. After a few years of bashing my head against that code I'm 
> finally getting some idea of how it works, but I'm sure I'll forget it 
> again soon. :)

*grin*

For my training I drew neat little pictures that I'll try to include in 
a future edition of the book.

>>> Comments? Ideas? Eager Zope 3 publisher hackers volunteering to start 
>>> building this? :)
>>
>> I've long been wanting to build a saner publication than 
>> zope.app.publication. With as many modifications as we're planning, it 
>> might make sense to start from scratch...
> 
> I'm motivated by a Real World Project (tm) so this will have to have 
> somebody else driving it. I am hoping I can start making what we've 
> sketched out here work (one way or another) in the Grok core next week. 
> If you think we can write a new publication machinery in a few days then 
> I'd be happy to help.

I might be able to round up some time next week.

>> Btw, I suppose we've now settled on the idea of making Grok explicitly 
>> *not* compatible with traditional Zope 3 browser pages defined via 
>> <browser:page />, right?
> 
> What do you mean by not compatible? I think it should remain possible to 
> add a traditional <browser:page>  to a Grok model. That's our "mutual 
> compatibility principle". Would there be a benefit towards breaking such 
> compatibility?

I thought we wanted to rid ourselves from the Zope 3-induced "ZMI" 
views? Perhaps I misunderstood. I agree that the Mutual compatibility 
principle is a good thing.


-- 
http://worldcookery.com -- Professional Zope documentation and training


More information about the Grok-dev mailing list