Skip to content

Commit 4692c12

Browse files
committed
Support encodings case-insensitively
The vast majority of real world traffic uses lowercase, but some does not, and it is technically case insensitive, so lets support it. This also adds 'binary', yet another common content-encoding mistake that seems to mean "there's no encoding here".
1 parent 221bdb3 commit 4692c12

File tree

4 files changed

+31
-24
lines changed

4 files changed

+31
-24
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The supported codecs are:
1212
* Brotli
1313
* Zstandard
1414

15-
The 'identity', 'amz-1.0', 'none', 'text' and 'utf-8' encodings (no-op encodings) are also supported, passed through with no en/decoding at all. Only 'identity' is standard, but the others are all in common use regardless.
15+
All encoding names are case-insensitive (although lowercase is generally standard). The 'identity', 'amz-1.0', 'none', 'text', 'binary' and 'utf-8' encodings (no-op encodings) are all supported as no-op encodings, passed through with no en/decoding at all. Only 'identity' is standard, but the others are all in common use regardless.
1616

1717
Found a codec used in real-world HTTP that isn't supported? Open an issue!
1818

src/index.ts

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ const IDENTITY_ENCODINGS = [
8181
// No idea where these comes from, but they definitely exist in real traffic and seem to come
8282
// from common confusion between content encodings and content types:
8383
'text',
84+
'binary',
8485
'utf-8'
8586
]
8687

@@ -102,6 +103,9 @@ export async function decodeBuffer(body: Uint8Array | ArrayBuffer, encoding: str
102103
}, Promise.resolve(bodyBuffer as Uint8Array)) as Promise<Buffer>;
103104
}
104105

106+
if (!encoding) encoding = 'identity';
107+
else encoding = encoding.toLowerCase();
108+
105109
if (encoding === 'gzip' || encoding === 'x-gzip') {
106110
return gunzip(bodyBuffer);
107111
} else if (encoding === 'deflate' || encoding === 'x-deflate') {
@@ -118,13 +122,7 @@ export async function decodeBuffer(body: Uint8Array | ArrayBuffer, encoding: str
118122
return asBuffer(await brotliDecompress(bodyBuffer));
119123
} else if (encoding === 'zstd') {
120124
return asBuffer(await zstdDecompress(bodyBuffer));
121-
} else if (
122-
// No encoding set at all:
123-
!encoding ||
124-
// Explicitly unencoded:
125-
IDENTITY_ENCODINGS.includes(encoding.toLowerCase())
126-
) {
127-
// All of the above are different ways of saying "no encoding at all"
125+
} else if (IDENTITY_ENCODINGS.includes(encoding)) {
128126
return asBuffer(bodyBuffer);
129127
}
130128

@@ -154,6 +152,9 @@ export async function decodeBuffer(body: Uint8Array | ArrayBuffer, encoding: str
154152
}, bodyBuffer) as Buffer;
155153
}
156154

155+
if (!encoding) encoding = 'identity';
156+
else encoding = encoding.toLowerCase();
157+
157158
if (encoding === 'gzip' || encoding === 'x-gzip') {
158159
return zlib.gunzipSync(bodyBuffer);
159160
} else if (encoding === 'deflate' || encoding === 'x-deflate') {
@@ -166,16 +167,7 @@ export async function decodeBuffer(body: Uint8Array | ArrayBuffer, encoding: str
166167
} else {
167168
return zlib.inflateRawSync(bodyBuffer);
168169
}
169-
} else if (encoding === 'amz-1.0') {
170-
// Weird encoding used by some AWS requests, actually just unencoded JSON:
171-
// https://docs.aws.amazon.com/en_us/AmazonCloudWatch/latest/APIReference/making-api-requests.html
172-
return asBuffer(bodyBuffer);
173-
} else if (
174-
// No encoding set at all:
175-
!encoding ||
176-
// Explicitly unencoded:
177-
IDENTITY_ENCODINGS.includes(encoding.toLowerCase())
178-
) {
170+
} else if (IDENTITY_ENCODINGS.includes(encoding)) {
179171
return asBuffer(bodyBuffer);
180172
}
181173

@@ -194,6 +186,9 @@ export async function decodeBuffer(body: Uint8Array | ArrayBuffer, encoding: str
194186
const bodyBuffer = asBuffer(body);
195187
const level = options.level ?? 4;
196188

189+
if (!encoding) encoding = 'identity';
190+
else encoding = encoding.toLowerCase() as SUPPORTED_ENCODING;
191+
197192
if (encoding === 'gzip' || encoding === 'x-gzip') {
198193
return gzip(bodyBuffer, { level });
199194
} else if (encoding === 'deflate' || encoding === 'x-deflate') {
@@ -206,12 +201,7 @@ export async function decodeBuffer(body: Uint8Array | ArrayBuffer, encoding: str
206201
} : {}));
207202
} else if (encoding === 'zstd') {
208203
return asBuffer(await zstdCompress(bodyBuffer, level));
209-
} else if (
210-
// No encoding set at all:
211-
!encoding ||
212-
// Explicitly unencoded:
213-
IDENTITY_ENCODINGS.includes(encoding.toLowerCase())
214-
) {
204+
} else if (IDENTITY_ENCODINGS.includes(encoding)) {
215205
return asBuffer(bodyBuffer);
216206
} else {
217207
throw new Error(`Unsupported encoding: ${encoding}`);

test/decode.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ describe("Decode", () => {
9595
const body = await decodeBuffer(content, 'br, identity, gzip, identity, zstd');
9696
expect(body.toString()).to.equal('First brotli, then gzip, last zstandard, now this');
9797
});
98+
99+
it('should decode bodies ignoring the code of the encoding', async () => {
100+
const content = bufferToTypedArray(zlib.gzipSync('Gzip response'));
101+
const body = await decodeBuffer(content, 'GZIP');
102+
expect(body.toString()).to.equal('Gzip response');
103+
});
98104
});
99105

100106
describe("DecodeSync", () => {
@@ -153,4 +159,10 @@ describe("DecodeSync", () => {
153159
const body = decodeBufferSync(content, 'deflate, identity, gzip, identity');
154160
expect(body.toString()).to.equal('First deflate, then gzip, now this');
155161
});
162+
163+
it('should decode bodies ignoring the code of the encoding', () => {
164+
const content = zlib.gzipSync('Gzip response');
165+
const body = decodeBufferSync(content, 'GZIP');
166+
expect(body.toString()).to.equal('Gzip response');
167+
});
156168
});

test/encode.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,9 @@ describe("Encode", () => {
7070
(await zstd).decompress(body)
7171
).toString()).to.equal('zstd zstd body body body');
7272
});
73+
74+
it('should encode bodies ignoring the case of the encoding', async () => {
75+
const body = await encodeBuffer(Buffer.from('Response to gzip'), 'gzip', { level: 1 });
76+
expect(zlib.gunzipSync(body).toString()).to.equal('Response to gzip');
77+
});
7378
});

0 commit comments

Comments
 (0)