Prompt and context
This backend question tests HTTP partial responses, object-store reads, and a download state machine. The challenge is not forwarding a header to storage; it is keeping ranges, entity versions, encodings, permissions, and concurrent segments consistent through failure and retry.
What the interviewer evaluates
- Whether you parse one byte range and construct 206, Content-Range, Content-Length, and Accept-Ranges correctly.
- Whether ETag or Last-Modified with If-Range prevents a client from joining different file versions.
- Whether invalid ranges, expired signatures, deleted objects, rate limits, and multi-range cost are handled.
- Whether integrity, observability, and authorization prevent the endpoint from becoming an arbitrary object reader.
Clarifying questions to ask
Confirm whether objects are public, the maximum size, whether multi-range responses are required, whether storage supports native ranges, whether compression is allowed, and whether the client persists ETags. Ask about URL lifetime, segment concurrency, the integrity algorithm, and product behavior when the resource version changes.
30-second answer framework
I would authorize the request and pin an object version, then read size, ETag, and media metadata. No Range returns 200; one satisfiable range returns 206 with an exact Content-Range; malformed or unsatisfiable ranges return 416 with the current length. If-Range mismatch causes a full response for the current version so the client restarts. Each segment is rate- and concurrency-limited, and both the response and final file are checked against the version and checksum.
Step-by-step deep dive
1. Pin the representation and authorization boundary
Authorize by user, tenant, and object id; never map an arbitrary client path directly to a storage key. Read object metadata and pin a version identifier, total bytes, Content-Type, Content-Encoding, and ETag. If objects change, use immutable or versioned storage so metadata and bytes cannot drift during one download.
2. Parse ranges and construct responses
Support one bytes=start-end, bytes=start-, or bytes=-suffix range, validating integers, overflow, and total length. After clamping a satisfiable range to the representation, return 206, Content-Range, and the exact length. Without Range return 200. If no range is satisfiable, return 416 with Content-Range: bytes */total. Multi-range requests need an explicit choice: reject, split into bounded requests, or implement multipart; never silently return the first part.
3. Handle If-Range and content coding
Honor a strong ETag or date in If-Range only when it still matches the selected representation; otherwise ignore Range and send the full current representation. Ranges refer to bytes of the representation actually transferred. Do not slice compressed bytes and ask a client to join them as if they were an uncompressed file. Either disable dynamic compression or give each encoding an independent version and checksum.
4. Bound concurrency, cost, and recovery
Limit segments per user, tenant, and object, plus total bandwidth and minimum range size, to prevent many tiny requests from amplifying storage cost. Retry a failed segment only with the same version and range. If a signed URL expires, issue a new one without changing the version. Object deletion or permission changes stop later segments, and the client discards an incomplete file instead of silently joining it.
5. Verify integrity and observe behavior
After download, verify object version, total length, and checksum; for high-risk data, verify each segment before joining. Log normalized ranges, version, status, bytes, storage latency, cache hit, and retry count without logging download credentials. Test empty ranges, suffixes, overflows, object updates, concurrent retries, offline resume, and each Content-Encoding to prove that 206 never serves the wrong version.
Strong sample answer
After authorization I pin an immutable object version and expose its size, ETag, type, and encoding. A satisfiable single bytes range returns 206 with Content-Range and Content-Length; no range returns 200; an unsatisfiable one returns 416 with bytes */total. If-Range mismatch ignores Range and sends the full current version, preventing mixed files. Per-user and per-object concurrency, rate, and minimum-range limits contain cost, and retries keep the same version. The client verifies length, version, and checksum; the server observes ranges, status, storage latency, and retries.
Common mistakes
- Forwarding Range without checking authorization, object version, or integer overflow.
- Returning 200 or an empty body for an unsatisfiable range instead of 416.
- Ignoring If-Range and letting an update create a mixed-version file.
- Applying range coordinates to compressed bytes that the client later treats as uncompressed.
- Allowing unlimited tiny segments and concurrency, turning one download into a storage storm.
- Checking only status codes instead of total length, ETag, and the final checksum.
Follow-up questions and answers
Why not always return 206?
Without Range the client requested the full representation, so 200 is correct. Even with Range, the server must check satisfiability; 416 tells the client the current length so it can correct the request.
How is If-Range different from If-Match?
If-Range decides whether partial transfer can continue: a match yields 206 and a mismatch yields the full representation. If-Match is a precondition for performing a target operation, so its failure has a different meaning.
What should you do with multi-range requests?
First confirm that the client and storage need them. Split into bounded requests or implement multipart/byteranges; if the cost is not justified, reject explicitly instead of returning the first range and creating ambiguity.
How do you prevent signed download links from being abused?
Use short-lived signatures bound to user, tenant, object, version, and permission. Recheck boundaries server-side and limit concurrency, rate, range count, and total bytes. Revoked access or deletion must invalidate subsequent range requests.