Skip to content

RESUMABLE: Redefine Upload-Complete on the server side#3404

Open
guoye-zhang wants to merge 15 commits into
httpwg:mainfrom
guoye-zhang:response-upload-complete
Open

RESUMABLE: Redefine Upload-Complete on the server side#3404
guoye-zhang wants to merge 15 commits into
httpwg:mainfrom
guoye-zhang:response-upload-complete

Conversation

@guoye-zhang
Copy link
Copy Markdown
Contributor

@guoye-zhang guoye-zhang commented Mar 26, 2026

Discussed during IETF125. Refining the Upload-Complete response header to differentiate the final response from the responses from the upload resource. Also allowing the final response to arrive early.

Resolves #3398

Comment thread draft-ietf-httpbis-resumable-upload.md Outdated
Copy link
Copy Markdown

@smatsson smatsson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea here but I think the PR needs a bit more to be fully understandable.

The biggest issue for me is that Upload-Complete: ?1 in a response no longer means what the name implies, that the upload is complete. It now means "Stop sending data, we are done here". I think that this change deserves more than a side note. A reader coming to this fresh will be confused.

It would definitely help to have some examples e.g. showing the early response case and what the client should do when it receives Upload-Complete: ?1 midway through the upload.

guoye-zhang and others added 2 commits May 1, 2026 18:07
Co-authored-by: Grant Gryczan <grantgryczan@gmail.com>
@guoye-zhang
Copy link
Copy Markdown
Contributor Author

@smatsson I updated one of the examples to show this in action. What do you think?

@smatsson
Copy link
Copy Markdown

smatsson commented May 4, 2026

@guoye-zhang Thanks for the update! Still not convinced of the wording.

The Upload-Complete response header field distinguishes the response from the initial targeted resource or the temporary upload resource. The value of true means the response is from the initial targeted resource, and the value of false means the response is from the temporary upload resource.

Why is this important to mention? It seems like an implementation detail to me. For an event based implementation (tusdotnet, tusd etc) the "teporary upload resource" could very well cause this case by user action in an event. Why not just simplify it and say that the server can cancel the entire upload by sending a response with Upload-Complete: ?1?

It would not hurt to add a sentence on what the expectations are from the client as well, given that this is what started the discussion in the other issue, e.g.

Upload-Complete: ?1 means that the request should not be retried regardless of what the response status code is.

@guoye-zhang
Copy link
Copy Markdown
Contributor Author

The reason I mentioned it is that we implemented resumable upload as a middleware. To the application at the top, it's just a regular upload and they don't need to be aware of the temporary upload resource at all. The responses with Upload-Complete: ?0 and Upload-Complete: ?1 are processed by different layers, so it's not just about ending the upload. Does that make sense? We could think of ways to clarify it more.

@smatsson
Copy link
Copy Markdown

smatsson commented May 8, 2026

@guoye-zhang Thanks for the clarification! While I understand that this makes sense for your specific middleware architecture, stating that the header "distinguishes the response from the initial targeted resource or the temporary upload resource" is completely irrelevant for other types of implementations.

Including this kind of implementation specific detail in the specification only creates confusion for anyone who hasn't built their server with the exact same architecture. We should just strictly define the protocol behavior over the wire and not add internal details about how different software layers process headers in a specific system.

It would be much clearer if the entire mention of "initial targeted" and "temporary upload" resources were just dropped. It's confusing because the draft already uses the terms "temporary resource" and "upload resource" to mean the URL returned in the Location header, see 3. Overview:

Resumable uploads are supported in HTTP through use of a temporary
resource, an upload resource (Section 4), that is separate from the
resource being uploaded to and specific to that upload. By
interacting with the upload resource, a client can retrieve the
current offset of the upload (Section 4.3), append to the upload
(Section 4.4), and cancel the upload (Section 4.5).

@GrantGryczan
Copy link
Copy Markdown
Contributor

GrantGryczan commented May 8, 2026

I want to clarify that the phrasing isn't about implementation details; it's about response semantics and isn't irrelevant depending on architecture. Let's suppose you create an upload using POST /files, and you interact with the upload resource using PATCH /uploads/1. If the upload is complete, the final successful response is considered to have come from /files, not /uploads/1. These different endpoints have different semantics. This is true for early complete responses too: if an upload append fails, the client needs to know if the failure response is coming from /uploads/1 or /files. If the latter, that means the entire upload has failed. Both resources may have entirely different semantics, so it needs to be distinguished which semantics we're working with given a response from the upload resource.

But I'm not arguing the phrasing is necessary, just adding this clarification about the intent behind it to inform your judgment. Personally, I am undecided on whether it's necessary. If we do keep it, it's probably a good idea to change the phrasing to make this clearer. Or alternatively, come up with different semantics that create the same effect.

