Subject: RE: Status code for creating lock-null resource

From: "Clemm, Geoff" <[email-masked]>
Date: Wed, 27 Jun 2001 23:00:27 -0400

Dan has lots of good stuff in this message that I'll want to
follow-up on, but I first wanted to focus on one particular
comment:

   From: Dan Brotsky [mailto:[email-masked]]

   Geoff is suggesting something slightly different: that LOCK not
   even be allowed on unmapped-URIs.  This also gets rid of LNRs and
   has the advantage that you always know whether something is a
   collection or not.  However it doesn't allow users to
   simultaneously create and LOCK resources for further editing, which
   bothers me.

Could you expand on why this bothers you?  Since (I believe) this is
the only thing that you gain with "unmapped URI locks" (UULs,
previously known as LNRs :-), it is important to understand why (or
whether) this matters enough to warrant the kind of confusion and
complexity that UULs bring to the model.

Suppose UULs are supported.  If you issue a LOCK against an unmapped
URI, this may fail because someone already has a lock on that URI.  In
this case, you either need to wait until that lock is removed (at
which time, it is likely there is a resource mapped to that URI, but
maybe not), or you need to try again on a different URI.

Now suppose UULs are not supported.  You can't issue a LOCK against an
unmapped URI, so instead, you first create a resource *of the
appropriate type* and then try to LOCK that.  This LOCK request may
fail because someone already has a lock on that URI.  In this case,
you either need to wait until that lock is removed (at which time, it
is likely there is a resource mapped to that URI, but maybe not), or
you need to try again on a different URI.

Those two cases look very similar (in fact, I copied the text
of the first case into the second case, so they should look
*really* similar :-).  So what do you really gain with UULs?

Note: for compatibility with old 2518 servers, we shouldn't say that a
LOCK MUST fail on an unmapped URI, but we certainly could amend the
protocol to say that it SHOULD fail.  Since UULs act so differently on
current servers, this is probably the only thing we could say, if we
wanted to tell client writers how to achieve interoperability with
existing servers.

Cheers,
Geoff

---

From: Alan Kent <[email-masked]>
Date: Thu, 28 Jun 2001 15:56:06 +1000

> you need to try again on a different URI.

I am having trouble associating what I was going to say exactly with
the above, but its a bit of context...

I do not have a personal need for the following, but what about the case
where an application wants to create a temporary file with a new unique
file name. It does a 'LOCK' on a name. If it fails, it tries another
unique name. It keeps trying until it succeeds.

Without the current LOCK semantics, you would have to do a PUT to
create an empty file and then LOCK it. Does PUT have an OVERWRITE Y/N
flag? (I dont have the spec handy). If it always overwrites, then
there is the potential for a race condition.

