mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-15 05:37:32 +00:00
fix: raw body limit (#10254)
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
import { Args, Mutation, Resolver } from '@nestjs/graphql';
|
||||
import type { TestFn } from 'ava';
|
||||
import ava from 'ava';
|
||||
import GraphQLUpload, {
|
||||
type FileUpload,
|
||||
} from 'graphql-upload/GraphQLUpload.mjs';
|
||||
import request from 'supertest';
|
||||
|
||||
import { buildAppModule } from '../../app.module';
|
||||
import { Public } from '../../core/auth';
|
||||
import { createTestingApp, TestingApp } from '../utils';
|
||||
|
||||
const gql = '/graphql';
|
||||
@@ -11,6 +16,26 @@ const test = ava as TestFn<{
|
||||
app: TestingApp;
|
||||
}>;
|
||||
|
||||
@Resolver(() => String)
|
||||
class TestResolver {
|
||||
@Public()
|
||||
@Mutation(() => Number)
|
||||
async upload(
|
||||
@Args({ name: 'body', type: () => GraphQLUpload })
|
||||
body: FileUpload
|
||||
): Promise<number> {
|
||||
const size = await new Promise<number>((resolve, reject) => {
|
||||
const stream = body.createReadStream();
|
||||
let size = 0;
|
||||
stream.on('data', chunk => (size += chunk.length));
|
||||
stream.on('error', reject);
|
||||
stream.on('end', () => resolve(size));
|
||||
});
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
test.before('start app', async t => {
|
||||
// @ts-expect-error override
|
||||
AFFiNE.flavor = {
|
||||
@@ -19,6 +44,7 @@ test.before('start app', async t => {
|
||||
} as typeof AFFiNE.flavor;
|
||||
const app = await createTestingApp({
|
||||
imports: [buildAppModule()],
|
||||
providers: [TestResolver],
|
||||
});
|
||||
|
||||
t.context.app = app;
|
||||
@@ -83,3 +109,29 @@ test('should not throw internal error when graphql call with invalid params', as
|
||||
message: /Failed to execute gql: query { workspace\("1"\) \}, status: 400/,
|
||||
});
|
||||
});
|
||||
|
||||
test('should can send maximum size of body', async t => {
|
||||
const { app } = t.context;
|
||||
|
||||
const body = Buffer.from('a'.repeat(10 * 1024 * 1024 - 1));
|
||||
const res = await app
|
||||
.POST('/graphql')
|
||||
.set({ 'x-request-id': 'test', 'x-operation-name': 'test' })
|
||||
.field(
|
||||
'operations',
|
||||
JSON.stringify({
|
||||
name: 'upload',
|
||||
query: `mutation upload($body: Upload!) { upload(body: $body) }`,
|
||||
variables: { body: null },
|
||||
})
|
||||
)
|
||||
.field('map', JSON.stringify({ '0': ['variables.body'] }))
|
||||
.attach(
|
||||
'0',
|
||||
body,
|
||||
`body-${Math.random().toString(16).substring(2, 10)}.data`
|
||||
)
|
||||
.expect(200);
|
||||
|
||||
t.is(Number(res.body.data.upload), body.length);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { mkdirSync, writeFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import { Controller, Post, RawBody } from '@nestjs/common';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import type { TestFn } from 'ava';
|
||||
import ava from 'ava';
|
||||
@@ -8,6 +9,7 @@ import request from 'supertest';
|
||||
|
||||
import { buildAppModule } from '../../app.module';
|
||||
import { Config } from '../../base';
|
||||
import { Public } from '../../core/auth';
|
||||
import { ServerService } from '../../core/config';
|
||||
import { createTestingApp, type TestingApp } from '../utils';
|
||||
|
||||
@@ -36,12 +38,22 @@ function initTestStaticFiles(staticPath: string) {
|
||||
}
|
||||
}
|
||||
|
||||
@Controller('/')
|
||||
export class TestResolver {
|
||||
@Public()
|
||||
@Post('/upload')
|
||||
async upload(@RawBody() buffer: Buffer | undefined): Promise<number> {
|
||||
return buffer?.length || 0;
|
||||
}
|
||||
}
|
||||
|
||||
test.before('init selfhost server', async t => {
|
||||
// @ts-expect-error override
|
||||
AFFiNE.isSelfhosted = true;
|
||||
AFFiNE.flavor.renderer = true;
|
||||
const app = await createTestingApp({
|
||||
imports: [buildAppModule()],
|
||||
controllers: [TestResolver],
|
||||
});
|
||||
|
||||
t.context.app = app;
|
||||
@@ -203,3 +215,16 @@ test.skip('should return web assets if visited by mobile', async t => {
|
||||
|
||||
t.true(res.text.includes('AFFiNE mobile'));
|
||||
});
|
||||
|
||||
test('should can send maximum size of body', async t => {
|
||||
const { app } = t.context;
|
||||
|
||||
const body = 'a'.repeat(1 * 1024 * 1024);
|
||||
const res = await app
|
||||
.POST('/upload')
|
||||
.set('Content-Type', 'application/octet-stream')
|
||||
.send(body)
|
||||
.expect(201);
|
||||
|
||||
t.is(Number(res.text), body.length);
|
||||
});
|
||||
|
||||
@@ -19,6 +19,8 @@ interface TestingAppMetadata extends ModuleMetadata {
|
||||
|
||||
export type TestUser = Omit<User, 'password'> & { password: string };
|
||||
|
||||
const OneMB = 1024 * 1024;
|
||||
|
||||
export async function createTestingApp(
|
||||
moduleDef: TestingAppMetadata = {}
|
||||
): Promise<TestingApp> {
|
||||
@@ -30,7 +32,7 @@ export async function createTestingApp(
|
||||
rawBody: true,
|
||||
});
|
||||
|
||||
app.useBodyParser('raw');
|
||||
app.useBodyParser('raw', { limit: 1 * OneMB });
|
||||
|
||||
const logger = new AFFiNELogger();
|
||||
|
||||
@@ -40,7 +42,7 @@ export async function createTestingApp(
|
||||
app.useGlobalFilters(new GlobalExceptionFilter(app.getHttpAdapter()));
|
||||
app.use(
|
||||
graphqlUploadExpress({
|
||||
maxFileSize: 10 * 1024 * 1024,
|
||||
maxFileSize: 10 * OneMB,
|
||||
maxFiles: 5,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -14,6 +14,8 @@ import { AuthGuard } from './core/auth';
|
||||
import { ENABLED_FEATURES } from './core/config/server-feature';
|
||||
import { serverTimingAndCache } from './middleware/timing';
|
||||
|
||||
const OneMB = 1024 * 1024;
|
||||
|
||||
export async function createApp() {
|
||||
const { AppModule } = await import('./app.module');
|
||||
|
||||
@@ -24,7 +26,7 @@ export async function createApp() {
|
||||
bufferLogs: true,
|
||||
});
|
||||
|
||||
app.useBodyParser('raw', { limit: '100mb' });
|
||||
app.useBodyParser('raw', { limit: 100 * OneMB });
|
||||
|
||||
app.useLogger(app.get(AFFiNELogger));
|
||||
|
||||
@@ -36,8 +38,7 @@ export async function createApp() {
|
||||
|
||||
app.use(
|
||||
graphqlUploadExpress({
|
||||
// TODO(@darkskygit): dynamic limit by quota maybe?
|
||||
maxFileSize: 100 * 1024 * 1024,
|
||||
maxFileSize: 100 * OneMB,
|
||||
maxFiles: 32,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -58,7 +58,7 @@ test.after.always(async t => {
|
||||
await t.context.app.close();
|
||||
});
|
||||
|
||||
test.only('should render page success', async t => {
|
||||
test('should render page success', async t => {
|
||||
const docId = randomUUID();
|
||||
const { app, adapter, permission } = t.context;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user