tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From c...@munat.com
Subject Re: [Fwd: Re: Parameters disappear from PUTs]
Date Fri, 05 Feb 2010 19:45:09 GMT
Re PUT, a little research will show that this has been a hot topic for
several years now, at least since Elliotte Rusty Harold's controversial
"Why REST Failed" post in 2006.

RFC 2616 is quite clear on this topic, IMO.

The POST method is used "to request that the origin server accept the
*entity* enclosed in the request as a new ***subordinate*** of the
resource identified by the Request-URI in the Request-Line." (Emphasis
mine.)

In the context of a REST web service, this means that if I, for example,
wrap a new "Person" entity in a POST request and send it to:

example.com/persons

then this Person will be added as a subordinate of "persons" -- that is,
the URI identifies the group of persons to which this new Person will be
added. It does not identify a specific Person. The application will then
determine a URI to identify this newly created Person.

Note also that this transaction is neither safe nor idempotent, i.e., it
makes changes on the server for which the user (I) may be held
responsible, and multiple requests result have the side effect of creating
multiple identical Persons in the Persons group, each with a different URI
-- probably not what I intended.

In contrast, the PUT method "requests that the enclosed *entity* be stored
*under the supplied Request-URI*." (Emphasis mine, again. Note that both
POST and PUT are dealing with entities, but that while POST treats the
entity as a subordinate of whatever exists at the Request-URI, PUT
identifies the entity *directly* with the Request-URI.

So, presuming that I was using a GUID as an identifier, I might send my
Person object via PUT to:

example.com/persons/6cd79223-3585-4618-ab78-1c20db09c535

This will, if no Person already exists at that address, create a new
Person, associate it with that URI, and send a 201 "Created" response.

If a Person already exists at that address, the enclosed Person entity
replaces that Person, and a 200 "Sure, whatever" response is sent.

Note that this transaction is still unsafe, but now it is idempotent: I
can repeat the same request again and again, but I still end up with that
person at that URI.

Thus, my interest in PUT. First, you can't really, at least IMO, implement
REST without it. Second, as a functional programmer who likes immutability
and the absence of side effects, I find idempotency pretty irresistible.

While POST is acceptable for creating new entities (if you don't mind side
effects), it is just plain wrong for updating entities. That's what PUT is
for! But PUT also allows for creating new entities, so if the URI can be
determined by the client -- and GUIDs make this drop dead simple -- then
creates can be idempotent as well.

So my REST service works thusly:

GET    /persons              -> returns all persons, 200
PUT    /persons/<guid>       -> creates person <guid>, returns 201
PUT    /persons/<guid>       -> replaces person <guid>, returns 200
DELETE /persons/<guid>       -> deletes person <guid>, returns 204

And everything is idempotent.

Except it doesn't work at all if Tomcat strips my entity out of the PUT!

With regard to your initial argument re parameters in the header, note
that Section 9.6 says that the PUT method "requests that the enclosed
ENTITY be stored..." (emphasis mine).

A quick check at Section 7 shows that "[a]n entity consists of
entity-header fields and an entity-body, although some responses will only
include the entity-headers." This would be the same "Entity" to which
Section 9.5 on the POST method refers. Hence, Section 9.6 certainly makes
clear in its reference to an "entity" that it could be identical to that
sent via a POST method. Unless you can point to some text in the RFC that
explains that "entity" means something different when applied to PUT vs.
POST? Where exactly does it state or even imply that a PUT entity does not
include parameters in the header, while a POST entity does?

So for Tomcat to unilaterally strip the entity-headers from a PUT request
while passing only the optional entity-body seems just, well, wrong to me.

For this reason, I'm guessing it's a bug.

Chas.