Personally I would say tough luck. The above seems important in /tmp
or C:\temp etc, but not on a WebDAV file system. And there are lots of
potentials for race conditions in other parts of WebDAV arn't there?
(OK, so I don't actually know of any...) So why worry about one case
when it makes things so much more confusing overall?
WebDAV would be easier to implement if LOCK didn't have to create
these temporary amorphous resources that change their resource type
later (or even vanish complete).

Alan

ps: I like getting rid of the jargon "null resource", and like getting
rid of "lock-null" resources too *if possible*. Simplicity is a good
thing. If people are not implementing it correctly, there is probably
a good reason.

---

From: "Dan Brotsky" <[email-masked]>
Date: Thu, 28 Jun 2001 00:30:04 -0700

At 11:00 PM -0400 6/27/01, Clemm, Geoff wrote:
>Could you expand on why this bothers you?

There are actually three reasons:

1. Because it sets you up for ambiguity and race conditions by 
breaking a single user-conceptual operation (beginning to edit a new 
resource) into two protocol operations (PUT and LOCK).  A client that 
wants to create and edit a new resource will go through a 
conventional sequence such as HEAD (to verify the URL as unmapped), 
PUT (to create the resource), and LOCK (to reserve the resource for 
editing).  This conflicts not only with itself but with the 
conventional sequence for editing an existing resource is LOCK / GET 
(LOCK first to make sure the GET content is the latest content). 
This gives rise to two canonical problem cases:

a. If I'm creating and editing a new resource, and you are editing a 
resource but specify my name by mistake, then my client has to deal 
with the unexpected (and meaningless at the user level) case where I 
successfully create the resource but then can't edit it, and your 
client has to deal with the unexpected (and meaningless at the user 
level) case where you open a resource to edit it only to find that 
it's empty or doesn't contain anything like what I was expecting.

b. If we're both trying to create and edit the same (new) resource, 
and my PUT precedes yours but my LOCK follows yours, then once I've 
obtained the LOCK I find that the etag on the resource is different 
than the one I got back from my PUT.  This is the canonical 
client-side warning sign that I'm in a race with someone else, and I 
have to stop and make sure that I pull down the current content.  At 
that point, unless you and I were using the same "template" resource 
in our initial PUTs, I've got a real problem.  I either have to blow 
away your edit (which I'm not entitled to do under normal 
circumstances) or I need to give up my lock.  But by then your LOCK 
has failed, so you've figured out that someone else is creating the 
resource and you've given up.

(I have observed both of these scenarios in existing graphic arts 
workflows, by the way.  There are many workflow systems in use that 
have exactly this kind of problem.)

2. Because there's no well-defined way for PUT to reliably create a 
no-content resource, which is the kind I claim you want to be 
creating when you're creating a new one but don't have content for it 
yet.  Most servers given a PUT of 0 length create a 0-length 
resource, which is quite a different thing than a no-content one.

3. Because doing a PUT and then a LOCK and then (eventually) another 
PUT forces you to make *two* updates to the resource rather than one, 
and the controlling server may not actually want to authorize that. 
(For example, workflow servers often want to send things off for 
approval, etc., each time they are updated.)

>   Since (I believe) this is

Don't get me wrong: I am as opposed to UULs as I am to LNRs!

>unmapped URI,

My proposal is that you *can* do this, but the effect is that a 
no-content resource is created and bound to that URI.

>  so instead, you first create a resource *of the
>appropriate type* and then try to LOCK that.

The big differences between this proposal and yours seem to be:

1. The initial content of the resource (none) is fixed.

2. The resource can be made a collection via MKCOL.

3. There's no chance of race conditions.

>   This LOCK request may

See above.  I think we're very close.

>wanted to tell client writers how to achieve interoperability with

In my proposal, there is no incompatibility with existing servers, 
because the LNR they create is a no-content resource (or would be, if 
you were allowed to do a GET :^), and you can still issue a MKCOL.

So let me ask you the converse question: You seem to be worried by 
the fact that we don't know what kind of resource (collection or not) 
the new resource is going to be.  What's the problem with letting the 
new resource start out as a no-content non-collection and then be 
made into a collection?

Note that in both of our proposals the same requests are 
made---either a PUT or a MKCOL and a LOCK.  It's just that in my 
version the LOCK comes first (a la the LOCK / GET sequence that 
initiates an edit).  And in my version the client doesn't have to 
figure out whether the resource exists before initiating the 
sequence: all edits (of both existing and new resources) start out 
with a LOCK / GET, and in the case of the create the LOCK comes back 
with a 201 which tells the client that the GET would return a 204 
(and thus there's no reason to issue it).

     dan
-- 
Daniel Brotsky, Adobe Systems
tel 408-536-4150, pager 877-704-4062
2-way pager email: <mailto:[email-masked]>

---

From: "Lisa Dusseault" <[email-masked]>
Date: Thu, 28 Jun 2001 09:36:44 -0700

Alan wrote:
> What about the case
> file name. It does a 'LOCK' on a name. If it fails, it trinother

In a sense, PUT does have overwrite semantics.  You can use the
"If-None-Match: *" header to make sure that there are no entity tags at the
URL destination.  We might want to mention it so (a) servers know they must
support it and (b) clients know they can use it, and what for.  RFC2616 does
state it quite clearly though (section 14.26): "It is also used to prevent a
method (e.g. PUT) from inadvertently modifying an existing resource when the
client believes that the resource does not exist."

Let's assume the "If-None-Match: *" feature can reliably be used, though I'd
want to check that before setting anything in stone.  Can we just remove the
lock-null feature?  Some useful interactions would still be lost:
 - A client can be the creator of a file which they subsequently lose
control of.  This is because they would have to create the file with PUT
then set permissions, leaving a window where the file is unlocked and some
other user can set ACLs before the first user has a chance to prevent.
 - A client can PUT a file and then find themselves unable to LOCK it if
somebody else has locked it.  They can't create the body, change properties,
or delete it.  They may not be able to unlock it.  What kind of problems
might this present to a user interface client?
 - Similar scenarios with MKCOL.

So let's imagine we could transform lock-null resources into locked empty
resources -- the only requirement on the server would now be that the server
would allow the creation of an empty resource through use of the LOCK
request.  With a locked empty resource, it's a regular resource, it appears
in listings, and it doesn't magically go away if no PUT request is received
before UNLOCK.  Would this help us out?

A locked empty resource as I described would solve the PUT-control problem,
but not the MKCOL problem, unless the server were required to be able to
support MKCOL on a locked empty resource.  So if I have write and
permissions access to a repository where other users have write and
permissions access, I could create a directory called "lisa" - and there's a
risk that somebody else can change permissions before I have a chance to.
The malicious user could lock me out of my own directory.  On the other
hand, presumably the malicious user could create a directory called "lisa"
in the first place and not have to worry about waiting for me to create it.

Some servers will solve this problem by assigning special permissions to the
creator of a resource, however I don't think we can rely on this being
always the case. There are certainly use cases for other permissions models.
We would want to think about whether it's valid for a server to grant
permissions permission on newly created resources to principals that did not
either create the new resource, or own the parent resource.

lisa

---

From: "Lisa Dusseault" <[email-masked]>
Date: Thu, 28 Jun 2001 09:36:46 -0700

> than the one I got back from my PUT.  This is the canonical

I believe this can, and should, be solved with the consistent use of
"If-None-Match: *" in the PUT request, whenever a client is trying to create
a new resource.

> resource, which is quite a different thing than a no-content one.

Can you elaborate on how this is a different thing?  It might be just as
hard for servers to handle no-content resources (if they currently only
handle 0-length resources) as it is to support a lock-null resource.  At any
rate, I wouldn't support adding a completely new concept (no-content
resources) even if we did remove the lock-null concept.

lisa

---

From: "Eric Sedlar" <[email-masked]>
Date: Thu, 28 Jun 2001 11:07:33 -0700

I think the historical view that resulted in LNR's is as follows:

* There are valid scenarios where clients want to create a resource and
	lock atomically, or create a collection and lock atomically
* We can't handle this for regular resources since we can't change PUT,
	although we could solve this for MKCOL

My suggestion is built on Lisa's suggestion:

* Make LOCK create empty resources (with length 0) that are real resources
	if the URL is not mapped and a special header is specified
	(say Create: true, kind of like the O_CREAT flag on open() on Unix)

* Make MKCOL take a header specifying that a lock should be granted as
	well, like Lock: true

I've always had a viceral negative reaction to creating gratuitous empty
files, but on retrospect I think this comes from working on versioning
systems where this would create a useless version that the customer doesn't
want.  In this case, since a deltaV content creation client would probably
do:

* Open -->   LOCK / Create: true
* Save -->   PUT followed by VERSION-CONTROL followed by UNLOCK

so there is no problem of an extraneous version.

--Eric

---

From: "Dan Brotsky" <[email-masked]>
Date: Thu, 28 Jun 2001 11:36:07 -0700

>"If-None-Match: *" in the PUT request, whenever a client is trying to create

Good point.  (And thanks, I had completely missed this "idiom."  Like 
you, I wonder if servers are good about supporting it.)

But in the workflows I described, the user concept is not "intent to 
create" per se, it's "intent to edit, creating if necessary".  From a 
user point of view, I'm being asked to work on resource "foo," 
creating it if necessary.  I don't want to have to tell my client to 
do something different in the two cases.  I just want to tell it "I 
want to edit 'foo'; do the right thing."  Which, if we allow LOCK to 
create foo if necessary (as it does currently), is always done by the 
sequence LOCK / GET (but only if the GET is allowed to succeed on the 
LOCKED created resource).

I actually think (from your next message) that we agree about what 
should happen.  And I actually believe that LNRs can be changed 
fairly easily to be "empty" rather than "null" resources; all we have 
to do is remove the method response restrictions AND take away the 
"auto-delete" on UNLOCK behavior.

>Can you elaborate on how this is a different thing?

A no-content resource is one which returns 204.  (By the way, some 
servers do this for directory resources when "default docs" and 
"directory listings" are turned off.)  The response means "there's a 
resource here but it has no body (and thus no mime type).

A 0-length resource corresponds to a 0-length file in a file system; 
it has a MIME type but no octets.

No-content resources and 0-length resources both show up in listings 
and both respond to GET.

>   It might be just as
>handle 0-length resources) as it is to support a lock-null resource.

