Use more efficient strategies to process user input (#196858)

## Summary

Address performance concerns with Regexps
This commit is contained in:
Gerard Soldevila 2024-10-22 14:07:25 +02:00 committed by GitHub
parent 2a085e103a
commit c9637cf71c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 64 additions and 11 deletions

View file

@ -14,11 +14,23 @@ function isEmptyPathname(pathname: string): boolean {
}
function removeTailSlashes(pathname: string): string {
return pathname.replace(/\/+$/, '');
let updated = pathname;
while (updated.endsWith('/')) {
updated = updated.substring(0, updated.length - 1);
}
return updated;
}
function removeLeadSlashes(pathname: string): string {
return pathname.replace(/^\/+/, '');
let updated = pathname;
while (updated.startsWith('/')) {
updated = updated.substring(1);
}
return updated;
}
export function removeSurroundingSlashes(pathname: string): string {

View file

@ -8,6 +8,7 @@
*/
import {
hasAllKeywordsInOrder,
isClusterShardLimitExceeded,
isIncompatibleMappingException,
isIndexNotFoundException,
@ -128,3 +129,31 @@ describe('isClusterShardLimitExceeded', () => {
expect(isClusterShardLimitExceeded(undefined)).toEqual(false);
});
});
describe('hasAllKeywordsInOrder', () => {
it('returns false if not all keywords are present', () => {
expect(
hasAllKeywordsInOrder('some keywords in a message', ['some', 'in', 'message', 'missing'])
).toEqual(false);
});
it('returns false if keywords are not in the right order', () => {
expect(
hasAllKeywordsInOrder('some keywords in a message', ['some', 'message', 'keywords'])
).toEqual(false);
});
it('returns false if the message is empty', () => {
expect(hasAllKeywordsInOrder('', ['some', 'message', 'keywords'])).toEqual(false);
});
it('returns false if the keyword list is empty', () => {
expect(hasAllKeywordsInOrder('some keywords in a message', [])).toEqual(false);
});
it('returns true if keywords are present and in the right order', () => {
expect(
hasAllKeywordsInOrder('some keywords in a message', ['some', 'keywords', 'in', 'message'])
).toEqual(true);
});
});

View file

@ -7,16 +7,16 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import type { ErrorCause } from '@elastic/elasticsearch/lib/api/types';
export const isWriteBlockException = (errorCause?: estypes.ErrorCause): boolean => {
export const isWriteBlockException = (errorCause?: ErrorCause): boolean => {
return (
errorCause?.type === 'cluster_block_exception' &&
errorCause?.reason?.match(/index \[.+] blocked by: \[FORBIDDEN\/8\/.+ \(api\)\]/) !== null
hasAllKeywordsInOrder(errorCause?.reason, ['index [', '] blocked by: [FORBIDDEN/8/', ' (api)]'])
);
};
export const isIncompatibleMappingException = (errorCause?: estypes.ErrorCause): boolean => {
export const isIncompatibleMappingException = (errorCause?: ErrorCause): boolean => {
return (
errorCause?.type === 'strict_dynamic_mapping_exception' ||
errorCause?.type === 'mapper_parsing_exception' ||
@ -24,17 +24,29 @@ export const isIncompatibleMappingException = (errorCause?: estypes.ErrorCause):
);
};
export const isIndexNotFoundException = (errorCause?: estypes.ErrorCause): boolean => {
export const isIndexNotFoundException = (errorCause?: ErrorCause): boolean => {
return errorCause?.type === 'index_not_found_exception';
};
export const isClusterShardLimitExceeded = (errorCause?: estypes.ErrorCause): boolean => {
export const isClusterShardLimitExceeded = (errorCause?: ErrorCause): boolean => {
// traditional ES: validation_exception. serverless ES: illegal_argument_exception
return (
(errorCause?.type === 'validation_exception' ||
errorCause?.type === 'illegal_argument_exception') &&
errorCause?.reason?.match(
/this action would add .* shards, but this cluster currently has .* maximum normal shards open/
) !== null
hasAllKeywordsInOrder(errorCause?.reason, [
'this action would add',
'shards, but this cluster currently has',
'maximum normal shards open',
])
);
};
export const hasAllKeywordsInOrder = (message: string | undefined, keywords: string[]): boolean => {
if (!message || !keywords.length) {
return false;
}
const keywordIndices = keywords.map((keyword) => message?.indexOf(keyword) ?? -1);
// check that all keywords are present and in the right order
return keywordIndices.every((v, i, a) => v >= 0 && (!i || a[i - 1] <= v));
};