Skip to content

Apigw ng implement header remapping #11237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Jul 23, 2024

Conversation

cloutierMat
Copy link
Contributor

@cloutierMat cloutierMat commented Jul 19, 2024

Motivation

This PR aims at bringing a higher level of parity with apigateway headers. Some headers when not passed through appropriately will fail the invocation.

As noted on the Important Notes of the Api Gateway documention, some headers are either, dropped, passthrough or remapped from the users requests and following data transformations.

Changes

A series of header manipulation in the handlers was added.

Invocation

(parsing handler)

Request

( integration request handler)

  • For HTTP_PPROXY integration, while most headers available to the context are passed through to the integration request, some seem to be removed BEFORE applying the mapping templates.
  • A set of headers will raise an InternalServerError if modified by request parameters of mapping templates. Even for AWS_PROXY where they are not applied, go figure 😄
  • Some request headers are dropped after being applied.
  • Some request headers are default and we only apply them if not already set by the templates

Response

( method response handler)

  • Some headers are remapped with x-amzn-Remapped-
  • Some headers are dropped
  • Some headers are added as default if not set by the integration response. For example, Connection, seems to be taking from the original requests Connection

@cloutierMat cloutierMat self-assigned this Jul 19, 2024
@cloutierMat cloutierMat added aws:apigateway Amazon API Gateway semver: patch Non-breaking changes which can be included in patch releases labels Jul 19, 2024
@cloutierMat cloutierMat added this to the 3.6 milestone Jul 19, 2024
Copy link

github-actions bot commented Jul 19, 2024

LocalStack Community integration with Pro

    2 files  ± 0      2 suites  ±0   1h 36m 9s ⏱️ -3s
3 299 tests +88  2 908 ✅ +85  391 💤 +3  0 ❌ ±0 
3 301 runs  +88  2 908 ✅ +85  393 💤 +3  0 ❌ ±0 

Results for commit 29f4f64. ± Comparison against base commit 4928fe8.

This pull request removes 54 and adds 142 tests. Note that renamed tests count towards both.
tests.aws.services.events.test_events_rules ‑ test_put_event_with_content_base_rule_in_pattern
tests.aws.services.events.test_events_rules ‑ test_put_events_with_rule_anything_but_to_sqs
tests.aws.services.events.test_events_rules ‑ test_put_events_with_rule_exists_false_to_sqs
tests.aws.services.events.test_events_rules ‑ test_put_events_with_rule_exists_true_to_sqs
tests.aws.services.events.test_events_rules ‑ test_put_rule
tests.aws.services.events.test_events_rules ‑ test_rule_disable
tests.aws.services.events.test_events_rules ‑ test_verify_rule_event_content
tests.aws.services.lambda_.test_lambda_integration_dynamodbstreams.TestDynamoDBEventSourceMapping ‑ test_deletion_event_source_mapping_with_dynamodb
tests.aws.services.lambda_.test_lambda_integration_dynamodbstreams.TestDynamoDBEventSourceMapping ‑ test_disabled_dynamodb_event_source_mapping
tests.aws.services.lambda_.test_lambda_integration_dynamodbstreams.TestDynamoDBEventSourceMapping ‑ test_duplicate_event_source_mappings
…
tests.aws.services.apigateway.test_apigateway_integrations.TestApiGatewayHeaderRemapping ‑ test_apigateway_header_remapping_aws[AWS]
tests.aws.services.apigateway.test_apigateway_integrations.TestApiGatewayHeaderRemapping ‑ test_apigateway_header_remapping_aws[AWS_PROXY]
tests.aws.services.apigateway.test_apigateway_integrations.TestApiGatewayHeaderRemapping ‑ test_apigateway_header_remapping_http[HTTP]
tests.aws.services.apigateway.test_apigateway_integrations.TestApiGatewayHeaderRemapping ‑ test_apigateway_header_remapping_http[HTTP_PROXY]
tests.aws.services.cloudformation.resources.test_ec2 ‑ test_ec2_security_group_id_with_vpc
tests.aws.services.lambda_.event_source_mapping.test_lambda_integration_dynamodbstreams.TestDynamoDBEventSourceMapping ‑ test_deletion_event_source_mapping_with_dynamodb
tests.aws.services.lambda_.event_source_mapping.test_lambda_integration_dynamodbstreams.TestDynamoDBEventSourceMapping ‑ test_disabled_dynamodb_event_source_mapping
tests.aws.services.lambda_.event_source_mapping.test_lambda_integration_dynamodbstreams.TestDynamoDBEventSourceMapping ‑ test_duplicate_event_source_mappings
tests.aws.services.lambda_.event_source_mapping.test_lambda_integration_dynamodbstreams.TestDynamoDBEventSourceMapping ‑ test_dynamodb_event_filter[content_filter_type]
tests.aws.services.lambda_.event_source_mapping.test_lambda_integration_dynamodbstreams.TestDynamoDBEventSourceMapping ‑ test_dynamodb_event_filter[content_multiple_filters]
…
This pull request removes 2 skipped tests and adds 5 skipped tests. Note that renamed tests count towards both.
tests.aws.services.events.test_events_rules ‑ test_verify_rule_event_content
tests.aws.services.lambda_.test_lambda_integration_kinesis.TestKinesisSource ‑ test_kinesis_event_source_mapping_with_async_invocation
tests.aws.services.apigateway.test_apigateway_integrations.TestApiGatewayHeaderRemapping ‑ test_apigateway_header_remapping_aws[AWS]
tests.aws.services.apigateway.test_apigateway_integrations.TestApiGatewayHeaderRemapping ‑ test_apigateway_header_remapping_aws[AWS_PROXY]
tests.aws.services.apigateway.test_apigateway_integrations.TestApiGatewayHeaderRemapping ‑ test_apigateway_header_remapping_http[HTTP]
tests.aws.services.apigateway.test_apigateway_integrations.TestApiGatewayHeaderRemapping ‑ test_apigateway_header_remapping_http[HTTP_PROXY]
tests.aws.services.lambda_.event_source_mapping.test_lambda_integration_kinesis.TestKinesisSource ‑ test_kinesis_event_source_mapping_with_async_invocation