@smatsson
Copy link
Copy Markdown

smatsson commented May 8, 2026

@GrantGryczan I completely understand the underlying use case here. The client needs to know whether an error occurred during the actual byte transfer (meaning they might be able to resume/retry) or during the final processing of the completed payload (meaning the transfer phase is over, but backend processing failed).

My issue is that the current phrasing in the draft is still unclear and messy. Trying to explain this by saying the response conceptually "comes from the initial targeted resource" rather than the "temporary upload resource" is an abstract and confusing way to describe it. Describing it this way leaks implementation details into the protocol, and as mentioned earlier, it also clashes with the terminology already established in Section 3.

Instead of describing which internal resource is supposedly answering, wouldn't it be much clearer to just describe what this means for the state of the upload?

Something along the lines of:

The Upload-Complete header indicates that the server considers the upload phase to be finalized. If Upload-Complete: ?1 is present on an error response, the client MUST NOT attempt to resume the upload, as the error originated from processing the completed payload rather than the transfer itself.

This achieves the exact same goal for the client but focuses on concrete protocol behavior rather than abstract backend architecture.

@GrantGryczan
Copy link
Copy Markdown
Contributor

GrantGryczan commented May 8, 2026

Again, this is completely independent from how it's implemented or any backend architecture. It's just about response semantics. It's saying:

  • If the initial request is a PUT request that results in the creation of a resource, then the Upload-Complete: ?1 response is required by RFC 9110 to use status 201, even though RFC 5789 doesn't specify any requirement for PATCH requests to respond with status 201.
  • If the initial request was to OPTIONS /whatever, then an Allow header included in the Upload-Complete: ?1 response specifies the allowed request methods for /whatever, not the upload resource.
  • If the initial request uses the Accept header, then the Upload-Complete: ?1 response ought to have a Content-Type that matches that media type, despite responding to a different request entirely.

These are just examples. The point is that all semantics that would otherwise apply to a response from the initial resource must also apply to an Upload-Complete: ?1 response from the upload resource.

To reiterate, this has nothing to do with backend architecture. In my backend implementation, I personally plan to implement the final complete response as coming from the same function that handles responses for the upload resource. There won't be any middleware or whatever. But the data that function generates for the response is still obliged to obey whatever semantics are defined for the initial resource.

Perhaps this is not the best way to communicate this effect, but my point is just that it's certainly not about implementation details. It's defining a contract that the interface must follow. Merely specifying whether the upload can be resumed or retried does not communicate the same contract.

@GrantGryczan
Copy link
Copy Markdown
Contributor

GrantGryczan commented May 10, 2026

Also, regarding @smatsson's initial feedback:

The biggest issue for me is that Upload-Complete: ?1 in a response no longer means what the name implies, that the upload is complete. It now means "Stop sending data, we are done here". I think that this change deserves more than a side note. A reader coming to this fresh will be confused.

This is a fair point. Would it be a good idea to rename Upload-Complete to more accurately reflect the concept it's trying to represent? Perhaps Upload-Done since an early-responded upload isn't "complete", but it is done (hence "we are done here")? Opinions needed.

@guoye-zhang
Copy link
Copy Markdown
Contributor Author

I thought about renaming it, ultimately concluded that keeping the same is the right decision for a few reasons:

  1. All the options are synonymous to "Upload-Complete", e.g. "Upload-Final", "Upload-Done", "Upload-Finished", "Upload-Ended". It would probably be more confusing if we renamed it to a synonym.
  2. Even though this change redefines the semantics of the header, most existing implementations already conform with little or no changes. It only affects servers that need to send early responses. Keeping the name avoids the churn.

@guoye-zhang
Copy link
Copy Markdown
Contributor Author

What about keeping both explanations? Saying that Upload-Complete: ?1 on the response means that the response is final and the client should not interact with the upload resource further.

@GrantGryczan
Copy link
Copy Markdown
Contributor

That could work, but I still think the phrasing of the current explanation needs refining.

@smatsson
Copy link
Copy Markdown

@GrantGryczan

The point is that all semantics that would otherwise apply to a response from the initial resource must also apply to an Upload-Complete: ?1 response from the upload resource.

I agree with this. My issue is just that the current phrasing in the draft doesn't actually say that. "distinguishes from the initial targeted resource" sounds like internal server routing, not HTTP semantics.

@guoye-zhang

Saying that Upload-Complete: ?1 on the response means that the response is final and the client should not interact with the upload resource further.

I think this is a good addition and I agree with you that the name should stay intact as the other names mean the same thing.

@guoye-zhang
Copy link
Copy Markdown
Contributor Author

