Re: Indeterminate-length partial content messages

Austin William Wright <aaa@bzfx.net> Sat, 04 November 2023 00:58 UTC

Return-Path: <ietf-http-wg-request+bounce-httpbisa-archive-bis2juki=ietf.org@listhub.w3.org>
X-Original-To: ietfarch-httpbisa-archive-bis2Juki@ietfa.amsl.com
Delivered-To: ietfarch-httpbisa-archive-bis2Juki@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id E5729C09B5E8 for <ietfarch-httpbisa-archive-bis2Juki@ietfa.amsl.com>; Fri, 3 Nov 2023 17:58:05 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -3.456
X-Spam-Level:
X-Spam-Status: No, score=-3.456 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HEADER_FROM_DIFFERENT_DOMAINS=0.249, MAILING_LIST_MULTI=-1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_ZEN_BLOCKED_OPENDNS=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, URIBL_BLOCKED=0.001, URIBL_DBL_BLOCKED_OPENDNS=0.001, URIBL_ZEN_BLOCKED_OPENDNS=0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (1024-bit key) header.d=bzfx.net
Received: from mail.ietf.org ([50.223.129.194]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id dRx7aXSMgeBj for <ietfarch-httpbisa-archive-bis2Juki@ietfa.amsl.com>; Fri, 3 Nov 2023 17:58:01 -0700 (PDT)
Received: from lyra.w3.org (lyra.w3.org [128.30.52.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 388C0C09BB43 for <httpbisa-archive-bis2Juki@ietf.org>; Fri, 3 Nov 2023 17:58:00 -0700 (PDT)
Received: from lists by lyra.w3.org with local (Exim 4.94.2) (envelope-from <ietf-http-wg-request@listhub.w3.org>) id 1qz4wN-007uqW-TS for ietf-http-wg-dist@listhub.w3.org; Sat, 04 Nov 2023 00:55:07 +0000
Resent-Date: Sat, 04 Nov 2023 00:55:07 +0000
Resent-Message-Id: <E1qz4wN-007uqW-TS@lyra.w3.org>
Received: from titan.w3.org ([128.30.52.76]) by lyra.w3.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from <aaa@bzfx.net>) id 1qz4wM-007upQ-7H for ietf-http-wg@listhub.w3.org; Sat, 04 Nov 2023 00:55:06 +0000
Received: from mail-pj1-x1030.google.com ([2607:f8b0:4864:20::1030]) by titan.w3.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from <aaa@bzfx.net>) id 1qz4wI-007JlK-Ty for ietf-http-wg@w3.org; Sat, 04 Nov 2023 00:55:05 +0000
Received: by mail-pj1-x1030.google.com with SMTP id 98e67ed59e1d1-2809fb0027cso2319909a91.2 for <ietf-http-wg@w3.org>; Fri, 03 Nov 2023 17:55:02 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bzfx.net; s=google; t=1699059298; x=1699664098; darn=w3.org; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=pghvCf673mQPdRT4AtRw/99O5BTmVGJj7bEshP8O66Y=; b=4bbl/ccfhqaTZUjIqLa7LzpmVNpCZ0m8/mq2Ifb3gTv/Hboo6IYewgVK4i1bG1XeqH l/pQBCoPRF0MAe9le9n+4IlB8VTrzhjC0aL+qZ7QR+mBYGJ9KqXck8660RdJPN+inh6p 6SoBfgr0k7Hty8uwRaoe/+4nIIHXgRKYgHwWw=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699059298; x=1699664098; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=pghvCf673mQPdRT4AtRw/99O5BTmVGJj7bEshP8O66Y=; b=XK5E/oKJzYa2zCN+e0omufLj8B+4QKYQewmDe+pjg7SOA0Yj6YlR2Kj8AN1emRkaaq lt3hudctATsWu2aSZWHuJeBaW3oTfiW7vuV4T+jwIDDvDJ67ijlq7heRmPyMQ9TtS264 ytcNjoTNhDD6bduY+VpUDIVYqDwYqmb+Thirh3uBnmy7TxutRZGacHJNIk81/x3tDxDJ e8igjhhJvSyjtiCDdkXsXJMWRuLavLRjTUs5wlOwaNUGtKAfdUAphNPWNNpESo+ps6cD jKyyIbzn2fcK/DrCO4yGA/VIzt73IuB+MLfRQ0OhximCpL2+/u3Ac7YJw+DigF1wWles j6MQ==
X-Gm-Message-State: AOJu0Yx5oUT0JZsCcPDzP5YzIKPxtDVm0JzGd/1yOFZvvDPTZrIgcUNz 9LXs+cZClCPVcDHAiDBmQSKdysSUP9CAy0c7NMM=
X-Google-Smtp-Source: AGHT+IEiZKyqdlxv3FaQ39XAktnf/znqANXtsYjXE60dN+Qgm5yoLuEnO3KeF9oRFOPBklJWp5ygaw==
X-Received: by 2002:a17:90a:2dc3:b0:280:3911:adfe with SMTP id q3-20020a17090a2dc300b002803911adfemr14727294pjm.39.1699059298314; Fri, 03 Nov 2023 17:54:58 -0700 (PDT)
Received: from smtpclient.apple (71-223-144-201.phnx.qwest.net. [71.223.144.201]) by smtp.gmail.com with ESMTPSA id u8-20020a17090ae00800b002777001ee76sm1941371pjy.18.2023.11.03.17.54.57 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 03 Nov 2023 17:54:57 -0700 (PDT)
Content-Type: text/plain; charset="utf-8"
Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3696.120.41.1.4\))
From: Austin William Wright <aaa@bzfx.net>
In-Reply-To: <ZUSJuHPNdy/8MXXP@xps13>
Date: Fri, 03 Nov 2023 17:54:57 -0700
Cc: ietf-http-wg <ietf-http-wg@w3.org>
Content-Transfer-Encoding: quoted-printable
Message-Id: <7C7CA647-3FC6-4505-AC92-466D91188866@bzfx.net>
References: <24E33249-6BFD-4625-9AFB-621D91C4E4A8@bzfx.net> <ZUSJuHPNdy/8MXXP@xps13>
To: Glenn Strauss <gs-lists-ietf-http-wg@gluelogic.com>
X-Mailer: Apple Mail (2.3696.120.41.1.4)
Received-SPF: pass client-ip=2607:f8b0:4864:20::1030; envelope-from=aaa@bzfx.net; helo=mail-pj1-x1030.google.com
X-W3C-Hub-DKIM-Status: validation passed: (address=aaa@bzfx.net domain=bzfx.net), signature is good
X-W3C-Hub-Spam-Status: No, score=-6.1
X-W3C-Hub-Spam-Report: BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, W3C_AA=-1, W3C_DB=-1, W3C_IRA=-1, W3C_WL=-1
X-W3C-Scan-Sig: titan.w3.org 1qz4wI-007JlK-Ty a850276e2865dcfb5ca361ce41c6f101
X-Original-To: ietf-http-wg@w3.org
Subject: Re: Indeterminate-length partial content messages
Archived-At: <https://www.w3.org/mid/7C7CA647-3FC6-4505-AC92-466D91188866@bzfx.net>
Resent-From: ietf-http-wg@w3.org
X-Mailing-List: <ietf-http-wg@w3.org> archive/latest/51553
X-Loop: ietf-http-wg@w3.org
Resent-Sender: ietf-http-wg-request@w3.org
Precedence: list
List-Id: <ietf-http-wg.w3.org>
List-Help: <https://www.w3.org/email/>
List-Post: <mailto:ietf-http-wg@w3.org>
List-Unsubscribe: <mailto:ietf-http-wg-request@w3.org?subject=unsubscribe>


> On Nov 2, 2023, at 22:48, Glenn Strauss <gs-lists-ietf-http-wg@gluelogic.com> wrote:
> 
> On Thu, Nov 02, 2023 at 09:26:17PM -0700, Austin William Wright wrote:
>> Hello HTTP WG,
>> 
>> HTTP APIs recently adopted my “Byte Range Patch” draft, a media type to overwrite or append to a resource, especially when Partial PUT is not suitable (e.g. when server support is undetermined, or when the patch must be exchanged as a file). It re-uses standard HTTP fields including Content-Range, but notably this field doesn’t support ranges of indeterminate length, so there's no way to encode an indefinitely long write at a specific offset—you must know the length of the write when you begin the request.
>> 
>> Currently, as a workaround, the draft specifies a special case for the Content-Range syntax. Since workarounds like this are questionable, I’ll specify a different field name (perhaps "Content-Offset"). However, this brings its own problems: There would be a field that only functions in the body of these PATCH requests, and isn’t used in HTTP headers or any other context. While it's plausible for Byte Range PATCH to abandon the HTTP field design, I think it may be simpler on the whole to share semantics with Range requests and multipart messages. And further, standardizing partial content offsets would have greater utility, including in 206 Partial Content responses, and synchronization more broadly.
>> 
>> This problem was previously observed in streaming media, treated by the experimental RFC 8673 <https://www.rfc-editor.org/rfc/rfc8673.html> (HTTP Random Access and Live Content). This RFC suggests using a very large Range endpoint to request the server stream content as it becomes available. Then, it uses this large number in the response Content-Range to indicate that the response is of indeterminate length.
>> 
>> While this solution caters to the requirements of Range requests, it cannot be used for uploads, where no Range field is used. And if a client sends “Content-Range: bytes 100-999999999999” in a request, but ends the stream with less content than that, this should only be seen as an error, not as an understanding that the exact length was unknown. So I think a different, more general solution is warranted.
>> 
>> This would also serve as an important building block for synchronization over HTTP, since this could be used in Partial PUT <https://www.rfc-editor.org/rfc/rfc9110.html#name-partial-put> or a Byte Range PATCH <https://datatracker.ietf.org/doc/draft-ietf-httpapi-patch-byterange/> to append to shift buffers <https://www.rfc-editor.org/rfc/rfc8673.html#name-shift-buffer-representation>, and other “live resources” whose content is not entirely known at request-time, but may be streamed as it becomes available (as opposed to transferring only the data defined at the time of the request). Features that could build on top of this may include:
>> 
>> - Indicating support for indeterminate-length 206 (Partial Content) responses.
>> - Indicating preference for “stream live data” versus “snapshot-at-request-time” messages.
>> - Managing sparse resources, including shift buffers and more complicated synchronization (e.g. multiple clients uploading to the same resource in parallel).
>> - Optimizing caching for shift buffers (e.g. indicate that content may grow and/or become forgotten, but does not change once defined).
>> - Subscribing to changes to an underlying resource (in realtime or as desired).
>> 
>> The two most obvious ways to define this feature would be (1) to extend Content-Range to a form like “bytes 10-*/*” (where the star indicates exact value unknown), or (2) a new header like “Content-Offset: 10” (or what Resumable Uploads calls “Upload-Offset” <https://httpwg.org/http-extensions/draft-ietf-httpbis-resumable-upload.html#name-upload-offset>).
>> 
>> I would like to propose "Content-Offset = sf-integer”, since there's a certain symmetry to it (other HTTP fields that change when the message is of indeterminate length). Though, in cachable responses, modifying Content-Range may be desirable instead, depending on how origins want to non-implementing caches to act. While some amount of compatibility must be considered (especially caches), I feel this is a problem that will spawn domain-specific solutions over and over until there’s a general solution.
>> 
>> Please send me feedback on this proposal, I would especially like to hear from anyone with experience implementing HTTP Random Access and Live Content, or with any of the use cases I’m describing here. Then if this seems reasonable, I’d can draft an experimental I-D.
> 
> When uploading a live stream, it is inefficient to send one byte of data
> at a time.  A quantum of data is sent instead.  This could be 1 second
> of audio/video, or could be 5 or 15 or 30 seconds.  Portable CD players
> back in the 1990's would read some 30 seconds of data off the disc so
> that skips could be recovered before the listener noticed.  But I
> digress.
> 
> For a server that is storing an upload, writes to disk occur in
> blocks, minimum 512 bytes (POSIX) and often 4k or larger.  Even if
> storing in memory, memory is allocated from the OS to the process
> in blocks of memory page sizes, often 4k or larger.
> 
> Sending a chunk of data, preferably block-sized or larger, is
> recommended for efficiency.

Yes, there’s all sorts of ways that the application may prefer to packetize the data, which are all supported, whether you use the standard response, RFC 8673 “live content", or Content-Offset.

> Appending to the end of a file is a special-case of patching a file.
> After all, O_APPEND is a POSIX flag to open(2).

This is a good point. Append is a special case in the sense that it’s a write offset at the length of the file.

However, I haven’t yet treated the case where you don’t know the length of the resource, but you want to append to it. For resumable uploads and other synchronization use, this isn’t a problem (and actually desired, you don’t want to leave any gaps). But for other uses like writing to a log file, the client may not care where the end is or if it gets mixed with other appends.

In this case, perhaps there should be an alternate form, like “Content-Offset: *” (where star represents current length of resource, though unknown). This could be mapped to O_APPEND.

> => Why must an "indeterminate length" be transmitted in a range request?
> Why not send a sequence of append requests, in 1-sec-of-data increments?

Two reasons:

First, we already have the ability to make indeterminate-length uploads and downloads from the beginning of a resource; why should we lose this ability because we want to skip over a portion of it? And while determinate-length messages may suffice for archived content, it is not practical for live streaming applications. If the client and the server are in the same room, the latency will cause humans some serious problems. If you’re trying to align video or speakers with each other, just 30ms is one television video frame, or 10m of sound distance (frequencies above 15Hz, the entire audible spectrum, will fall out-of-phase). At one second, conference calls become a circus.

Now the server could relay the data as soon as it comes in, before the end of the message arrives—but then why break up the stream into multiple requests in the first place? Just continue using the first one. HTTP is already widely used for live streaming in this manner, with PUT and POST, but there is no standard way to write at an offset, you can only start a stream from the beginning.

Second, clients cannot distinguish “live content” messages from “static content" in most cases. An origin server reading an image on a filesystem, a gateway forwarding from an origin, and a server relaying a live video feed, do not require different capabilities of the client. In all three cases, the data comes through at a certain maximum rate, and the final length might not be known by the server until the end.

Yet, in all these cases, a client might want to restart the request at a certain offset—but if the server doesn’t know the final length of the resource, then this query may be impossible to answer. (Strictly speaking: the server doesn’t have to know the total length of the resource, but it does have to know where the response will end before it can even begin.)

That is to say: Resuming or breaking up requests should always be possible, but never required. In the absence of an actual error, this should be at the discretion of the client.

> Separately, another problem with "indeterminate length" is file range
> locking, which might prevent scenarios of multiple uploads of different
> ranges.  Another is resource allocation on the server, indeterminant
> versus guaranteed allocation of specific size (think posix_fallocate()).

Yes, this should be a consideration. I don’t think a locking mechanism needs to be defined at this time, but it's one of the uses that should be afforded.

> When designing a synchronization mechanism, why is HTTP the right layer
> to implement this, versus using HTTP as an opaque transport layer,
> similar to TCP or UDP?

Implementing such a feature without HTTP would mean defining your own application protocol for synchronization. Not always unwarranted (especially if performance is the reason), but usually redundant.

Implementing this on top of HTTP would mean that generic clients (user agents and intermediaries alike) cannot use this feature. Most notably, resources couldn't be cached.

Cheers,

Austin.

> 
> Cheers, Glenn