Skip to content

Content-Range chunk-upload header uses exclusive end byte (off-by-one) #28

Description

@dobby-coder

Problem

The chunked Cryptify upload emits Content-Range headers whose end byte is one past the last byte in the chunk:

https://github.com/encryption4all/postguard-dotnet/blob/main/src/Api/CryptifyClient.cs#L93

// In UploadAsync:
var end = offset + chunkLen;             // EXCLUSIVE end index
token = await StoreChunkAsync(uuid, token, sealedData, offset, end, ct);
offset = end;

// In StoreChunkAsync:
request.Content.Headers.Add("Content-Range", $"bytes {offset}-{end}/*");

For a first 1 MB chunk this emits Content-Range: bytes 0-1048576/*. Per RFC 9110 §14.4, range-end is inclusive, so the correct value is bytes 0-1048575/*. The current header overlaps the next chunk by one byte (1048576-…).

Whether this matters in practice depends on how the Cryptify server validates the header. If it currently lets it through, that's still relying on lenient parsing; a stricter server (or an HTTP proxy enforcing the spec) would reject it.

Suggested fix

Use the inclusive last byte index when emitting the header:

// In StoreChunkAsync, replace:
request.Content.Headers.Add(\"Content-Range\", $\"bytes {offset}-{end}/*\");
// with:
request.Content.Headers.Add(\"Content-Range\", $\"bytes {offset}-{end - 1}/*\");

(Or rename the parameter to make exclusivity explicit and compute end - 1 at the header.)

Before patching, please verify against the actual Cryptify server / upstream JS client — pg-fallback / postguard-js may emit the same off-by-one, in which case the server is permissive and a fix here is still spec-correct but harmless. If pg-fallback emits the inclusive form, this SDK is genuinely diverging from the wire protocol.

Filed for human review rather than auto-fix because the right fix depends on what Cryptify actually expects.

Files

  • src/Api/CryptifyClient.cs:39-46UploadAsync chunking loop
  • src/Api/CryptifyClient.cs:93Content-Range header

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions