Handling DeleteObjectsRequest broken after JS SDK update
See original GitHub issueI’m running some integration tests against a localstack S3 container using AWS SDK v3 for JavaScript. With the recently published version v3.197.0 of the SDK, i’m getting errors when running a DeleteObjects request.
I compared the requests that are sent by the SDK, and can see the following difference (from the localstack logs): Before:
POST localhost/3ee3499c-208f-43f3-aadd-b667f3b2ea6f?delete=&x-id=DeleteObjects
Afterwards:
POST localhost/89e28fce-e5f2-427a-ab59-5229b83a15ee/?delete=&x-id=DeleteObjects
Stacktrace of the error:
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: 2022-10-27T09:35:28.605 INFO --- [ asgi_gw_0] localstack.request.aws : AWS s3.DeleteObjects => 500 (InternalError); DeleteObjectsRequest({'Bucket': '89e28fce-e5f2-427a-ab59-5229b83a15ee', 'Delete': {'Objects': [{'Key': 'sameDirectory/316b663c-663f-4881-bdd8-73ec94d62260'}, {'Key': 'sameDirectory/77680bae-2e2c-4230-af2c-165680c8057d'}]}, 'MFA': None, 'RequestPayer': None, 'BypassGovernanceRetention': None, 'ExpectedBucketOwner': None, 'ChecksumAlgorithm': None}, headers={'content-type': 'application/xml', 'content-length': '259', 'Expect': '100-continue', 'content-md5': 'SeDvWL0dJ6G0h+yQ476qfg==', 'host': 'localhost', 'x-amz-user-agent': 'aws-sdk-js/3.197.0', 'user-agent': 'aws-sdk-js/3.197.0 os/darwin/22.1.0 lang/js md/nodejs/16.18.0 api/s3/3.197.0', 'amz-sdk-invocation-id': 'bbd8ffc8-d792-4298-b7bd-68deca0c3d07', 'amz-sdk-request': 'attempt=1; max=3', 'x-amz-date': '20221027T093528Z', 'x-amz-content-sha256': 'f52fc7ca91861bfc5dac677a383afa8e05c00d54b61593ddd96502aff8711057', 'authorization': 'AWS4-HMAC-SHA256 Credential=accessKeyId/20221027/eu-central-1/s3/aws4_request, SignedHeaders=amz-sdk-invocation-id;amz-sdk-request;content-length;content-md5;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-user-agent, Signature=62c6fb145a2d09eca53b1083ec3b0b75490ffd7cd2a22d572087784bd0599536', 'Connection': 'keep-alive', 'x-localstack-tgt-api': 's3', 'x-moto-account-id': '000000000000', 'x-localstack-edge': 'http://localhost', 'X-Forwarded-For': '127.0.0.1, localhost'}); InternalError(exception while calling s3.DeleteObjects: Traceback (most recent call last): +4ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/localstack/aws/chain.py", line 90, in handle +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: handler(self, self.context, response) +1ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/localstack/aws/handlers/service.py", line 122, in __call__ +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: handler(chain, context, response) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/localstack/aws/handlers/legacy.py", line 81, in __call__ +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: result = self.forward_request( +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/localstack/aws/handlers/legacy.py", line 141, in forward_request +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: return do_forward_request( +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/localstack/services/edge.py", line 225, in do_forward_request +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: result = do_forward_request_inmem(api, method, path, data, headers, port=port) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/localstack/services/edge.py", line 249, in do_forward_request_inmem +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: response = modify_and_forward( +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/localstack/services/generic_proxy.py", line 601, in wrapper +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: value = func(*args, **kwargs) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/localstack/services/generic_proxy.py", line 774, in modify_and_forward +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: updated_response = listener.return_response( +1ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/localstack/services/s3/s3_listener.py", line 1644, in return_response +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: object_path = parts[1] if parts[1][0] == "/" else "/+0ms" % parts[1]
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: IndexError: string index out of range +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: , headers={'Content-Type': 'application/xml', 'Content-Length': '1525', 'x-amz-request-id': 'FF7XCYIT7RZKAU1DEAH2YKXFG4F37LYNDJ07Z942D2LEXHLG1AOJ', 'x-amz-id-2': 'MzRISOwyjmnupFF7XCYIT7RZKAU1DEAH2YKXFG4F37LYNDJ07Z942D2LEXHLG1AOJ7/JypPGXLh0OVFGcJaaO3KW/hRAqKOpIEEp'}) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: 2022-10-27T09:35:28.619 ERROR --- [uest_thread)] werkzeug : Error on request: +14ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: Traceback (most recent call last): +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/werkzeug/serving.py", line 335, in run_wsgi +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: execute(self.server.app) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/werkzeug/serving.py", line 322, in execute +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: application_iter = app(environ, start_response) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/moto/moto_server/werkzeug_app.py", line 249, in __call__ +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: return backend_app(environ, start_response) +2ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/flask/app.py", line 2091, in __call__ +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: return self.wsgi_app(environ, start_response) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/flask/app.py", line 2076, in wsgi_app +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: response = self.handle_exception(e) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/flask_cors/extension.py", line 165, in wrapped_function +1ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: return cors_after_request(app.make_response(f(*args, **kwargs))) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/flask/app.py", line 2073, in wsgi_app +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: response = self.full_dispatch_request() +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/flask/app.py", line 1519, in full_dispatch_request +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: rv = self.handle_user_exception(e) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/flask_cors/extension.py", line 165, in wrapped_function +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: return cors_after_request(app.make_response(f(*args, **kwargs))) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/flask/app.py", line 1517, in full_dispatch_request +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: rv = self.dispatch_request() +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/flask/app.py", line 1503, in dispatch_request +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/localstack/utils/patch.py", line 38, in proxy +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: return new(target, *args, **kwargs) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/localstack/utils/aws/request_context.py", line 174, in convert_to_flask_response_call +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: return fn(*args, **kwargs) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/moto/core/utils.py", line 110, in __call__ +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: result = self.callback(request, request.url, dict(request.headers)) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/moto/s3/responses.py", line 254, in ambiguous_response +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: return self.bucket_response(request, full_url, headers) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/moto/utilities/aws_headers.py", line 60, in _wrapper +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: response = f(*args, **kwargs) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/moto/s3/responses.py", line 260, in bucket_response +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: response = self._bucket_response(request, full_url) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/moto/s3/responses.py", line 305, in _bucket_response +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: return self._bucket_response_post(request, bucket_name) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/moto/s3/responses.py", line 983, in _bucket_response_post +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: key = form["key"] +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: File "/opt/code/localstack/.venv/lib/python3.10/site-packages/werkzeug/datastructures.py", line 375, in __getitem__ +1ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: raise exceptions.BadRequestKeyError(key) +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand. +0ms
testcontainers:containers TRACE a06d147a600e3a0d915f0ed0923d716f17491e2406353bc3a7829fd26c34b1a2: KeyError: 'key' +0ms
What I understand is that the POST request for deletion is not determined as a delete request by the self.is_delete_keys
method here, and thus interpreted as a PutObject request afterwards.
From what I can see, the method for determining the delete request currently does not account for this changed URL, where we now have /?delete=
instead of ?delete=
.
Could it already be the fix to include /?delete=
in the check?
Issue Analytics
- State:
- Created a year ago
- Comments:6
Hi @bblommers, thanks so much for the quick follow-up & fix! Much appreciated 😃
We’re currently using the localstack docker image in our tests, and I think they’re not pulling the latest moto version yet. I tried running our tests with the moto docker image instead, but couldn’t get it to work so far. So I can’t really verify, sorry 😕 But I believe your PR should do the trick, so I think you can consider this closed, and I will report back once I’m able to check.
Again, thanks for your quick help!
No worries @j-beyer - I’ll raise a PR shortly to improve the overall logic here a bit.