What about now? @GrantGryczan @smatsson

@GrantGryczan
Copy link
Copy Markdown
Contributor

GrantGryczan commented May 12, 2026

This is better, but I think it still doesn't make much sense to say a response comes from the temporary upload resource. As I said in my previous review, if a client creates a resumable upload with Upload-Complete: ?0, then a server may respond with Upload-Complete: ?0, but the client doesn't know about the temporary upload resource before receiving that response, so saying it's "from" the temporary upload resource is incoherent to the client. Does that make sense?

Furthermore, I suspect Stefan's criticism still applies to the "distinguishes the response from the initial targeted resource or the temporary upload resource", "response is from", and "targeted resource decides to generate" phrasings. I think those should probably be replaced or removed entirely, because framing it in terms of which semantics apply is much less ambiguous. I'll defer to Stefan.

@guoye-zhang
Copy link
Copy Markdown
Contributor Author

I rephrased it by avoiding mentioning the upload resource

Comment thread draft-ietf-httpbis-resumable-upload.md Outdated

An upload is marked as completed if a request for creating the upload resource ({{upload-creation}}) or appending to it ({{upload-appending}}) included the `Upload-Complete` header field with a true value and the request content was fully processed.

The `Upload-Complete` response header field distinguishes the response from the initial targeted resource or the temporary upload resource. The value of true means the response is from the initial targeted resource, and the value of false means the response is from the temporary upload resource. It is worth noting that `Upload-Complete` can be true even when the full representation data was not received if the targeted resource decides to generate an early response.

This comment was marked as outdated.

Comment thread draft-ietf-httpbis-resumable-upload.md Outdated

An upload is marked as completed if a request for creating the upload resource ({{upload-creation}}) or appending to it ({{upload-appending}}) included the `Upload-Complete` header field with a true value and the request content was fully processed.

The `Upload-Complete` response header field distinguishes the response from the initial targeted resource or the temporary upload resource. The value of true means the response is from the initial targeted resource, and that the semantics of the targeted resource apply; the value of false means the response is from the temporary upload resource, and the semantics of the resumable upload protocol apply. It is worth noting that `Upload-Complete` can be true even when the full representation data was not received if the targeted resource decides to generate an early response. The client SHOULD NOT perform upload resumption to the upload resource after receiving a response with the `Upload-Complete` field value set to true.

This comment was marked as outdated.

Comment thread draft-ietf-httpbis-resumable-upload.md Outdated
@GrantGryczan
Copy link
Copy Markdown
Contributor

Nice work! I think this is great. Let's see what Stefan thinks.

Co-authored-by: Grant Gryczan <grantgryczan@gmail.com>
Comment thread draft-ietf-httpbis-resumable-upload.md Outdated
Comment thread draft-ietf-httpbis-resumable-upload.md Outdated

An upload is marked as completed if a request for creating the upload resource ({{upload-creation}}) or appending to it ({{upload-appending}}) included the `Upload-Complete` header field with a true value and the request content was fully processed.

The `Upload-Complete` response header field signals whether the response comes from the initial targeted resource. The value of true means that the semantics of the targeted resource apply, and the value of false means that the semantics of the resumable upload protocol apply. It is worth noting that `Upload-Complete` can be true even when the full representation data was not transmitted in the case that the server decides to generate an early response when processing the targeted resource. The client SHOULD NOT perform upload resumption to the upload resource after receiving a response with the `Upload-Complete` field value set to true.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we mention the possibility of an early response in the sections for PATCH and/or HEAD as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added Upload-Complete back as a SHOULD but realized that it was removed earlier in draft 10. Does the change make sense?

Comment thread draft-ietf-httpbis-resumable-upload.md Outdated
~~~

D) The following example shows an upload creation being rejected by the server because uploads to the targetted resource are not allowed. The client cannot continue the upload.
D) The following example shows an upload creation being rejected by the server because uploads to the targeted resource are not allowed. The Upload-Complete header in the response is set to true since the server is uninterested in receiving the full representation and the upload is complete in its perspective. The client cannot continue the upload.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unsure this is a good example for an early response. A 4XX response usually marks the end of an upload regardless of the presence of the Upload-Complete: ?1 header. IMO the value of early responses isn't visible in error responses, but actually successful responses. Could we have an example where the early response is 2XX because the targeted resource already received all the representation it needed to generate a response?

Copy link
Copy Markdown
Contributor

