### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current Behavior

When folder names contain a space then `listObjects` returns names without `/` at the end. Without space it works fine.

### Expected Behavior

Folders containing space in the name are returned with `/` at the end.

### How are you starting LocalStack?

With a `docker run` command

### Steps To Reproduce

awslocal s3api put-object --bucket bucket-name --key "folder name/"

awslocal s3api list-objects --bucket bucket-name
```
{
    "Contents": [
        {
            "Key": "folder name",
            "LastModified": "2023-12-11T10:15:20.000Z",
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            "Size": 0,
            "StorageClass": "STANDARD",
            "Owner": {
                "DisplayName": "webfile",
                "ID": "75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a"
            }
        }
    ],
    "RequestCharged": null
}
```


### Environment

```markdown
- OS: Linux Mint 21.2
- LocalStack: localstack/localstack:3.0
```


### Anything else?

_No response_
except ProtocolParserError:
                # GET requests should ignore the body, so we just let them pass
                if not (reque_get_body_errors):
                    raise
        # even if the payload has been parsed, the rest of the shape needs to be processed as well
        # (for members which are located outside of the body, like uri or header)
        non_payload_parsed = self._parse_shape(request, shan_payload_parsed, uri_params)
        # update the final result with the parsed body and the parsed payload (where the payload has precedence)
        final_parsed.update(non_payload_parsed)
        final_parsed.update(payload_parsed)
    def _initial_body_parse(self, requespReq -> Any:
        """
        This method executes the initial parsing of the body (XML, JSON, or CBOR).
        The parsed body will afterwards still be walked through and the nodes will be converted to the appropriate
        types, but this method does the first round of parsing.
        :param request: of which the body should be parsed
        :return: depending on the actual implementation
        """
        raise NotImplementedError("_initial_body_parse")
    e_event_stream(self, requespRequest, shape: Shape) -> Any:
        # TODO handle event streams
        raise NotImplementedError("_create_event_stream")
    def create_input_stream(self, requespReq -> IO[bytes]:
        """
        Returns an IO object that makes the payload of the HttpRequest available for streaming.
        :param request: the http request
        :return: the input stream that allows services to consume the request payload
        """
        # for now _get_stream_for_parsing seems to be a good compromise. it can be used even after `request.data` was
        # previously called. however the reverse doesn't work. once the stream has been consumed, `request.data` will