Re: Resumable Uploads

Carsten Bormann <> Sun, 21 April 2013 11:25 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id B781F21F8E96 for <>; Sun, 21 Apr 2013 04:25:36 -0700 (PDT)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -8.93
X-Spam-Status: No, score=-8.93 tagged_above=-999 required=5 tests=[AWL=1.669, BAYES_00=-2.599, RCVD_IN_DNSWL_HI=-8]
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id CNXjpvla-hLm for <>; Sun, 21 Apr 2013 04:25:36 -0700 (PDT)
Received: from ( []) by (Postfix) with ESMTP id 1BAC821F8E04 for <>; Sun, 21 Apr 2013 04:25:35 -0700 (PDT)
Received: from lists by with local (Exim 4.72) (envelope-from <>) id 1UTsNW-0005Z7-SU for; Sun, 21 Apr 2013 11:24:18 +0000
Resent-Date: Sun, 21 Apr 2013 11:24:18 +0000
Resent-Message-Id: <>
Received: from ([]) by with esmtp (Exim 4.72) (envelope-from <>) id 1UTsNT-0005YO-9z for; Sun, 21 Apr 2013 11:24:15 +0000
Received: from ([] by with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.72) (envelope-from <>) id 1UTsNS-0007Hv-1d for; Sun, 21 Apr 2013 11:24:15 +0000
X-Virus-Scanned: amavisd-new at
Received: from ( []) by (8.14.4/8.14.4) with ESMTP id r3LBNeLV007588; Sun, 21 Apr 2013 13:23:40 +0200 (CEST)
Received: from [] ( []) (using TLSv1 with cipher AES128-SHA (128/128 bits)) (No client certificate requested) by (Postfix) with ESMTPSA id 40C3B39C1; Sun, 21 Apr 2013 13:23:40 +0200 (CEST)
Mime-Version: 1.0 (Mac OS X Mail 6.3 \(1503\))
Content-Type: text/plain; charset="iso-8859-1"
From: Carsten Bormann <>
In-Reply-To: <>
Date: Sun, 21 Apr 2013 13:23:39 +0200
Cc: Yoav Nir <>, Felix Geisendörfer <>, HTTP Working Group <>
Content-Transfer-Encoding: quoted-printable
Message-Id: <>
References: <> <> <> <> <>
To: Mark Nottingham <>
X-Mailer: Apple Mail (2.1503)
Received-SPF: none client-ip=;;
X-W3C-Hub-Spam-Status: No, score=-5.6
X-W3C-Hub-Spam-Report: AWL=-1.350, BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_PASS=-0.001
X-W3C-Scan-Sig: 1UTsNS-0007Hv-1d c76f082288f5fc2c08678dc1bc53910d
Subject: Re: Resumable Uploads
Archived-At: <>
X-Mailing-List: <> archive/latest/17447
Precedence: list
List-Id: <>
List-Help: <>
List-Post: <>
List-Unsubscribe: <>

On Apr 21, 2013, at 04:08, Mark Nottingham <> wrote:

> PUT /foo HTTP/1.1  # create the new resource
> PATCH /foo HTTP/1.1  # start uploading it...
> PATCH /foo HTTP/1.1  # continue...
> ...
> PATCH /foo HTTP/1.1
> Upload-Complete: 1  # we're done!

This is starting to look like draft-ietf-core-block, and is bound to have a number of the same characteristics (except that CoAP blocks are small and fixed-size).
(Of course, -block is solving a different problem...)

How to do this properly probably depends on whether the new resource is freestanding, is bound to be part of a collection, or is an update of an existing resource.

The first PUT may not really create the resource, it might create a temporary that can become the new representation of the resource.
The resource representation is only really completely uploaded with the final patch.

If access to the resource-in-creation is exclusive (e.g., a new URI that is only used by the uploader), the resource can grow in place.
If you don't want to indicate explicitly that it is done, the client can do that implicitly by just starting to use the URI.
Garbage collection (incompletely uploaded resources) is more fun, though.

If access is non-exclusive (multiple clients could be updating it in parallel), you can lock, or you can create an explicit temporary for each uploader, enabling "the last update wins".

Since the original project seems to be about uploading videos, exclusive access is probably the better paradigm.
We don't know if a PATCH (or even the initial PUT) is going to go through completely, so indicating at the start that it is the last one may be impossible.
An explicit close, conditional on the size actually received, may be the best way to do this.
This could use the LINK method or something else.

Grüße, Carsten