> Hi.
>
> I'll forward your reply to the list, since apparently you did not.
> Let me just point out that I was only trying to help, and I do not
> believe that there were any grounds in my reply for the sarcastic tone
> used in yours.
>
> In the meantime, I did re-read both sections of the RFC 2616 (9.5 POST
> and 9.6 PUT), and I suggest that you do the same, with an open mind.
> I agree that neither one of them explicitly talks about "request
> parameters".  But this paragraph, to me, is rather explicit as to the
> difference in /meaning/ between a POST and a PUT :
>
> quote
> The fundamental difference between the POST and PUT requests is
> reflected in the different meaning of the Request-URI. The URI in a POST
> request identifies the resource that will handle the enclosed entity.
> That resource might be a data-accepting process, a gateway to some other
> protocol, or a separate entity that accepts annotations. In contrast,
> the URI in a PUT request identifies the entity enclosed with the request
> -- the user agent knows what URI is intended and the server MUST NOT
> attempt to apply the request to some other resource.
> unquote
>
> Personally, I interpret this as meaning that a PUT request is basically
> meant as a way to "upload" ONE resource to a server, in such a way that
> this resource would later be available (for example through a GET),
> using the same URI as the one used to upload it.
> On the other hand, the description of a POST request in section 9.5,
> quite explicitly indicates purposes such as updating database records
> and the like, which tends to imply the usage of "data fields" in the
> form of parameters.
>
> There is anyway enough leeway in these paragraphs, to justify the fact
> that the Tomcat developers may have been justified to not implement any
> handling of "parameters" for PUT requests; while developers of other
> servlet engines may have felt justified in providing such handling.
> The point I am trying to make is that if you create an application which
> depends on parameters being processed in a PUT request, you may well
> create an application which is not portable to all servlet engines or
> HTTP servers.  But that is of course your choice.
>
> All this triggers a question however : in an earlier post, you mention
> that the request works fine as a POST.  Why then do you insist to send
> it as a PUT ?
>
>
>
> -------- Original Message --------
> Subject: Re: Parameters disappear from PUTs
> Date: Thu, 4 Feb 2010 05:03:10 -0800
> From: chas@munat.com
> To: aw@ice-sa.com
> References: <2e9812dbea1d2cdeedb703759e39e602.squirrel@mail.munat.com>
>    <4B6AC1CC.5020502@ice-sa.com>
>
> By golly, you're right! Aren't you the clever one? I guess I should just
> use POST and give up on PUT.
>
> Whoops. But wait. I read section 9.5 of RFC 2616, and it doesn't "admit"
> parameters either. Well, if that isn't a bummer. I guess we'll just have
> to file a bug report and rip all that silly parameter stuff out of POST
> requests.
>
> Good thing you spotted that.
>
> Chas.
>
>
>> chas@munat.com wrote:
>>> I am submitting forms to a restful interface using an HTTP PUT with the
>>> params in the header of the PUT. I believe that's normal, and it works
>>> just fine on Jetty. The params are definitely sent.
>>>
>>> When I load my app into Tomcat 6 (Ubuntu), the form submission works
>>> perfectly if I use a POST: the params are definitely received. If I use
>>> a
>>> PUT, it works, but the parameters are missing -- not blank, but gone
>>> completely. I can also use a DELETE and that works (no params involved,
>>> of
>>> course), so it's not that PUT/DELETE are blocked.
>>>
>>> I've searched the docs, the wiki, and this list, but can't find
>>> anything
>>> about this. Is this expected behavior? Is there a setting somewhere? I
>>> found a setting in web.xml, but that appeared to refer only to SSI and
>>> was
>>> an all or nothing switch. Here, the PUT goes through and all the right
>>> methods are called, resulting in a row in the database. But the row is
>>> blank. (The only required field is the ID and that's passed in the
>>> URL.)
>>>
>>> I'm stumped. Anyone have any ideas?
>>>
>> Well, are you sure that a PUT request actually admits "parameters" ?
>> http://www.ietf.org/rfc/rfc2616.txt, section 9.6
>>
>> A PUT request requests that the attached entity (in the requst body) be
>> stored at the location indicated by the URI.
>> But I see no reference to parameters here.
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: users-help@tomcat.apache.org
>>
>>
>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>
>



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Mime
View raw message