From 8dfff2691a3ebd5721462c055d8da638ac77e571 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Tue, 11 Jul 2023 00:33:10 +0100 Subject: [PATCH] fix(client): properly handle multi-byte characters in Content-Length (#47) --- src/core.ts | 16 +++++++++++++++- tests/index.test.ts | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/core.ts b/src/core.ts index 150c5cb6..d4019229 100644 --- a/src/core.ts +++ b/src/core.ts @@ -122,6 +122,20 @@ export abstract class APIClient { return this.requestAPIList(Page, { method: 'get', path, ...opts }); } + private calculateContentLength(body: unknown): string | null { + if (typeof body === 'string') { + if (typeof Buffer !== 'undefined') { + return Buffer.byteLength(body, 'utf8').toString(); + } + + const encoder = new TextEncoder(); + const encoded = encoder.encode(body); + return encoded.length.toString(); + } + + return null; + } + buildRequest( options: FinalRequestOptions, ): { req: RequestInit; url: string; timeout: number } { @@ -131,7 +145,7 @@ export abstract class APIClient { isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null; - const contentLength = typeof body === 'string' ? body.length.toString() : null; + const contentLength = this.calculateContentLength(body); const url = this.buildURL(path!, query); if ('timeout' in options) validatePositiveInteger('timeout', options.timeout); diff --git a/tests/index.test.ts b/tests/index.test.ts index ec344c28..e7bc3c09 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -144,3 +144,19 @@ describe('instantiate client', () => { expect(client.apiKey).toBeNull(); }); }); + +describe('request building', () => { + const client = new Anthropic({ apiKey: 'my api key' }); + + describe('Content-Length', () => { + test('handles multi-byte characters', () => { + const { req } = client.buildRequest({ path: '/foo', method: 'post', body: { value: '—' } }); + expect((req.headers as Record)['Content-Length']).toEqual('20'); + }); + + test('handles standard characters', () => { + const { req } = client.buildRequest({ path: '/foo', method: 'post', body: { value: 'hello' } }); + expect((req.headers as Record)['Content-Length']).toEqual('22'); + }); + }); +});