Skip to content

Commit 2e46959

Browse files
authored
fix(browser): Send gzipped request body as ArrayBuffer (#3172)
* fix(browser): Send gzipped request body as ArrayBuffer In WebKit, calling `fetch` with a `Blob` in the body results in an empty request. Using an ArrayBuffer allows the bytes to be written directly to the request body buffer, while Blobs require a seperate lookup in a blob registry. Presumably this step is failing (seems like a bug?). * chore(browser): add changeset * test: update expected body type
1 parent 186871a commit 2e46959

File tree

3 files changed

+15
-18
lines changed

3 files changed

+15
-18
lines changed

.changeset/tired-rings-fry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'posthog-js': patch
3+
---
4+
5+
fix: Compressed requests use ArrayBuffer

packages/browser/src/__tests__/request.test.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable compat/compat */
22
/// <reference lib="dom" />
33

4+
import { TextDecoder } from 'util'
45
import { extendURLParams, request } from '../request'
56
import { Compression, RequestWithOptions } from '../types'
67

@@ -400,14 +401,10 @@ describe('request', () => {
400401
})
401402
)
402403
expect(mockedXHR.send).toHaveBeenCalledTimes(1)
403-
expect(mockedXHR.send.mock.calls[0][0]).toBeInstanceOf(Blob)
404-
// Decode and check the blob content
404+
expect(mockedXHR.send.mock.calls[0][0]).toBeInstanceOf(ArrayBuffer)
405+
// Decode and check the ArrayBuffer content
405406

406-
const res = await new Promise((resolve) => {
407-
const reader = new FileReader()
408-
reader.onload = () => resolve(reader.result)
409-
reader.readAsText(mockedXHR.send.mock.calls[0][0])
410-
})
407+
const res = new TextDecoder().decode(mockedXHR.send.mock.calls[0][0] as ArrayBuffer)
411408

412409
expect(res).toMatchInlineSnapshot(`
413410
"��VJ��W�RJJ,R���+
@@ -505,15 +502,11 @@ describe('request', () => {
505502

506503
expect(mockedNavigator?.sendBeacon).toHaveBeenCalledWith(
507504
'https://any.posthog-instance.com/?_=1700000000000&ver=1.23.45&compression=gzip-js&beacon=1',
508-
expect.any(Blob)
505+
expect.any(ArrayBuffer)
509506
)
510-
const blob = mockedNavigator?.sendBeacon.mock.calls[0][1] as Blob
507+
const arrayBuffer = mockedNavigator?.sendBeacon.mock.calls[0][1] as ArrayBuffer
511508

512-
const reader = new FileReader()
513-
const result = await new Promise((resolve) => {
514-
reader.onload = () => resolve(reader.result)
515-
reader.readAsText(blob)
516-
})
509+
const result = new TextDecoder().decode(arrayBuffer)
517510

518511
expect(result).toMatchInlineSnapshot(`
519512
"��VJ��W�RJJ,R���+

packages/browser/src/request.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const SIXTY_FOUR_KILOBYTES = 64 * 1024
2424
const KEEP_ALIVE_THRESHOLD = SIXTY_FOUR_KILOBYTES * 0.8
2525
type EncodedBody = {
2626
contentType: string
27-
body: string | BlobPart
27+
body: string | BlobPart | ArrayBuffer
2828
estimatedSize: number
2929
}
3030

@@ -75,11 +75,10 @@ const encodePostData = ({ data, compression }: RequestWithOptions): EncodedBody
7575

7676
if (compression === Compression.GZipJS) {
7777
const gzipData = gzipSync(strToU8(jsonStringify(data)), { mtime: 0 })
78-
const blob = new Blob([gzipData], { type: CONTENT_TYPE_PLAIN })
7978
return {
8079
contentType: CONTENT_TYPE_PLAIN,
81-
body: blob,
82-
estimatedSize: blob.size,
80+
body: gzipData.buffer.slice(gzipData.byteOffset, gzipData.byteOffset + gzipData.byteLength) as ArrayBuffer,
81+
estimatedSize: gzipData.byteLength,
8382
}
8483
}
8584

0 commit comments

Comments
 (0)