mirror of
https://github.com/ONLYOFFICE/server.git
synced 2026-02-10 18:05:07 +08:00
[feature] Add requestDefault parameters
This commit is contained in:
@ -320,8 +320,8 @@
|
||||
"User-Agent": "Node.js/6.13",
|
||||
"Connection": "Keep-Alive"
|
||||
},
|
||||
"decompress": true,
|
||||
"rejectUnauthorized": true
|
||||
"gzip": true,
|
||||
"rejectUnauthorized": true
|
||||
},
|
||||
"autoAssembly": {
|
||||
"enable": false,
|
||||
|
||||
@ -296,6 +296,7 @@ function isAllowDirectRequest(ctx, uri, isInJwtToken) {
|
||||
}
|
||||
function addExternalRequestOptions(ctx, uri, isInJwtToken, options) {
|
||||
let res = false;
|
||||
const tenTenantRequestDefaults = ctx.getCfg('services.CoAuthoring.requestDefaults', cfgRequestDefaults);
|
||||
const tenExternalRequestAction = ctx.getCfg('externalRequest.action', cfgExternalRequestAction);
|
||||
const tenRequestFilteringAgent = ctx.getCfg('services.CoAuthoring.request-filtering-agent', cfgRequesFilteringAgent);
|
||||
if (isAllowDirectRequest(ctx, uri, isInJwtToken)) {
|
||||
@ -316,6 +317,10 @@ function addExternalRequestOptions(ctx, uri, isInJwtToken, options) {
|
||||
agentOptions.port = parsedProxyUrl.port;
|
||||
agentOptions.protocol = parsedProxyUrl.protocol;
|
||||
}
|
||||
|
||||
if (tenTenantRequestDefaults.forever !== undefined) {
|
||||
agentOptions.keepAlive = !!tenTenantRequestDefaults.forever;
|
||||
}
|
||||
|
||||
if (uri.startsWith('https:')) {
|
||||
options.httpsAgent = new RequestFilteringHttpsAgent(agentOptions);
|
||||
@ -348,6 +353,11 @@ async function downloadUrlPromise(ctx, uri, optTimeout, optLimit, opt_Authorizat
|
||||
uri = URI.serialize(URI.parse(uri));
|
||||
const connectionAndInactivity = optTimeout?.connectionAndInactivity ? ms(optTimeout.connectionAndInactivity) : undefined;
|
||||
const options = config.util.cloneDeep(tenTenantRequestDefaults);
|
||||
if (options.gzip !== undefined && !options.gzip) {
|
||||
options.headers = options.headers || {};
|
||||
options.headers['Accept-Encoding'] = 'identity';
|
||||
delete options.gzip;
|
||||
}
|
||||
if (!exports.addExternalRequestOptions(ctx, uri, opt_filterPrivate, options)) {
|
||||
throw new Error('Block external request. See externalRequest config options');
|
||||
}
|
||||
@ -355,6 +365,9 @@ async function downloadUrlPromise(ctx, uri, optTimeout, optLimit, opt_Authorizat
|
||||
const protocol = new URL(uri).protocol;
|
||||
if (!options.httpsAgent && !options.httpAgent) {
|
||||
const agentOptions = { ...https.globalAgent.options, rejectUnauthorized: tenTenantRequestDefaults.rejectUnauthorized === false? false : true};
|
||||
if (tenTenantRequestDefaults.forever !== undefined) {
|
||||
agentOptions.keepAlive = !!tenTenantRequestDefaults.forever;
|
||||
}
|
||||
if (protocol === 'https:') {
|
||||
options.httpsAgent = new https.Agent(agentOptions);
|
||||
} else if (protocol === 'http:') {
|
||||
@ -536,6 +549,13 @@ async function postRequestPromise(ctx, uri, postData, postDataStream, postDataSi
|
||||
timeout: connectionAndInactivity,
|
||||
validateStatus: (status) => status === 200 || status === 204
|
||||
});
|
||||
|
||||
if (options.gzip !== undefined && !options.gzip) {
|
||||
options.headers = options.headers || {};
|
||||
options.headers['Accept-Encoding'] = 'identity';
|
||||
delete options.gzip;
|
||||
}
|
||||
|
||||
if (!addExternalRequestOptions(ctx, uri, opt_isInJwtToken, options)) {
|
||||
throw new Error('Block external request. See externalRequest config options');
|
||||
}
|
||||
@ -545,6 +565,11 @@ async function postRequestPromise(ctx, uri, postData, postDataStream, postDataSi
|
||||
...https.globalAgent.options,
|
||||
rejectUnauthorized: tenTenantRequestDefaults.rejectUnauthorized === false ? false : true
|
||||
};
|
||||
|
||||
if (tenTenantRequestDefaults.forever !== undefined) {
|
||||
agentOptions.keepAlive = !!tenTenantRequestDefaults.forever;
|
||||
}
|
||||
|
||||
if (protocol === 'https:') {
|
||||
options.httpsAgent = new https.Agent(agentOptions);
|
||||
} else if (protocol === 'http:') {
|
||||
|
||||
@ -152,6 +152,35 @@ describe('HTTP Request Integration Tests', () => {
|
||||
const buffer = Buffer.alloc(2097152);
|
||||
res.send(buffer);
|
||||
});
|
||||
app.get('/api/headers', (req, res) => {
|
||||
// Ensure you're only sending headers, which won't contain circular references
|
||||
res.json({ headers: req.headers });
|
||||
});
|
||||
|
||||
// Endpoint that returns connection header info
|
||||
app.get('/api/connection', (req, res) => {
|
||||
res.json({
|
||||
connection: req.headers.connection,
|
||||
keepAlive: req.headers.connection?.toLowerCase() === 'keep-alive'
|
||||
});
|
||||
});
|
||||
|
||||
// Endpoint that returns only the accept-encoding header
|
||||
app.get('/api/accept-encoding', (req, res) => {
|
||||
res.json({
|
||||
acceptEncoding: req.headers['accept-encoding'] || null
|
||||
});
|
||||
});
|
||||
|
||||
// Endpoint that returns only the connection header
|
||||
app.get('/api/connection-header', (req, res) => {
|
||||
const connectionHeader = req.headers['connection'] || '';
|
||||
res.json({
|
||||
connection: connectionHeader,
|
||||
keepAlive: connectionHeader.toLowerCase() === 'keep-alive'
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Start server
|
||||
server = http.createServer(app);
|
||||
@ -336,6 +365,163 @@ describe('HTTP Request Integration Tests', () => {
|
||||
null
|
||||
)).rejects.toThrow('Error response: content-length:2097152');
|
||||
});
|
||||
|
||||
test('enables compression when gzip is true', async () => {
|
||||
// Setup a simple server that captures headers
|
||||
let capturedHeaders = {};
|
||||
const app = express();
|
||||
app.get('/test', (req, res) => {
|
||||
capturedHeaders = {
|
||||
acceptEncoding: req.headers['accept-encoding']
|
||||
};
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
const testServer = http.createServer(app);
|
||||
const testPort = PORT + 1000;
|
||||
await new Promise(resolve => testServer.listen(testPort, resolve));
|
||||
|
||||
try {
|
||||
const mockCtx = createMockContext({
|
||||
'services.CoAuthoring.requestDefaults': {
|
||||
headers: { "User-Agent": "Node.js/6.13" },
|
||||
gzip: true,
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
});
|
||||
|
||||
await utils.downloadUrlPromise(
|
||||
mockCtx,
|
||||
`http://localhost:${testPort}/test`,
|
||||
{ wholeCycle: '2s' },
|
||||
1024 * 1024,
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
// When gzip is true, 'accept-encoding' should include 'gzip'
|
||||
expect(capturedHeaders.acceptEncoding).toBeDefined();
|
||||
expect(capturedHeaders.acceptEncoding).toMatch(/gzip/i);
|
||||
} finally {
|
||||
await new Promise(resolve => testServer.close(resolve));
|
||||
}
|
||||
});
|
||||
|
||||
test('disables compression when gzip is false', async () => {
|
||||
// Setup a simple server that captures headers
|
||||
let capturedHeaders = {};
|
||||
const app = express();
|
||||
app.get('/test', (req, res) => {
|
||||
capturedHeaders = {
|
||||
acceptEncoding: req.headers['accept-encoding']
|
||||
};
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
const testServer = http.createServer(app);
|
||||
const testPort = PORT + 1001;
|
||||
await new Promise(resolve => testServer.listen(testPort, resolve));
|
||||
|
||||
try {
|
||||
const mockCtx = createMockContext({
|
||||
'services.CoAuthoring.requestDefaults': {
|
||||
headers: { "User-Agent": "Node.js/6.13" },
|
||||
gzip: false,
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
});
|
||||
|
||||
await utils.downloadUrlPromise(
|
||||
mockCtx,
|
||||
`http://localhost:${testPort}/test`,
|
||||
{ wholeCycle: '2s' },
|
||||
1024 * 1024,
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
expect(capturedHeaders.acceptEncoding === 'identity' || capturedHeaders.acceptEncoding === undefined).toBe(true);
|
||||
} finally {
|
||||
await new Promise(resolve => testServer.close(resolve));
|
||||
}
|
||||
});
|
||||
|
||||
test('enables keep-alive when forever is true', async () => {
|
||||
// Setup a simple server that captures headers
|
||||
let capturedHeaders = {};
|
||||
const app = express();
|
||||
app.get('/test', (req, res) => {
|
||||
capturedHeaders = {
|
||||
connection: req.headers['connection']
|
||||
};
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
const testServer = http.createServer(app);
|
||||
const testPort = PORT + 1002;
|
||||
await new Promise(resolve => testServer.listen(testPort, resolve));
|
||||
|
||||
try {
|
||||
const mockCtx = createMockContext({
|
||||
'services.CoAuthoring.requestDefaults': {
|
||||
headers: { "User-Agent": "Node.js/6.13" },
|
||||
forever: true,
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
});
|
||||
|
||||
await utils.downloadUrlPromise(
|
||||
mockCtx,
|
||||
`http://localhost:${testPort}/test`,
|
||||
{ wholeCycle: '2s' },
|
||||
1024 * 1024,
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
// When forever is true, connection should be 'keep-alive'
|
||||
expect(capturedHeaders.connection?.toLowerCase()).toMatch(/keep-alive/i);
|
||||
} finally {
|
||||
await new Promise(resolve => testServer.close(resolve));
|
||||
}
|
||||
});
|
||||
|
||||
test('disables keep-alive when forever is false', async () => {
|
||||
const mockCtx = createMockContext({
|
||||
'services.CoAuthoring.requestDefaults': {
|
||||
headers: {
|
||||
"User-Agent": "Node.js/6.13"
|
||||
},
|
||||
forever: false,
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
});
|
||||
|
||||
const result = await utils.downloadUrlPromise(
|
||||
mockCtx,
|
||||
`${BASE_URL}/api/connection-header`,
|
||||
{ wholeCycle: '5s', connectionAndInactivity: '3s' },
|
||||
1024 * 1024,
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
const responseData = JSON.parse(result.body.toString());
|
||||
|
||||
// When forever is false, connection should NOT be 'keep-alive'
|
||||
// Note: Different HTTP clients might handle this differently,
|
||||
// so we're checking that keepAlive is false
|
||||
expect(responseData.keepAlive).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
test('handles binary data correctly', async () => {
|
||||
@ -768,5 +954,94 @@ describe('HTTP Request Integration Tests', () => {
|
||||
expect(error).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
test('applies gzip setting to POST requests', async () => {
|
||||
// Setup a simple server that captures headers
|
||||
let capturedHeaders = {};
|
||||
const app = express();
|
||||
app.post('/test', express.json(), (req, res) => {
|
||||
capturedHeaders = {
|
||||
acceptEncoding: req.headers['accept-encoding']
|
||||
};
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
const testServer = http.createServer(app);
|
||||
const testPort = PORT + 1003;
|
||||
await new Promise(resolve => testServer.listen(testPort, resolve));
|
||||
|
||||
try {
|
||||
const mockCtx = createMockContext({
|
||||
'services.CoAuthoring.requestDefaults': {
|
||||
headers: { "User-Agent": "Node.js/6.13" },
|
||||
gzip: false,
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
});
|
||||
|
||||
const postData = JSON.stringify({ test: 'data' });
|
||||
|
||||
await utils.postRequestPromise(
|
||||
mockCtx,
|
||||
`http://localhost:${testPort}/test`,
|
||||
postData,
|
||||
null,
|
||||
postData.length,
|
||||
{ wholeCycle: '2s' },
|
||||
null,
|
||||
false,
|
||||
{ 'Content-Type': 'application/json' }
|
||||
);
|
||||
|
||||
expect(capturedHeaders.acceptEncoding === 'identity' || capturedHeaders.acceptEncoding === undefined).toBe(true);
|
||||
} finally {
|
||||
await new Promise(resolve => testServer.close(resolve));
|
||||
}
|
||||
});
|
||||
|
||||
test('applies forever setting to POST requests', async () => {
|
||||
// Setup a simple server that captures headers
|
||||
let capturedHeaders = {};
|
||||
const app = express();
|
||||
app.post('/test', express.json(), (req, res) => {
|
||||
capturedHeaders = {
|
||||
connection: req.headers['connection']
|
||||
};
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
const testServer = http.createServer(app);
|
||||
const testPort = PORT + 1004;
|
||||
await new Promise(resolve => testServer.listen(testPort, resolve));
|
||||
|
||||
try {
|
||||
const mockCtx = createMockContext({
|
||||
'services.CoAuthoring.requestDefaults': {
|
||||
headers: { "User-Agent": "Node.js/6.13" },
|
||||
forever: true,
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
});
|
||||
|
||||
const postData = JSON.stringify({ test: 'data' });
|
||||
|
||||
await utils.postRequestPromise(
|
||||
mockCtx,
|
||||
`http://localhost:${testPort}/test`,
|
||||
postData,
|
||||
null,
|
||||
postData.length,
|
||||
{ wholeCycle: '2s' },
|
||||
null,
|
||||
false,
|
||||
{ 'Content-Type': 'application/json' }
|
||||
);
|
||||
|
||||
// When forever is true, connection should be 'keep-alive'
|
||||
expect(capturedHeaders.connection?.toLowerCase()).toMatch(/keep-alive/i);
|
||||
} finally {
|
||||
await new Promise(resolve => testServer.close(resolve));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user