Re: Implementing HTTP PUT

On Wed, Mar 28, 2001 at 11:51:50PM -0800, Fish wrote:
> > -----Original Message-----
> > From: www-talk-request@w3.org [mailto:www-talk-request@w3.org]On Behalf
> > Of Aaron Swartz
> > Sent: Wednesday, March 28, 2001 1:59 PM
> > To: Fish; www-talk@w3.org
> > Subject: Re: Implementing HTTP PUT
> >
> >
> > Aha! This seems to be the problem. Using EricP's excellent patchPannel
> > (thanks to Gerald and dajobe), I find that Amaya is sending the following
> > request:
> >
> > PUT /testing HTTP/1.0
> > Accept: text/html
> > Accept-Encoding: *,deflate
> > TE: trailers,deflate
> > Expect: 100-continue
> 

If Amaya is putting HTTP/1.0 there it's because it already talked with
the server and found out it was an 1.0 one. If you use Amaya to publish
for the first time to your server, it will put HTTP/1.1. BTW, this is
coded in libwww and it's Henrik himself who made sure it was HTTP 
compliant. Amaya is just another application on top of libwww.

Now, if you send a header that the server doesn't understand, it should
just ignore it. That's what the spec says. The Expect: header here doesn't
do anything. Because the client may be talking to an HTTP/1.1 server, it
has a timeout for allowing to get the 100-Continue from the server. For
example the server could send a 30x redirect message instead of the
100-Continue. I'm not sure if once we're back to 1.0 if we still have
the timeout, though.

Missing in your example is the Content-Length and Content-Type. This
tells the server what kind of resource you're trying to create and its
length.

The server replies just tells you if it succeded in creating the resource
or not. We expect to have a 201 for the first time you create the 
resource. You could give back a 200 OK if it worked ok, or a 204.

The spec isn't very clear on what kind of headers you should return.
Most of the time, the return message can have a body too and the 
Content-Type and Content-Length describe this body. However, for a 204,
the spec precises that the headers can return information related
to the resource that was just created, such as it's Etag and Location.
However, it doesn't say anything bout whether it's possible to send a body
or not in the response. So, Jigsaw does send a small body and
the Content-Length and Content-Type describe that body.

For the 204, the spec does say no body should be returned. Jigsaw seems
to use in this case the Content-Length and Type of the resource that
was saved. As there's no body, why not do it? The spec doesn't say if it's
ok or not, but it should be clearer, IMO.

A final remark... in Amaya, we use the HTTP preconditional headers together
with ETAGS. This is to allow detecting multiple concurrent PUTS to the same
resource. If you're not planning to support these features yourself, you
should go to the Preferences/Publishing menu and turn off the Conditional
support entry.

