CoAP Blockwise Uploads with Multiple Clients: Prevent Transfer State from Being Mixed

Do not key an in-progress CoAP upload by URI alone. Preserve the endpoint and request properties that define the operation, and use Request-Tag where concurrent otherwise-matchable request bodies must remain distinct. Then enforce bounded state and an explicit policy for conflicting uploads.

This article covers stateful Block1 request-body assembly under RFC 7959 and Request-Tag under RFC 9175. It does not cover Block2 representation downloads or claim support in a particular library. Request-Tag separates operations; it does not authorize clients, guarantee storage commit, or resolve application-level conflicts over the final resource.

1. Identify what the server actually sees

Draw the path from each client to the blockwise server. Two direct clients may appear as different endpoints. Through a proxy, several upstream clients can become operations from one downstream endpoint. Record which hop terminates security, performs block assembly, or rewrites request options.

RFC 9175 defines matchability using the endpoint pair, request code, and relevant options. It then requires messages with different Request-Tag lists to remain separate operations. A server treats tags as opaque. See the Request-Tag processing rules.

Use the selected stack’s full matching implementation rather than inventing a shortcut containing only “client address plus tag.” URI, method, option semantics, and security context still matter. Conversely, a display name or user account label is not automatically the protocol endpoint identity.

Upload association uses request context and Request-Tag lists to choose separate bounded operation states before complete-body validation and commit policy.
Request-Tag separates blockwise operations. It does not grant access or resolve competing valid updates to one resource.

2. Keep operation identity separate from block progress

Each admitted operation needs an owner, immutable matching properties, a bounded representation limit, accepted byte ranges, inactivity/deadline state, and a terminal status. Block number and current offset are progress within that operation, not the whole identity of the operation.

Arrival Required distinction
Different endpoints, same URI and tag bytes. Do not collapse the operations merely because their tags match.
Same endpoint and otherwise-matchable requests, different tag lists. Keep separate operation state.
Same matching properties and a repeated block. Evaluate duplicate progress without creating another commit.
Same apparent operation but conflicting bytes for a retained range. Reject or fail the candidate under a documented policy.
New initial block while old state exists. Apply the stack’s restart/cancellation semantics; do not blindly append.

Matching tags are necessary in the applicable operation but not sufficient evidence that arbitrary blocks belong together. An absent Request-Tag and a present empty Request-Tag are also distinct states in RFC 9175. Preserve that distinction through parsing, wrappers, and proxy serialization.

3. Verify client tag lifetime

The client keeps the Request-Tag setting consistent across one operation. If a Block1 request is followed by a Block2 phase in the same operation, its tag continues there. Request-Tag belongs in request messages, not response messages. These are RFC 9175 section 3.4 requirements.

Do not infer that a changed Token begins a new upload body. Tokens correlate exchanges and have their own rules; Request-Tag identifies the blockwise operation. A stack can expose both fields through one transaction object, so inspect what its convenience upload API actually generates.

Tag recycling has a purpose-specific completion requirement. For the security model in RFC 9175 section 3.5.1, it depends on whether previously sent messages could still be accepted if replayed. An empty ACK or a short local timeout is insufficient proof. Use the library’s documented protected-transfer behavior and a reviewed security context, rather than inventing tag-reuse arithmetic.

4. Bound memory before admitting another body

Set limits for simultaneous operations per peer and globally, maximum body size, retained ranges, temporary storage, and inactivity. Include the resources consumed by rejected or unauthenticated traffic. Do not allocate a peer-supplied Size1 value without checking the product cap first.

RFC 9175 describes capacity responses such as delaying a new operation with 5.03 and Max-Age, or dropping older state so later blocks receive 4.08. Select a supported behavior and test it; adding Request-Tag does not require unlimited concurrency. Base Block1 transfer and incomplete-request behavior are defined in RFC 7959.

Keep incomplete bodies isolated from active configuration. After assembly, validate the representation and apply the resource’s authorization and conflict policy. Two individually correct uploads can still race to replace one resource. Choose whether the application serializes commits, uses a documented conditional update, or reports a conflict. The tag itself does not pick a winner.

5. Build a concurrent-upload fixture

Use two synthetic bodies with distinctive content in every block, and a controlled client/proxy harness. Keep a separate expected-body ledger. The following tests are proposed, not executed:

  1. Interleave two direct clients’ uploads to the same resource, including identical tag bytes, and verify no cross-client assembly.
  2. From one endpoint, interleave otherwise-matchable uploads with distinct Request-Tag lists; require two independent candidates.
  3. Repeat one block and verify it does not increase accepted length or cause a second commit.
  4. Send conflicting bytes for one range and require a visible failure instead of silent replacement.
  5. Exercise absent and present-empty tags through the actual parser and proxy path.
  6. Fill the configured operation limit, then start another upload; require the selected bounded response and intact existing state.
  7. Expire an upload, then deliver a late tail; require it cannot attach to a newer candidate.
  8. Complete two valid bodies concurrently and verify the application conflict policy independently of assembly correctness.

Record accepted ranges, operation-owner labels, response codes, final body hashes, and commit counts. A packet count alone cannot reveal a mixed-body defect.

Hypothetical proxy failure

Two service tools upload different configuration objects through one CoAP proxy. The downstream server indexes temporary storage only by URI. Interleaved blocks overwrite each other, producing a complete-length object assembled from both tools.

The corrected integration preserves the downstream operation distinctions and tests the proxy’s tag behavior. It also applies authorization at the intended endpoint. As CoAP’s request model makes clear, protocol messages carry requests to resources; application policy still determines what a valid request is allowed to change.

Release the upload path with a matching-key review, bounded-state policy, tag-lifetime evidence, and concurrent-body fixtures. Protecting individual blocks and identifying an operation are essential inputs to correctness, not a complete product-security claim.

Similar Posts