Skip to content

Commit e54f255

Browse files
authored
Merge branch 'main' into 1040-Z-DATA-ERROR-during-push-parsing
2 parents d3ead42 + dcf154f commit e54f255

File tree

2 files changed

+25
-54
lines changed

2 files changed

+25
-54
lines changed

src/proxy/routes/index.ts

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ const proxyFilter: ProxyOptions['filter'] = async (req, res) => {
4747
return false;
4848
}
4949

50+
// For POST pack requests, use the raw body extracted by extractRawBody middleware
51+
if (isPackPost(req) && (req as any).bodyRaw) {
52+
(req as any).body = (req as any).bodyRaw;
53+
// Clean up the bodyRaw property before forwarding the request
54+
delete (req as any).bodyRaw;
55+
}
56+
5057
const action = await executeChain(req, res);
5158

5259
if (action.error || action.blocked) {
@@ -130,7 +137,7 @@ const proxyReqBodyDecorator: ProxyOptions['proxyReqBodyDecorator'] = (bodyConten
130137
return bodyContent;
131138
};
132139

133-
const proxyErrorHandler: ProxyOptions['proxyErrorHandler'] = (err, res, next) => {
140+
const proxyErrorHandler: ProxyOptions['proxyErrorHandler'] = (err, _res, next) => {
134141
console.log(`ERROR=${err}`);
135142
next(err);
136143
};
@@ -139,42 +146,24 @@ const isPackPost = (req: Request) =>
139146
req.method === 'POST' &&
140147
/^(?:\/[^/]+)*\/[^/]+\.git\/(?:git-upload-pack|git-receive-pack)$/.test(req.url);
141148

142-
const teeAndValidate = async (req: Request, res: Response, next: NextFunction) => {
149+
const extractRawBody = async (req: Request, res: Response, next: NextFunction) => {
143150
if (!isPackPost(req)) {
144151
return next();
145152
}
146153

147-
const proxyStream = new PassThrough();
148-
const pluginStream = new PassThrough();
154+
const proxyStream = new PassThrough({
155+
highWaterMark: 4 * 1024 * 1024,
156+
});
157+
const pluginStream = new PassThrough({
158+
highWaterMark: 4 * 1024 * 1024,
159+
});
149160

150161
req.pipe(proxyStream);
151162
req.pipe(pluginStream);
152163

153164
try {
154165
const buf = await getRawBody(pluginStream, { limit: '1gb' });
155-
(req as any).body = buf;
156-
const verdict = await executeChain(req, res);
157-
if (verdict.error || verdict.blocked) {
158-
const message = verdict.errorMessage ?? verdict.blockedMessage ?? 'Unknown error';
159-
const type = verdict.error ? ActionType.ERROR : ActionType.BLOCKED;
160-
161-
logAction(req.url, req.headers?.host, req.headers?.['user-agent'], type, message);
162-
163-
res
164-
.set({
165-
'content-type': 'application/x-git-receive-pack-result',
166-
expires: 'Fri, 01 Jan 1980 00:00:00 GMT',
167-
pragma: 'no-cache',
168-
'cache-control': 'no-cache, max-age=0, must-revalidate',
169-
vary: 'Accept-Encoding',
170-
'x-frame-options': 'DENY',
171-
connection: 'close',
172-
})
173-
.status(200) // return status 200 to ensure that the error message is rendered by the git client
174-
.send(handleMessage(message));
175-
return;
176-
}
177-
166+
(req as any).bodyRaw = buf;
178167
(req as any).pipe = (dest: any, opts: any) => proxyStream.pipe(dest, opts);
179168
next();
180169
} catch (e) {
@@ -186,7 +175,7 @@ const teeAndValidate = async (req: Request, res: Response, next: NextFunction) =
186175

187176
const getRouter = async () => {
188177
const router = Router();
189-
router.use(teeAndValidate);
178+
router.use(extractRawBody);
190179

191180
const originsToProxy = await getAllProxiedHosts();
192181
const proxyKeys: string[] = [];
@@ -261,6 +250,6 @@ export {
261250
handleMessage,
262251
handleRefsErrorMessage,
263252
isPackPost,
264-
teeAndValidate,
253+
extractRawBody,
265254
validGitRequest,
266255
};
Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ const fakeChain = {
99
executeChain: sinon.stub(),
1010
};
1111

12-
const { teeAndValidate, isPackPost, handleMessage } = proxyquire('../src/proxy/routes', {
12+
const { extractRawBody, isPackPost } = proxyquire('../src/proxy/routes', {
1313
'raw-body': fakeRawBody,
1414
'../chain': fakeChain,
1515
});
1616

17-
describe('teeAndValidate middleware', () => {
17+
describe('extractRawBody middleware', () => {
1818
let req;
1919
let res;
2020
let next;
@@ -38,39 +38,21 @@ describe('teeAndValidate middleware', () => {
3838

3939
it('skips non-pack posts', async () => {
4040
req.method = 'GET';
41-
await teeAndValidate(req, res, next);
41+
await extractRawBody(req, res, next);
4242
expect(next.calledOnce).to.be.true;
4343
expect(fakeRawBody.called).to.be.false;
4444
});
4545

46-
it('when the chain blocks it sends a packet and does NOT call next()', async () => {
47-
fakeChain.executeChain.resolves({ blocked: true, blockedMessage: 'denied!' });
48-
49-
req.write('abcd');
50-
req.end();
51-
52-
await teeAndValidate(req, res, next);
53-
54-
expect(fakeRawBody.calledOnce).to.be.true;
55-
expect(fakeChain.executeChain.calledOnce).to.be.true;
56-
expect(next.called).to.be.false;
57-
58-
expect(res.set.called).to.be.true;
59-
expect(res.status.calledWith(200)).to.be.true; // status 200 is used to ensure error message is rendered by git client
60-
expect(res.send.calledWith(handleMessage('denied!'))).to.be.true;
61-
});
62-
63-
it('when the chain allow it calls next() and overrides req.pipe', async () => {
64-
fakeChain.executeChain.resolves({ blocked: false, error: false });
65-
46+
it('extracts raw body and sets bodyRaw property', async () => {
6647
req.write('abcd');
6748
req.end();
6849

69-
await teeAndValidate(req, res, next);
50+
await extractRawBody(req, res, next);
7051

7152
expect(fakeRawBody.calledOnce).to.be.true;
72-
expect(fakeChain.executeChain.calledOnce).to.be.true;
53+
expect(fakeChain.executeChain.called).to.be.false;
7354
expect(next.calledOnce).to.be.true;
55+
expect(req.bodyRaw).to.exist;
7456
expect(typeof req.pipe).to.equal('function');
7557
});
7658
});

0 commit comments

Comments
 (0)