♻️ This comment has been updated with latest results.

@cloutierMat cloutierMat marked this pull request as ready for review July 19, 2024 21:35
@cloutierMat cloutierMat force-pushed the apigw-ng-implement-header-remapping branch from 90ca21d to 254c093 Compare July 19, 2024 21:44
Copy link
Contributor

@bentsku bentsku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, that is a lot of work! Impressive tests, they really cover a lot of ground here.

I'm a bit torn about the headers helper file, as some of those methods are very tied to their handler and integration, and I'm wondering if it would maybe make more sense to have them in the handler directly, as they most probably won't be able to be re-used as is. We could keep the base header manipulation utils there, and move the "handler" specific methods directly there? What do you think? It feels like having helpers at first made sense, but now that there is a lot of integration specific (that we didn't expect), maybe it could be simpler and more contained.

Also, the fact that one is used for both exceptions and invocations makes me want to create a response handler for those, maybe it could simplify it a bit. It's not a big deal if the header doesn't do a lot, I think it might even be a good thing! 😄

We could also attach the integration type to the context in the request routing, I think that could be worth it as we access it quite often now.

All in all, this is really great work, you really went above and beyond here 🚀

@cloutierMat
Copy link
Contributor Author

Thanks for the review @bentsku. I agree that the headers helper is doing a bit more than it should really. You are right that in the and, most of the methods are tightly coupled with their integrations. I will move those methods in their respective handlers and keep only the shared methods in there

@cloutierMat cloutierMat requested a review from bentsku July 23, 2024 01:43
Copy link
Contributor

@bentsku bentsku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, nice changes! Thanks a lot for addressing my concerns, this looks really good! The PR felt very easy to parse and understand, that was a lot of work! Congrats!
I just have minor comments, but nothing too major. After the questions are answered, this can be merged 😄 LGTM!

error = self.create_exception_response(exception, context)
if error:
response.update_from(error)

@staticmethod
def set_error_context(exception: BaseGatewayException, context: RestApiInvocationContext):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so neat 👌

# TODO apply responseParameters to the headers and get content-type from the gateway_response
return {"content-type": APPLICATION_JSON, "x-amzn-ErrorType": exception.code}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: any particular reason we're deleting the Content-Type here? We could avoid the workaround to remove the default content-type of the response if we'd let this for now, as right above we call json.dumps, maybe setting the content type explicitly makes sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that makes more sense. Then when we implement the response mappings, we will have the content-type available from the template! 👍

Comment on lines +128 to +131
# Some headers can't be modified by parameter mappings or mapping templates.
# Aws will raise in those were present. Even for AWS_PROXY, where it is not applying them.
if header_mappings := request_data_mapping["header"]:
self._validate_headers_mapping(header_mappings, integration_type)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super neat!

Comment on lines +75 to +77
if not (connection := request.headers.get("Connection")) or connection != "close":
# We only set the connection if it isn't close.
# There appears to be in issue in Localstack, where setting "close" will result in "close, close"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, good catch!

Comment on lines +97 to +101
assert default_context.integration_request["body"] == b""
assert default_context.integration_request["headers"]["Accept"] == "application/json"
assert default_context.integration_request["http_method"] == "POST"
assert default_context.integration_request["query_string_parameters"] == {}
assert default_context.integration_request["uri"] == "https://example.com"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good change! might be easier to parse what's wrong in the test 👍

return ApiGatewayEndpoint.create_response(Request())


class TestResponseContextHandler:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: should we add a test for the keep-alive behavior? e.g. not setting the close if it's there, and setting keep-alive if anything else?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this is the right place for this test, but I can create a new test file to test this behavior

from localstack.utils.strings import short_uid


class ResponseContextHandler(RestApiGatewayHandler):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: what do you think about the name InvocationResponseEnricher? I'm not sure the name convey what it really does here.

@cloutierMat cloutierMat merged commit e67710d into master Jul 23, 2024
31 of 32 checks passed
@cloutierMat cloutierMat deleted the apigw-ng-implement-header-remapping branch July 23, 2024 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
aws:apigateway Amazon API Gateway semver: patch Non-breaking changes which can be included in patch releases
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants