Adding Brotli compression support (#4288)

Summary:
Closes https://github.com/facebook/flipper/issues/2578

Adds Brotli compression support for br-encoded endpoints

## Changelog

 - Brotli compression support

Pull Request resolved: https://github.com/facebook/flipper/pull/4288

Test Plan:
Confirmed `content-encoding` had `br` for Brotli and that the response text post-decompression was parsed properly:

![image](https://user-images.githubusercontent.com/117083/199068874-1577577f-2d2f-4687-a3d8-aa41a032ab32.png)
![image](https://user-images.githubusercontent.com/117083/199069109-8564ea03-99db-4c8a-9dbc-4d007fe38f5b.png)

A note for reviewer(s) is that I am by no means a javascript/typescript/yarn/npm/electron/etc developer, so please please make sure I did things properly and let me know what to fix, how, why it's wrong. Thanks!

Reviewed By: antonk52

Differential Revision: D41444623

Pulled By: mweststrate

fbshipit-source-id: ac4e84b4501c67a4b89163c20c63de1be14d6cef
This commit is contained in:
Dallas Gutauckis
2022-12-16 02:39:49 -08:00
committed by Facebook GitHub Bot
parent a4525790a2
commit 10d7c288f5
3 changed files with 50 additions and 17 deletions

View File

@@ -7,6 +7,7 @@
* @format
*/
import decompress from 'brotli/decompress';
import pako from 'pako';
import {Request, Header, ResponseInfo} from './types';
import {Base64} from 'js-base64';
@@ -99,26 +100,37 @@ export function decodeBody(
}
try {
const isGzip = getHeaderValue(headers, 'Content-Encoding') === 'gzip';
if (isGzip) {
try {
// The request is gzipped, so convert the raw bytes back to base64 first.
const dataArr = Base64.toUint8Array(data);
// then inflate.
return isTextual(headers, dataArr)
? // pako will detect the BOM headers and return a proper utf-8 string right away
pako.inflate(dataArr, {to: 'string'})
: pako.inflate(dataArr);
} catch (e) {
// on iOS, the stream send to flipper is already inflated, so the content-encoding will not
// match the actual data anymore, and we should skip inflating.
// In that case, we intentionally fall-through
if (!('' + e).includes('incorrect header check')) {
throw e;
const contentEncoding = getHeaderValue(headers, 'Content-Encoding');
switch (contentEncoding) {
// Gzip encoding
case 'gzip': {
try {
// The request is gzipped, so convert the raw bytes back to base64 first.
const dataArr = Base64.toUint8Array(data);
// then inflate.
return isTextual(headers, dataArr)
? // pako will detect the BOM headers and return a proper utf-8 string right away
pako.inflate(dataArr, {to: 'string'})
: pako.inflate(dataArr);
} catch (e) {
// on iOS, the stream send to flipper is already inflated, so the content-encoding will not
// match the actual data anymore, and we should skip inflating.
// In that case, we intentionally fall-through
if (!('' + e).includes('incorrect header check')) {
throw e;
}
break;
}
}
// Brotli encoding (https://github.com/facebook/flipper/issues/2578)
case 'br': {
return new TextDecoder().decode(
decompress(Buffer.from(Base64.toUint8Array(data))),
);
}
}
// If this is not a gzipped request, assume we are interested in a proper utf-8 string.
// If this is not a gzipped or brotli-encoded request, assume we are interested in a proper utf-8 string.
// - If the raw binary data in is needed, in base64 form, use data directly
// - either directly use data (for example)
const bytes = Base64.toUint8Array(data);