Skip to content

Commit

Permalink
feat(appmesh): rename the class HttpHeaderMatch to HeaderMatch (#15468)
Browse files Browse the repository at this point in the history
- Renaming the `HttpHeaderMatch` class to `HeaderMatch`.
- Adding `validateMatchArrayLength` function to check the number of headers

BREAKING CHANGE: the class `HttpHeaderMatch` has been renamed to `HeaderMatch`

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
Seiya6329 authored Jul 9, 2021
1 parent bf656e4 commit d88b45e
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 186 deletions.
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-appmesh/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,8 @@ router.addRoute('route-http2', {
protocol: appmesh.HttpRouteProtocol.HTTPS,
headers: [
// All specified headers must match for the route to match.
appmesh.HttpHeaderMatch.valueIs('Content-Type', 'application/json'),
appmesh.HttpHeaderMatch.valueIsNot('Content-Type', 'application/json'),
appmesh.HeaderMatch.valueIs('Content-Type', 'application/json'),
appmesh.HeaderMatch.valueIsNot('Content-Type', 'application/json'),
]
},
}),
Expand Down
167 changes: 167 additions & 0 deletions packages/@aws-cdk/aws-appmesh/lib/header-match.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { CfnRoute } from './index';

// keep this import separate from other imports to reduce chance for merge conflicts with v2-main
// eslint-disable-next-line no-duplicate-imports, import/order
import { Construct } from '@aws-cdk/core';

/**
* Configuration for `HeaderMatch`
*/
export interface HeaderMatchConfig {
/**
* Route CFN configuration for the route header match.
*/
readonly headerMatch: CfnRoute.HttpRouteHeaderProperty;
}

/**
* Used to generate header matching methods.
*/
export abstract class HeaderMatch {
/**
* The value of the header with the given name in the request must match the
* specified value exactly.
*
* @param headerName the name of the header to match against
* @param headerValue The exact value to test against
*/
public static valueIs(headerName: string, headerValue: string): HeaderMatch {
return new HeaderMatchImpl(headerName, false, { exact: headerValue });
}

/**
* The value of the header with the given name in the request must not match
* the specified value exactly.
*
* @param headerName the name of the header to match against
* @param headerValue The exact value to test against
*/
public static valueIsNot(headerName: string, headerValue: string): HeaderMatch {
return new HeaderMatchImpl(headerName, true, { exact: headerValue });
}

/**
* The value of the header with the given name in the request must start with
* the specified characters.
*
* @param headerName the name of the header to match against
* @param prefix The prefix to test against
*/
public static valueStartsWith(headerName: string, prefix: string): HeaderMatch {
return new HeaderMatchImpl(headerName, false, { prefix });
}

/**
* The value of the header with the given name in the request must not start
* with the specified characters.
*
* @param headerName the name of the header to match against
* @param prefix The prefix to test against
*/
public static valueDoesNotStartWith(headerName: string, prefix: string): HeaderMatch {
return new HeaderMatchImpl(headerName, true, { prefix });
}

/**
* The value of the header with the given name in the request must end with
* the specified characters.
*
* @param headerName the name of the header to match against
* @param suffix The suffix to test against
*/
public static valueEndsWith(headerName: string, suffix: string): HeaderMatch {
return new HeaderMatchImpl(headerName, false, { suffix });
}

/**
* The value of the header with the given name in the request must not end
* with the specified characters.
*
* @param headerName the name of the header to match against
* @param suffix The suffix to test against
*/
public static valueDoesNotEndWith(headerName: string, suffix: string): HeaderMatch {
return new HeaderMatchImpl(headerName, true, { suffix });
}

/**
* The value of the header with the given name in the request must include
* the specified characters.
*
* @param headerName the name of the header to match against
* @param regex The regex to test against
*/
public static valueMatchesRegex(headerName: string, regex: string): HeaderMatch {
return new HeaderMatchImpl(headerName, false, { regex });
}

/**
* The value of the header with the given name in the request must not
* include the specified characters.
*
* @param headerName the name of the header to match against
* @param regex The regex to test against
*/
public static valueDoesNotMatchRegex(headerName: string, regex: string): HeaderMatch {
return new HeaderMatchImpl(headerName, true, { regex });
}

/**
* The value of the header with the given name in the request must be in a
* range of values.
*
* @param headerName the name of the header to match against
* @param start Match on values starting at and including this value
* @param end Match on values up to but not including this value
*/
public static valuesIsInRange(headerName: string, start: number, end: number): HeaderMatch {
return new HeaderMatchImpl(headerName, false, {
range: {
start,
end,
},
});
}

/**
* The value of the header with the given name in the request must not be in
* a range of values.
*
* @param headerName the name of the header to match against
* @param start Match on values starting at and including this value
* @param end Match on values up to but not including this value
*/
public static valuesIsNotInRange(headerName: string, start: number, end: number): HeaderMatch {
return new HeaderMatchImpl(headerName, true, {
range: {
start,
end,
},
});
}

/**
* Returns the header match configuration.
*/
public abstract bind(scope: Construct): HeaderMatchConfig;
}

class HeaderMatchImpl extends HeaderMatch {
constructor(
private readonly headerName: string,
private readonly invert: boolean,
private readonly matchProperty: CfnRoute.HeaderMatchMethodProperty,
) {
super();
}

bind(_scope: Construct): HeaderMatchConfig {
return {
headerMatch: {
name: this.headerName,
invert: this.invert,
match: this.matchProperty,
},
};
}
}
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-appmesh/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export * from './listener-tls-options';
export * from './tls-validation';
export * from './tls-client-policy';
export * from './http-route-method';
export * from './header-match';
13 changes: 13 additions & 0 deletions packages/@aws-cdk/aws-appmesh/lib/private/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Token, TokenComparison } from '@aws-cdk/core';
import { CfnVirtualNode } from '../appmesh.generated';
import { HeaderMatch } from '../header-match';
import { ListenerTlsOptions } from '../listener-tls-options';
import { TlsClientPolicy } from '../tls-client-policy';

Expand Down Expand Up @@ -92,3 +93,15 @@ export function renderMeshOwner(resourceAccount: string, meshAccount: string) :
? meshAccount
: undefined;
}

/**
* This is the helper method to validate the length of match array when it is specified.
*/
export function validateMatchArrayLength(headers?: HeaderMatch[]) {
const MIN_LENGTH = 1;
const MAX_LENGTH = 10;

if (headers && (headers.length < MIN_LENGTH || headers.length > MAX_LENGTH)) {
throw new Error(`Number of headers provided for matching must be between ${MIN_LENGTH} and ${MAX_LENGTH}, got: ${headers.length}`);
}
}
Loading

0 comments on commit d88b45e

Please sign in to comment.