226 IM Used
What is HTTP 226 IM Used?
When websites change a little bit, instead of downloading the whole webpage agai...
Explain Like I’m 3
You asked for a picture, but instead of sending you the whole picture again, someone just sends you the new parts that changed! Like when you color a coloring book - they only send you the new crayons you added, not the whole page again!
Example: You drew a house yesterday. Today you added a tree. Instead of sending the whole drawing again, they just send you the tree part and say ‘add this to what you have!’
Explain Like I’m 5
When websites change a little bit, instead of downloading the whole webpage again (which wastes time and space), the computer can ask ‘just send me what changed!’ The website says ‘226 IM Used’ which means ‘I’m using Instance Manipulations - I’m sending you a special file that shows only the changes!’ Your computer then adds those changes to the old version it already has, creating the new version. It’s like a puzzle - you already have most pieces, and you just need the few new pieces. This is called ‘delta encoding’ and it saves a lot of bandwidth!
Example: You have a news website you visit every day. The news changes, but the logo, menu, and layout stay the same. Instead of downloading all 2MB again, the website sends you a 50KB ‘delta’ file showing only the changed news articles. Your browser applies those changes to yesterday’s version, and you see today’s page!
Jr. Developer
HTTP 226 IM Used indicates the server fulfilled a GET request using instance manipulations - transformations applied to a cached representation to produce the current representation. This is primarily for delta encoding (RFC 3229) where the server sends only the differences (delta) between the cached version and current version, saving bandwidth. The client includes A-IM: vcdiff (or other delta encoding) in the request, signaling it can handle deltas. If the client has a cached version (sends If-None-Match with ETag), the server can compute the delta and return 226 with IM: vcdiff indicating the body is a delta, not the full resource. The client applies the delta to its cached version, reconstructing the current version. Use cases: news sites with incremental updates, software updates (downloading only changed files), large resources with small frequent changes, bandwidth-constrained environments. 226 is extremely rare in practice - few servers implement delta encoding, and most bandwidth optimization relies on compression (gzip) and caching (304 Not Modified) instead. You’ll primarily see 226 in academic papers and RFC examples, not production systems.
Example: A client has version 1 of a 10MB document (ETag: “v1”). The document is updated to version 2 with only 100KB of changes. Client sends GET with If-None-Match: “v1” and A-IM: vcdiff. Server computes the delta (100KB), returns 226 IM Used with IM: vcdiff and ETag: “v2”. Body contains the 100KB delta. Client applies delta to cached version 1, producing version 2, saving 9.9MB of bandwidth.
Code Example
// Conceptual 226 request/response// Client requestGET /large-document.html HTTP/1.1Host: example.comIf-None-Match: \"abc123\" // ETag of cached versionA-IM: vcdiff // I can handle vcdiff deltas
// Server response (if delta encoding is supported)HTTP/1.1 226 IM UsedETag: \"def456\" // ETag of new versionIM: vcdiff // Body is vcdiff deltaContent-Type: application/octet-streamContent-Length: 102400 // Delta size: 100KB
[vcdiff binary delta data]
// If server doesn't support delta encodingHTTP/1.1 304 Not Modified// orHTTP/1.1 200 OK[full content]Crash Course
226 IM Used, defined in RFC 3229 (Delta Encoding in HTTP), indicates the server has fulfilled a GET request and the response is a representation resulting from one or more instance manipulations (IMs) applied to the cached instance. Instance manipulations are transformations like delta encoding (sending differences), compression, or range selection. The primary use case is bandwidth optimization via delta encoding: clients cache large resources and request only changes on subsequent fetches. The A-IM (Accept-IM) request header lists supported instance manipulations (e.g., vcdiff, diffe, gzip, range). The IM response header indicates which manipulations were applied, in order (e.g., IM: vcdiff, deflate means delta-encoded then compressed). The ETag header in 226 responses identifies the current instance after applying manipulations - clients store this for future If-None-Match requests. Delta encoding algorithms include vcdiff (RFC 3284, binary diff), diffe (line-based text diff), and gdiff (generic diff). The server must support computing deltas between arbitrary versions, requiring version storage or on-the-fly computation. Caching proxies receiving 226 can decode manipulations to store the full current instance as 200 OK, enabling cache hits for clients not supporting IMs. 226 is distinct from 304 Not Modified: 304 means ‘your cached version is still current, use it as-is,’ while 226 means ‘your cached version is stale, here’s a delta to update it.’ The technology is sound but adoption is near-zero - delta encoding adds complexity (servers must compute/store deltas, clients must apply them), modern compression is highly effective (gzip reduces size 60-90%), CDN caching makes full downloads fast, and 304 Not Modified handles most caching needs. You’ll see 226 in specialized scenarios: software update systems (apt-get uses delta updates), scientific data distribution (incremental dataset updates), bandwidth-constrained military/maritime networks.
Example: A weather forecast API serves a 5MB JSON file with global forecasts, updated hourly. Typically only 200KB changes each hour (updated predictions for next few hours). A mobile app on a slow 3G connection caches the 5MB file with ETag: “hour-12”. At hour-13, it sends GET with If-None-Match: “hour-12” and A-IM: vcdiff. The server computes a 200KB vcdiff delta between hour-12 and hour-13 versions, returns 226 IM Used with IM: vcdiff, ETag: “hour-13”, and the 200KB delta body. The app applies the delta, reconstructing the hour-13 version, saving 4.8MB (96%) of bandwidth. Over 24 requests, this saves 115.2MB vs. downloading full 5MB each time.
Code Example
// Conceptual delta encoding implementationconst express = require('express');const vcdiff = require('vcdiff'); // Hypothetical vcdiff libraryconst crypto = require('crypto');const app = express();
// In-memory version storage (in production: database or filesystem)const versions = new Map();
app.get('/api/data', async (req, res) => { const currentData = await fetchCurrentData(); const currentETag = generateETag(currentData);
// Check if client accepts instance manipulations const acceptIM = req.headers['a-im']; const clientETag = req.headers['if-none-match']?.replace(/\"/g, '');
if (acceptIM && acceptIM.includes('vcdiff') && clientETag) { // Client supports vcdiff and has a cached version const cachedData = versions.get(clientETag);
if (!cachedData) { // Don't have the client's version - send full response return sendFullResponse(res, currentData, currentETag); }
if (cachedData === currentData) { // No changes - 304 Not Modified return res.status(304) .set('ETag', `\"${currentETag}\"`) .end(); }
// Compute delta const delta = vcdiff.encode(cachedData, currentData);
// Store current version for future requests versions.set(currentETag, currentData);
// Return 226 IM Used with delta res.status(226) .set({ 'ETag': `\"${currentETag}\"`, 'IM': 'vcdiff', 'Content-Type': 'application/octet-stream', 'Content-Length': delta.length, 'Cache-Control': 'private, no-transform' }) .send(delta);
} else { // Client doesn't support delta encoding or no cached version sendFullResponse(res, currentData, currentETag); }});
function sendFullResponse(res, data, etag) { versions.set(etag, data);
res.status(200) .set({ 'ETag': `\"${etag}\"`, 'Content-Type': 'application/json', 'IM': 'identity', // No transformations 'Cache-Control': 'private' }) .json(data);}
function generateETag(data) { return crypto.createHash('md5').update(JSON.stringify(data)).digest('hex');}
async function fetchCurrentData() { // Fetch current data from database... return { forecast: [...], timestamp: Date.now() };}
app.listen(3000);Deep Dive
The 226 IM Used status code, specified in RFC 3229 Section 10.4.1 (Delta Encoding in HTTP), indicates that the server has fulfilled a GET request for the resource, and the response is a representation of the result of one or more instance manipulations applied to the current instance. Per RFC 3229: ‘The request MUST have included an A-IM header field listing at least one instance-manipulation. The response MUST include an ETag header field giving the entity tag of the current instance.’ Instance manipulations are content transformations that produce variants of a resource: delta encoding (vcdiff, diffe, gdiff), compression (gzip, deflate), range selection (bytes), and combinations thereof. The IM header lists applied manipulations in order, enabling reconstruction: IM: vcdiff, deflate means delta-encoded then compressed - client must decompress then apply delta.
Technical Details
Delta encoding workflow follows a specific pattern. The initial request (no cached version) includes A-IM: vcdiff. Server responds 200 OK with full content, IM: identity (no transformation), and ETag: “v1”. Client caches the content with ETag “v1”. Subsequent requests include A-IM: vcdiff and If-None-Match: “v1”. Server checks if content changed. If unchanged, responds 304 Not Modified. If changed, computes delta from v1 to v2, responds 226 IM Used with IM: vcdiff, ETag: “v2”, and delta in body. Client applies delta to cached v1, producing v2, stores v2 with ETag “v2”. Future requests use If-None-Match: “v2”.\n\nDelta algorithms specified in RFC 3229 include vcdiff (RFC 3284, binary differential compression, efficient for binaries), diffe (line-based text diff, simple but inefficient), and gdiff (generic diff format). Vcdiff is most efficient - used by tools like xdelta, rsync wire protocol. The algorithm finds matching byte sequences between source (cached) and target (current) versions, encoding target as ‘copy X bytes from position Y in source’ and ‘add these literal bytes’ instructions. For files with small localized changes, vcdiff achieves 90-99% compression.\n\nServer implementation challenges include version storage (must retain old versions to compute deltas - costly for large files or many versions), delta computation cost (CPU-intensive, especially for large files), and cache management (when to purge old versions, how many versions to keep). Strategies: rolling window (keep last N versions), time-based (keep versions from last 24 hours), or on-demand (compute deltas from cached versions, store current only).\n\nCaching proxy behavior is specified in RFC 3229 Section 7. When a proxy receives a 226 IM Used response, it MAY decode all instance manipulations to recover the original instance and store that as a 200 OK response in cache. This enables serving clients that don’t support IMs. Conversely, a proxy with a cached 200 OK response MAY generate 226 IM Used responses with deltas for clients sending A-IM, if the proxy has the capability to compute deltas. This shifts delta computation from origin to proxy, distributing load.\n\nContent negotiation with IM is orthogonal to Accept-Encoding. Accept-Encoding: gzip requests transfer compression (transparent encoding/decoding). A-IM: vcdiff, gzip requests delta encoding with optional subsequent compression. A server might respond IM: vcdiff, gzip (delta then compressed) or IM: gzip, vcdiff (compressed then delta - unusual). The order matters for reconstruction.\n\nSecurity implications include denial-of-service via delta bombs (crafted small delta that expands to huge resource, exhausting client memory/CPU - similar to compression bombs), cache poisoning (if delta computation is incorrect, clients reconstruct wrong content), and timing attacks (delta computation time might leak information about content changes). Mitigations: limit delta expansion ratio (max output size relative …
Code Example
// Production-grade delta encoding service\nconst express = require('express');\nconst vcdiff = require('xdelta3'); // Real vcdiff implementation\nconst crypto = require('crypto');\nconst zlib = require('zlib');\nconst LRU = require('lru-cache');\nconst app = express();\n\n// LRU cache for versions (limit memory usage)\nconst versionCache = new LRU({\n max: 1000, // Max 1000 versions\n maxSize: 500 * 1024 * 1024, // Max 500MB total\n sizeCalculation: (value) => value.length,\n ttl: 1000 * 60 * 60 * 24 // 24 hour TTL\n});\n\napp.get('/api/large-resource', async (req, res) => {\n const currentData = await fetchLargeResource();\n const currentBuffer = Buffer.from(JSON.stringify(currentData));\n const currentETag = generateETag(currentBuffer);\n \n // Parse A-IM header\n const acceptIM = parseAIM(req.headers['a-im']);\n const clientETag = req.headers['if-none-match']?.replace(/\"/g, '');\n \n const supportsVcdiff = acceptIM.includes('vcdiff');\n const supportsGzip = acceptIM.includes('gzip') || req.headers['accept-encoding']?.includes('gzip');\n \n // Check if we should use delta encoding\n if (supportsVcdiff && clientETag) {\n const cachedBuffer = versionCache.get(clientETag);\n \n if (!cachedBuffer) {\n // Don't have client's version - fall back to full response\n console.log('Client ETag not found in cache, sending full response');\n return sendFullResponse(res, currentBuffer, currentETag, supportsGzip);\n }\n \n // Check if content actually changed\n if (currentETag === clientETag) {\n return res.status(304)\n .set('ETag', \`\"${currentETag}\"\`)\n .end();\n }\n \n try {\n // Compute vcdiff delta\n const deltaStart = Date.now();\n const delta = await computeVcdiffDelta(cachedBuffer, currentBuffer);\n const deltaTime = Date.now() - deltaStart;\n \n console.log(`Delta computed in ${deltaTime}ms: ${cachedBuffer.length} -> ${currentBuffer.length}, delta size ${delta.length}`);\n \n // Calculate savings\n const savings = ((1 - delta.length / currentBuffer.length) * 100).toFixed(1);\n \n // Optionally compress delta\n let responseBody = delta;\n let usedIMs = ['vcdiff'];\n \n if (supportsGzip && delta.length > 1024) {\n responseBody = zlib.gzipSync(delta);\n usedIMs.push('gzip');\n console.log(`Delta compressed: ${delta.length} -> ${responseBody.length}`);\n }\n \n // Store current version\n versionCache.set(currentETag, currentBuffer);\n \n // Return 226 IM Used\n res.status(226)\n .set({\n 'ETag': \`\"${currentETag}\"\`,\n 'IM': usedIMs.join(', '),\n 'Content-Type': 'application/octet-stream',\n 'Content-Length': responseBody.length,\n 'X-Delta-Savings': \`${savings}%\`,\n 'X-Delta-Time-Ms': deltaTime,\n 'Cache-Control': 'private, no-transform'\n })\n .send(re...Frequently Asked Questions
What is delta encoding and how does 226 IM Used relate to it?
Delta encoding means sending only the differences (delta) between a cached version and the current version, instead of sending the full resource again. 226 IM Used indicates the server is using instance manipulations (like delta encoding) - the response body contains a delta that the client applies to its cached version to reconstruct the current version, saving bandwidth.
How is 226 IM Used different from 304 Not Modified?
304 means 'your cached version is still current, use it as-is' (no body sent). 226 means 'your cached version is stale, but here's a delta to update it' (delta body sent). Both save bandwidth vs. 200 OK with full content, but 226 handles the case where content changed but most of it is the same.
Why isn't 226 IM Used widely used?
Delta encoding adds significant complexity: servers must compute and store deltas, clients must apply them correctly. Modern gzip compression achieves 60-90% size reduction with less complexity. CDNs make full downloads fast. 304 Not Modified handles most caching needs. The bandwidth savings often don't justify the implementation cost. It's used in specialized scenarios like software updates but rarely in general web traffic.
What instance manipulations can be indicated by the IM header?
Common instance manipulations include: vcdiff (binary delta encoding, RFC 3284), diffe (line-based text diff), gzip/deflate (compression), range (byte range selection), and combinations like 'vcdiff, gzip' (delta-encoded then compressed). The IM header lists them in order of application, so the client can reverse the transformations to get the original content.
Can I use 226 in REST APIs for sending partial updates?
Technically yes, but it's非standard and clients likely won't support it. For partial updates in REST APIs, better approaches include: JSON Patch (RFC 6902) for structured JSON diffs, returning only changed fields in 200 responses, using GraphQL for selective field requests, or custom delta formats in application logic. Reserve 226 for specialized bandwidth-constrained scenarios where HTTP-level delta encoding is justified.
Common Causes
- Software update systems using delta updates (apt-get pdiffs, system updates)
- Large file sync services transmitting only changes
- News/data feeds with incremental updates (weather data, financial data)
- Bandwidth-constrained networks (maritime, military, satellite)
- Scientific data distribution with large datasets and small changes
- Academic/research HTTP delta encoding implementations
Implementation Guidance
- Client-side: Send A-IM: vcdiff header to indicate delta encoding support
- Client-side: Include If-None-Match with cached version’s ETag
- Client-side: Apply delta from 226 response to cached content to reconstruct current version
- Client-side: Handle fallback to 200 if server doesn’t support delta encoding
- Server-side: Parse A-IM header to check client capabilities
- Server-side: Compute delta between cached version (from If-None-Match) and current
- Server-side: Return 226 with IM header listing manipulations used
- Server-side: Include ETag of current version in response
- Server-side: Implement version storage/caching for delta computation
- Server-side: Limit delta expansion ratio to prevent delta bombs
- Server-side: Fall back to 200/304 if delta computation fails or isn’t beneficial
- Consider alternatives: gzip compression, 304 Not Modified, application-level deltas