To help you debug, you can tell libwww to make a log its transactions. See
it as a kind of libwww in-built PatchPanel. To activate it, go to your
.amaya directory (or wherever you're storing your Amaya preferences), 
and open the thot.rc file. There should be an entry saying:

  ENABLE_LIBWWW_DEBUG=

Change it to read:

  ENABLE_LIBWWW_DEBUG=99

This will generate a file called w3chttp.out _someplace_ in your work space,
(probably in the same one where you're launching Amaya) and will continue
the log of the transaction. A libwww.log file will also be created
under .amaya/. This is an undocumented features of Amaya because we
can't control yet where the logs are generated. We mostly use them for
debugging. Remember to turn it off as the log files aren't erased
automatically, but keep accumulating stuff.

Basically, for an HTTP/1.0 server, you have the following transaction:

===
Request:
====
PUT <URL-of-resource> HTTP/1.0
Content-Type: <your type>
Content-Lenght: <length of resource>
<Any number of other header>

<body of the request (the resource>

===
Reply:
===
HTTP/1.0 <code> <some text>

The code may be a 201, a 204, a 30x, a 40x, ... Under HTTP/1.0, you
shouldn't send back a 100 Continue.

I'm enclosing a complete transaction log here after. My comments on what's
happening are prefixed with a @@. My trimming is shown with ... Hope 
it helps you.

You can find more info about the lost update problems and the use
of conditional requests in the following W3C note:

=========================
Editing the Web
Detecting the Lost Update Problem Using Unreserved Checkout
W3C Note May 10 1999
http://www.w3.org/1999/04/Editing/
============================

-jose

=============================================================

@@ Precondition testing... does the resource exist?

HEAD /Amaya/Tests/jose-test5.html HTTP/1.1
Accept: text/html
Accept-Encoding: *,deflate
TE: trailers,deflate
Host: www.w3.org
User-Agent: amaya/V4.3.2 libwww/5.3.1
Connection: TE,Keep-Alive

@@ No

HTTP/1.1 404 Not Found
Date: Thu, 29 Mar 2001 10:51:59 GMT
Server: Apache/1.3.6 (Unix) PHP/3.0.15
Opt: "http://www.w3.org/2000/P3Pv1";ns=11
11-PolicyRef: /2000/06/P3P/p3p_www.xml
Keep-Alive: timeout=15
Connection: Keep-Alive
Content-Type: text/html
X-Pad: avoid browser bug

@@ Ok, let's save it

PUT /Amaya/Tests/jose-test5.html HTTP/1.1
Accept: */*
Accept-Encoding: *,deflate
TE: trailers,deflate
Expect: 100-continue
Host: www.w3.org
If-None-Match: *
User-Agent: amaya/V4.3.2 libwww/5.3.1
Cache-Control: no-cache
Connection: TE
Date: Thu, 29 Mar 2001 10:50:23 GMT
Allow: PUT
Content-Length: 7210
Content-Type: text/html;charset=iso-8859-1
Last-Modified: Thu, 29 Mar 2001 10:50:23 GMT

<!-- a comment -->
<?xml version="1.0" encoding="iso-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
...

@@ Sorry, you cannot save directly to the W3 server, you have to
@@ use the Jigsaw one (handled automatically on Amaya, no user interaction).
@@ Note that we didn't @@ get the 100 Continue, but the 302 right away...
@@ more efficient.  @@ Also note the use of chunks.

HTTP/1.1 302 Found
Date: Thu, 29 Mar 2001 10:51:59 GMT
Server: Apache/1.3.6 (Unix) PHP/3.0.15
Location: http://jigsaw.w3.org/Amaya/Tests/jose-test5.html
Transfer-Encoding: chunked
Content-Type: text/html

e5 
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>302 Found</TITLE>
</HEAD><BODY>
<H1>Found</H1>
The document has moved <A HREF="http://jigsaw.w3.org/Amaya/Tests/jose-test5.html">here</A>.<P>
</BODY></HTML>

0

@@ Ok, let's save it there then
PUT /Amaya/Tests/jose-test5.html HTTP/1.1
Accept: */*
Accept-Encoding: *,deflate
TE: trailers,deflate
Expect: 100-continue
Host: jigsaw.w3.org
If-None-Match: *
User-Agent: amaya/V4.3.2 libwww/5.3.1
Cache-Control: no-cache
Connection: Keep-Alive,TE
Date: Thu, 29 Mar 2001 10:50:25 GMT
Allow: PUT
Content-Length: 7210
Content-Type: text/html;charset=iso-8859-1
Last-Modified: Thu, 29 Mar 2001 10:50:23 GMT

@@ But we forgot we need authorization! We need to ask the client
@@ to authenticate first

HTTP/1.1 401 Unauthorized
Date: Thu, 29 Mar 2001 10:50:39 GMT
Content-Length: 269
Content-Type: text/html
Server: Jigsaw/2.1.0
WWW-Authenticate: Digest ** some auth info **

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
                      "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML><HEAD>
<TITLE>Unauthorized</TITLE>
</HEAD>
<BODY><h1>Unauthorized access</h1><p>You are denied access to this resource.</BODY>
</HTML

@@ Here it is again

PUT /Amaya/Tests/jose-test5.html HTTP/1.1
Accept: */*
Accept-Encoding: *,deflate
TE: trailers,deflate
Authorization: Digest *encoded password*
Expect: 100-continue
Host: jigsaw.w3.org
If-None-Match: *
User-Agent: amaya/V4.3.2 libwww/5.3.1
Cache-Control: no-cache
Connection: Keep-Alive,TE
Date: Thu, 29 Mar 2001 10:50:26 GMT
Allow: PUT
Content-Length: 7210
Content-Type: text/html;charset=iso-8859-1
Last-Modified: Thu, 29 Mar 2001 10:50:23 GMT

@@ All looks ok, go ahead

HTTP/1.1 100 Continue
Date: Thu, 08 Mar 2001 17:06:25 GMT
Server: Jigsaw/2.1.0

@@ The body

<!-- a comment -->
<?xml version="1.0" encoding="iso-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <title>Amaya - Bienvenue</title>
  <style type="text/css">
 body {font-family: helvetica, arial, sans-serif; color: black; background-color: #C0C0C0}
....

@@ Server creates the resource and returns its etag. The Content-Type
@@ and Content-Lenght relate to the body of the resource

HTTP/1.1 201 Created
Date: Thu, 29 Mar 2001 10:50:46 GMT
Content-Length: 31
Content-Type: text/html
Etag: "l5bl6r:sm508fs8"
Server: Jigsaw/2.1.0

<P>Resource succesfully created

@@ I'll now save it again... just showing the final PUT and reply
@@ NOtice we use the previous etag in the If-Match conditional header.

PUT /Amaya/Tests/jose-test5.html HTTP/1.1
Accept: text/html
Accept-Encoding: *,deflate
TE: trailers,deflate
Authorization: Digest *encoded password*
Expect: 100-continue
Host: jigsaw.w3.org
If-Match: "l5bl6r:sm508fs8"
User-Agent: amaya/V4.3.2 libwww/5.3.1
Cache-Control: no-cache
Connection: TE
Date: Thu, 29 Mar 2001 11:15:57 GMT
Allow: PUT
Content-Length: 7242
Content-Type: text/html;charset=iso-8859-1
Last-Modified: Thu, 29 Mar 2001 11:15:57 GMT

HTTP/1.1 100 Continue
Date: Thu, 08 Mar 2001 17:06:25 GMT
Server: Jigsaw/2.1.0

<?xml version="1.0" encoding="iso-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <meta content="text/html; charset=iso...

@@ Done... C-Length and type are those of the saved resource
@@ We get a new etag

HTTP/1.1 204 No Content
Date: Thu, 29 Mar 2001 11:16:14 GMT
Content-Length: 7242
Content-Type: text/html
Etag: "l5bl6r:sm51n330"
Last-Modified: Thu, 29 Mar 2001 11:16:12 GMT
Server: Jigsaw/2.1.0

Received on Thursday, 29 March 2001 06:21:33 UTC