@GrantGryczan GrantGryczan May 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally think an early 2XX response in the wild would be extremely rare. Supporting error responses that interrupt an upload is probably going to be the most common use case for early responses, and there's no reason an example couldn't reflect that well. Though I agree this in particular is not the best example of that, since the error response here is the very first response, so in a sense, it's not really "interrupting" the upload, just preventing it from starting in the first place.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the most common cases for early responses are failures (401 unauthorized for example), and it's usually at the very beginning of the request. I think this example is fine for showcasing that Upload-Complete can be false in the request but true in the response. Or do we want an edge case example showing a particular pattern?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the most common cases for early responses are failures (401 unauthorized for example)

In my mental model, these authentication failures would be raised before an upload resource is even allocated. But this might be different depending on your implementation.

One example for an early error response that's slightly different is when a content-encoded representation (e.g. Content-Encoding: gzip) is uploaded and a decoding failure occurs. If the resource receives invalid gzip data at some point, it can decide to end the upload with an early response because it cannot recover the decoded representation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the example to corrupted gzip

Copy link
Copy Markdown
Contributor

@GrantGryczan GrantGryczan May 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, ideally, if the example is intended to demonstrate the significance of early responses, then the error should occur after the upload resource has been successfully created (even if that's less common), in response to an upload append.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a 104 to the example

Comment thread draft-ietf-httpbis-resumable-upload.md Outdated
Co-authored-by: Lucas Pardue <lucas@lucaspardue.com>
Comment thread draft-ietf-httpbis-resumable-upload.md Outdated
Comment thread draft-ietf-httpbis-resumable-upload.md Outdated
Copy link
Copy Markdown
Contributor

@LPardue LPardue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG thanks!

Comment thread draft-ietf-httpbis-resumable-upload.md Outdated
@smatsson
Copy link
Copy Markdown

@guoye-zhang Much clearer now, thanks! The update resolves my concerns.

guoye-zhang and others added 2 commits May 13, 2026 10:04
Co-authored-by: Grant Gryczan <grantgryczan@gmail.com>
~~~

D) The following example shows an upload creation being rejected by the server because uploads to the targetted resource are not allowed. The client cannot continue the upload.
D) The following example shows an upload creation being rejected by the server because the request content cannot be decoded. The Upload-Complete header in the response is set to true since the server is uninterested in receiving the full representation after the decoding failure and the upload is complete in its perspective. The client cannot continue the upload.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: fixed formatting.

Suggested change
D) The following example shows an upload creation being rejected by the server because the request content cannot be decoded. The Upload-Complete header in the response is set to true since the server is uninterested in receiving the full representation after the decoding failure and the upload is complete in its perspective. The client cannot continue the upload.
D) The following example shows an upload creation being rejected by the server because the request content cannot be decoded. The `Upload-Complete` header in the response is set to true since the server is uninterested in receiving the full representation after the decoding failure and the upload is complete in its perspective. The client cannot continue the upload.

@GrantGryczan
Copy link
Copy Markdown
Contributor

GrantGryczan commented May 14, 2026

Something seems off about these new semantics. I'm concerned about the error responses specified by the resumable upload protocol: mismatching offset, completed upload, and inconsistent length. If the upload was already completed, then what should Upload-Complete be set to for these responses?

  • If Upload-Complete: ?1, this change defines that the response comes from the initial targeted resource rather than following resumable upload semantics, which is not true. The initial targeted resource would have given a different response, so this value violates the new definition.
  • If Upload-Complete: ?0, that would be consistent with the new definition, since these errors do follow resumable upload semantics rather than the semantics of the initial targeted resource. But on the other hand, this value is misleading since the upload was completed. It could be argued that this misleading nature indicates a fundamental design flaw with doing early responses this way. But a client would discover the upload is already complete upon attempting upload resumption (via offset retrieval), so perhaps this is fine.
  • If Upload-Complete is absent, a generalized client will probably treat the response similarly to if it included Upload-Complete: ?0, so refer to the above. Arguably, this is less misleading since it doesn't look like an assertion that the upload is incomplete. But it also has the downside of behavior being less predictable here, and clients being uncertain how to handle this, going only off of heuristics. Ideally, a compliant client should handle these errors reliably.

If we decide one of these is best, I think it should be recommended explicitly in the draft. I would not be surprised if servers mistakenly choose a bad value here, since this situation is confusing.

We could also carve out an exception in the new definition to allow just these error responses to use Upload-Complete to signal the current completeness state, but that seems needlessly inconsistent and again arguably hints at a fundamental design flaw. The underlying inconsistency is that Upload-Complete is used for two different purposes: to communicate which response semantics apply, and to signal whether the upload has been completed. In most cases, these purposes are aligned, but sometimes, they are at odds.

Another example of this is offset retrieval responses, which use Upload-Complete strictly informatively rather than in a way that affects response semantics. The definition may need to cover this as an exception case too, unless we want to change our approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

RESUMABLE: Early response handling

5 participants