Skip to content

Commit 3fb5738

Browse files
committed
Use text-encoder to ensure accurate content-length calculation with unicode chars
1 parent 57f4234 commit 3fb5738

File tree

3 files changed

+23
-18
lines changed

3 files changed

+23
-18
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ function fetchQuery(operation, variables) {
3434

3535
## Browser Support
3636

37-
Tested in the latest Chrome, Firefox, Safari, Edge, and Internet Explorer 11.
37+
Tested in the latest Chrome, Firefox, Safari, Edge, and Internet Explorer 11. Requires a polyfill for TextEncoder/Decoder. Since only utf-8 encoding is required, it's recommended to use [text-encoding-utf-8](https://www.npmjs.com/package/text-encoding-utf-8) to minimize impact on bundle size.

src/__test__/PatchResolver.spec.js

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import { PatchResolver } from '../PatchResolver';
2+
import { TextEncoder, TextDecoder } from 'util';
3+
// polyfill TextDecoder/Encoder for node
4+
global.TextEncoder = TextEncoder;
5+
global.TextDecoder = TextDecoder;
26

37
const chunk1 = [
48
'',
@@ -22,18 +26,18 @@ const chunk2 = [
2226
'',
2327
'---',
2428
'Content-Type: application/json',
25-
'Content-Length: 84',
29+
'Content-Length: 85',
2630
'',
27-
'{"path":["viewer","currencies"],"data":["USD","GBP","EUR","CAD","AUD","CHF","MXN"]}\n',
31+
'{"path":["viewer","currencies"],"data":["USD","GBP","EUR","CAD","AUD","CHF","😂"]}\n', // test unicode
2832
].join('\r\n');
2933

3034
const chunk2error = [
3135
'',
3236
'---',
3337
'Content-Type: application/json',
34-
'Content-Length: 126',
38+
'Content-Length: 127',
3539
'',
36-
'{"path":["viewer","currencies"],"data":["USD","GBP","EUR","CAD","AUD","CHF","MXN"],"errors":[{"message":"Not So Bad Error"}]}\n',
40+
'{"path":["viewer","currencies"],"data":["USD","GBP","EUR","CAD","AUD","CHF","😂"],"errors":[{"message":"Not So Bad Error"}]}\n',
3741
].join('\r\n');
3842

3943
const chunk3 = [
@@ -63,7 +67,7 @@ describe('PathResolver', function() {
6367
expect(onResponse).toHaveBeenCalledWith({
6468
data: {
6569
viewer: {
66-
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', 'MXN'],
70+
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', '😂'],
6771
user: { profile: null },
6872
},
6973
},
@@ -73,7 +77,7 @@ describe('PathResolver', function() {
7377
expect(onResponse).toHaveBeenCalledWith({
7478
data: {
7579
viewer: {
76-
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', 'MXN'],
80+
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', '😂'],
7781
user: { profile: { displayName: 'Steven Seagal' } },
7882
},
7983
},
@@ -111,7 +115,7 @@ describe('PathResolver', function() {
111115
expect(onResponse).toHaveBeenCalledWith({
112116
data: {
113117
viewer: {
114-
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', 'MXN'],
118+
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', '😂'],
115119
user: { profile: null },
116120
},
117121
},
@@ -130,7 +134,7 @@ describe('PathResolver', function() {
130134
expect(onResponse).toHaveBeenCalledWith({
131135
data: {
132136
viewer: {
133-
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', 'MXN'],
137+
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', '😂'],
134138
user: { profile: { displayName: 'Steven Seagal' } },
135139
},
136140
},
@@ -150,7 +154,7 @@ describe('PathResolver', function() {
150154
expect(onResponse.mock.calls[1][0]).toEqual({
151155
data: {
152156
viewer: {
153-
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', 'MXN'],
157+
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', '😂'],
154158
user: { profile: null },
155159
},
156160
},
@@ -174,7 +178,7 @@ describe('PathResolver', function() {
174178
expect(onResponse.mock.calls[1][0]).toEqual({
175179
data: {
176180
viewer: {
177-
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', 'MXN'],
181+
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', '😂'],
178182
user: { profile: null },
179183
},
180184
},
@@ -187,7 +191,7 @@ describe('PathResolver', function() {
187191
expect(onResponse).toHaveBeenCalledWith({
188192
data: {
189193
viewer: {
190-
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', 'MXN'],
194+
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', '😂'],
191195
user: { profile: { displayName: 'Steven Seagal' } },
192196
},
193197
},
@@ -213,7 +217,7 @@ describe('PathResolver', function() {
213217
expect(onResponse).toHaveBeenCalledWith({
214218
data: {
215219
viewer: {
216-
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', 'MXN'],
220+
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', '😂'],
217221
user: { profile: null },
218222
},
219223
},
@@ -236,7 +240,7 @@ describe('PathResolver', function() {
236240
expect(onResponse).toHaveBeenCalledWith({
237241
data: {
238242
viewer: {
239-
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', 'MXN'],
243+
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', '😂'],
240244
user: { profile: null },
241245
},
242246
},
@@ -247,7 +251,7 @@ describe('PathResolver', function() {
247251
expect(onResponse).toHaveBeenCalledWith({
248252
data: {
249253
viewer: {
250-
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', 'MXN'],
254+
currencies: ['USD', 'GBP', 'EUR', 'CAD', 'AUD', 'CHF', '😂'],
251255
user: { profile: { displayName: 'Steven Seagal' } },
252256
},
253257
},

src/parseMultipartHttp.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,18 @@ export function parseMultipartHttp(buffer, previousParts = []) {
4747

4848
// Strip out the terminating boundary
4949
rest = rest.replace(terminatingBoundary, '');
50+
const uint = new TextEncoder().encode(rest);
5051

51-
if (rest.length < contentLength) {
52+
if (uint.length < contentLength) {
5253
// still waiting for more body to be sent;
5354
return {
5455
newBuffer: buffer,
5556
parts: previousParts,
5657
};
5758
}
5859

59-
const body = rest.substring(0, contentLength);
60-
const nextBuffer = rest.substring(contentLength);
60+
const body = new TextDecoder().decode(uint.subarray(0, contentLength));
61+
const nextBuffer = new TextDecoder().decode(uint.subarray(contentLength));
6162
const part = JSON.parse(body);
6263
const newParts = [...previousParts, part];
6364

0 commit comments

Comments
 (0)