Skip to content

Commit

Permalink
Check request size for POST and POSTForm requests (#24)
Browse files Browse the repository at this point in the history
Heuristically check body size for POST and POSTForm requests. Fixes #20
  • Loading branch information
chaosrealm authored Jul 4, 2024
1 parent 5396765 commit b7e06f7
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 1 deletion.
25 changes: 24 additions & 1 deletion api-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ type Method = "POST" | "GET" | "PUT" | "DELETE";
/* eslint-disable @typescript-eslint/no-explicit-any */

export class CortexApiClient {
private readonly maxRequestSize = 32 * 1000 * 1000; // API is configured with max request body size of 32mb

constructor(
private org: string,
private apiUrl: string,
Expand All @@ -27,6 +29,11 @@ export class CortexApiClient {
}

async POSTForm(path: string, form: FormData) {
const requestSize = CortexApiClient.getFormDataSize(form);
if (requestSize > this.maxRequestSize) {
throw new Error("Request body too large");
}

return fetch(`${this.apiUrl}/org/${this.org}${path}`, {
method: "POST",
headers: {
Expand All @@ -37,13 +44,29 @@ export class CortexApiClient {
}

private async makeRequest(method: Method, path: string, body?: any) {
const requestBody = body ? JSON.stringify(body) : undefined;
// Note that we use character size instead of byte size. This is still a useful heuristic as we don't want to incur the overhead
// of using TextEncoder to calculate the precise byte count
if (requestBody && requestBody.length > this.maxRequestSize) {
throw new Error("Request body too large");
}

return fetch(`${this.apiUrl}/org/${this.org}${path}`, {
method,
headers: {
Authorization: `Bearer ${this.accessToken}`,
"Content-Type": "application/json",
},
body: body ? JSON.stringify(body) : undefined,
body: requestBody,
});
}

private static getFormDataSize(formData: FormData) {
return [...formData].reduce(
(size, [_, value]) =>
// Use heuristic of string length instead of byte size, to avoid incurring the cost of using TextEncoder
size + (typeof value === "string" ? value.length : value.size),
0,
);
}
}
6 changes: 6 additions & 0 deletions content.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ test(
expect(content.version).toBe(0);
expect(content.commands.length).toBe(1);

// check that prompt that is too large will fail gracefully without hitting the service
const hugePrompt = "p".repeat(32 * 1000 * 1000);
await expect(() =>
cortex.generateContent({ title, prompt: hugePrompt }),
).rejects.toThrow("Request body too large");

// get content
const getContent = await testClient.getContent(content.id);
expect(getContent.content.length).toBe(content.content.length);
Expand Down

0 comments on commit b7e06f7

Please sign in to comment.