That's a good point.  But I'm not arguing against LNRs cause I think 
they're hard to implement :^).  I don't like their conceptual model, 
and I think we don't need to introduce them at all.

>   At any

No-content resources are not new; they're in HTTP 1.0 and 1.1.

     dan

---

From: "Dan Brotsky" <[email-masked]>
Date: Thu, 28 Jun 2001 12:58:21 -0700

At 9:36 AM -0700 6/28/01, Lisa Dusseault wrote:
><snip>

I claim yes.  That's exactly what I'm proposing, and where I think 
Tim and Jim got to in their discussion earlier on this thread.

>support MKCOL on a locked empty resource.

Which I think is reasonable, but I'm likely to be in the minority about this.

>   So if I have write and

I really don't think malicious users are the problem.  It's 
accidental collisions that are the problem: you want to make 
directory "lisa" because it's your name at the same time someone else 
wants to make file "lisa" because it's a picture of her niece Lisa. 
Accidental collisions are rare but a real pain if the underlying 
protocol allows races.

>either create the new resource, or own the parent resource.

It's valid for servers to do whatever is appropriate for the 
application.  This gets back to the other example I raised in my 
message: workflow servers typically want to attribute workflow intent 
to file operations, so two PUTS are quite different than one, and 
LOCK / PUT means something quite different than PUT / LOCK.

I think that, without requiring servers to support "placeholder" 
resources of some kind, it's going to be hard to avoid races around 
LOCKING and creation.  I think that's why LNRs were introduced in the 
first place.  I simply think that the notion of placeholder was too 
restrictive, and the notion of a "placeholder that vanishes" was just 
ill-conceived.  Since HTTP already supports the notion of 
"placeholders" well with no-content resources, I think we can simply 
say that LOCKing an unmapped URI puts a locked no-content resource 
there, and it stays there until someone either says "here's content" 
with PUT or "actually it's a collection" with MKCOL.  If they really 
made a mistake they can say DELETE.

     dan

---

From: "Lisa Dusseault" <[email-masked]>
Date: Fri, 29 Jun 2001 11:48:46 -0700

> I think we can simply

I'd point out that in many systems, DELETE privilege is separate from
create(write) privilege.  UserA, creating a resource in a folder "owned" by
UserB, may well end up creating a resource that UserA cannot delete (perhaps
UserB can).  Thus they can't necessarily do cleanup.

This is a problem with any write operation that doesn't turn out the way the
user expects so I'd be happy if that problem was not solved at all,
particularly through a special case "disappearing" resource.

lisa