Skip to content

Commit

Permalink
Merge pull request #2462 from murgatroid99/grpc-js-xds_header_match_s…
Browse files Browse the repository at this point in the history
…tring_match

grpc-js-xds: Support string_match in header matching
  • Loading branch information
murgatroid99 committed Jun 2, 2023
2 parents 566034a + 81e1f75 commit 2a11a2c
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 14 deletions.
48 changes: 39 additions & 9 deletions packages/grpc-js-xds/src/matcher.ts
Expand Up @@ -37,14 +37,19 @@ export interface ValueMatcher {
}

export class ExactValueMatcher implements ValueMatcher {
constructor(private targetValue: string) {}
constructor(private targetValue: string, private ignoreCase: boolean) {
}

apply(value: string) {
return value === this.targetValue;
if (this.ignoreCase) {
return value.toLowerCase() === this.targetValue.toLowerCase();
} else {
return value === this.targetValue;
}
}

toString() {
return 'Exact(' + this.targetValue + ')';
return 'Exact(' + this.targetValue + ', ignore_case=' + this.ignoreCase + ')';
}
}

Expand Down Expand Up @@ -94,26 +99,51 @@ export class PresentValueMatcher implements ValueMatcher {
}

export class PrefixValueMatcher implements ValueMatcher {
constructor(private prefix: string) {}
constructor(private prefix: string, private ignoreCase: boolean) {
}

apply(value: string) {
return value.startsWith(this.prefix);
if (this.ignoreCase) {
return value.toLowerCase().startsWith(this.prefix.toLowerCase());
} else {
return value.startsWith(this.prefix);
}
}

toString() {
return 'Prefix(' + this.prefix + ')';
return 'Prefix(' + this.prefix + ', ignore_case=' + this.ignoreCase + ')';
}
}

export class SuffixValueMatcher implements ValueMatcher {
constructor(private suffix: string) {}
constructor(private suffix: string, private ignoreCase: boolean) {}

apply(value: string) {
return value.endsWith(this.suffix);
if (this.ignoreCase) {
return value.toLowerCase().endsWith(this.suffix.toLowerCase());
} else {
return value.endsWith(this.suffix);
}
}

toString() {
return 'Suffix(' + this.suffix + ', ignore_case=' + this.ignoreCase + ')';
}
}

export class ContainsValueMatcher implements ValueMatcher {
constructor(private contains: string, private ignoreCase: boolean) {}

apply(value: string) {
if (this.ignoreCase) {
return value.toLowerCase().includes(this.contains.toLowerCase());
} else {
return value.includes(this.contains);
}
}

toString() {
return 'Suffix(' + this.suffix + ')';
return 'Contains(' + this.contains + + ', ignore_case=' + this.ignoreCase + ')';
}
}

Expand Down
28 changes: 24 additions & 4 deletions packages/grpc-js-xds/src/resolver-xds.ts
Expand Up @@ -37,7 +37,7 @@ import { HeaderMatcher__Output } from './generated/envoy/config/route/v3/HeaderM
import ConfigSelector = experimental.ConfigSelector;
import LoadBalancingConfig = experimental.LoadBalancingConfig;
import { XdsClusterManagerLoadBalancingConfig } from './load-balancer-xds-cluster-manager';
import { ExactValueMatcher, FullMatcher, HeaderMatcher, Matcher, PathExactValueMatcher, PathPrefixValueMatcher, PathSafeRegexValueMatcher, PrefixValueMatcher, PresentValueMatcher, RangeValueMatcher, RejectValueMatcher, SafeRegexValueMatcher, SuffixValueMatcher, ValueMatcher } from './matcher';
import { ContainsValueMatcher, ExactValueMatcher, FullMatcher, HeaderMatcher, Matcher, PathExactValueMatcher, PathPrefixValueMatcher, PathSafeRegexValueMatcher, PrefixValueMatcher, PresentValueMatcher, RangeValueMatcher, RejectValueMatcher, SafeRegexValueMatcher, SuffixValueMatcher, ValueMatcher } from './matcher';
import { envoyFractionToFraction, Fraction } from "./fraction";
import { RouteAction, SingleClusterRouteAction, WeightedCluster, WeightedClusterRouteAction } from './route-action';
import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL } from './resources';
Expand Down Expand Up @@ -136,7 +136,7 @@ function getPredicateForHeaderMatcher(headerMatch: HeaderMatcher__Output): Match
let valueChecker: ValueMatcher;
switch (headerMatch.header_match_specifier) {
case 'exact_match':
valueChecker = new ExactValueMatcher(headerMatch.exact_match!);
valueChecker = new ExactValueMatcher(headerMatch.exact_match!, false);
break;
case 'safe_regex_match':
valueChecker = new SafeRegexValueMatcher(headerMatch.safe_regex_match!.regex);
Expand All @@ -150,10 +150,30 @@ function getPredicateForHeaderMatcher(headerMatch: HeaderMatcher__Output): Match
valueChecker = new PresentValueMatcher();
break;
case 'prefix_match':
valueChecker = new PrefixValueMatcher(headerMatch.prefix_match!);
valueChecker = new PrefixValueMatcher(headerMatch.prefix_match!, false);
break;
case 'suffix_match':
valueChecker = new SuffixValueMatcher(headerMatch.suffix_match!);
valueChecker = new SuffixValueMatcher(headerMatch.suffix_match!, false);
break;
case 'string_match':
const stringMatch = headerMatch.string_match!
switch (stringMatch.match_pattern) {
case 'exact':
valueChecker = new ExactValueMatcher(stringMatch.exact!, stringMatch.ignore_case);
break;
case 'safe_regex':
valueChecker = new SafeRegexValueMatcher(stringMatch.safe_regex!.regex);
break;
case 'prefix':
valueChecker = new PrefixValueMatcher(stringMatch.prefix!, stringMatch.ignore_case);
break;
case 'suffix':
valueChecker = new SuffixValueMatcher(stringMatch.suffix!, stringMatch.ignore_case);
break;
case 'contains':
valueChecker = new ContainsValueMatcher(stringMatch.contains!, stringMatch.ignore_case);
break;
}
break;
default:
valueChecker = new RejectValueMatcher();
Expand Down
3 changes: 2 additions & 1 deletion packages/grpc-js-xds/src/xds-stream-state/rds-state.ts
Expand Up @@ -29,7 +29,8 @@ const SUPPPORTED_HEADER_MATCH_SPECIFIERS = [
'range_match',
'present_match',
'prefix_match',
'suffix_match'];
'suffix_match',
'string_match'];
const SUPPORTED_CLUSTER_SPECIFIERS = ['cluster', 'weighted_clusters', 'cluster_header'];

const UINT32_MAX = 0xFFFFFFFF;
Expand Down

0 comments on commit 2a11a2c

Please sign in to comment.