### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current Behavior

Hi! 
I believe there is compatibility issue between localstack and Perl module wrapping S3 API [Net::Amazon::S3](https://metacpan.org/pod/Net::Amazon::S3). Uploading and downloading file works great, but listing bucket contents always gives empty list (i think also listing all buckets gives empty list but this is not an issue for me, since i'm always using one bucket). Listing files using AWS CLI, python's Boto3 or even old Perl alternative [Amazon::S3](https://metacpan.org/release/BIGFOOT/Amazon-S3-0.59/view/lib/Amazon/S3.pm) works OK for me.

### Expected Behavior

Both perl modules should be able to list bucket contents

### How are you starting LocalStack?

With a docker-compose file

### Steps To Reproduce

#### Part of `docker-compose.yml`

```
  localstack:
    container_name: "${LOCALSTACK_DOCKER_NAME:-localstack-main}"
    image: localstack/localstack:latest
    ports:
      - "127.0.0.1:4566:4566"            # LocalStack Gateway
      - "127.0.0.1:4510-4559:4510-4559"  # external services port range
    environment:
      # LocalStack configuration: https://docs.localstack.cloud/references/configuration/
      - DEBUG=${DEBUG- }
    networks:
      - default


```
#### Perl code that prints nothing (i.e. can't see uploaded file)
```
#!/usr/bin/perl
use warnings;
use Net::Amazon::S3;

use Config::IniFiles;

my $bucket_name = "myname";
my $s3_endpoint = "localstack:4566";
my $homedir = "/usr/share/httpd";
my $aws_cfg = Config::IniFiles->new(-file => "$homedir/.aws/config");



my $s3 = Net::Amazon::S3->new(
    {
        aws_access_key_id => $aws_cfg->val('default', 'aws_access_key_id'),
        aws_secret_access_key => $aws_cfg->val('default', 'aws_secret_access_key'),
        retry => 1,
        host => $s3_endpoint,
        secure => 0,
        use_virtual_host => 0,
    }
);

$s3->add_bucket( { bucket => $bucket_name } )
    or die $s3->err . ": " . $s3->errstr;

my $bucket_obj = $s3->bucket($bucket_name);

my $bucket_contents = $bucket_obj->list
        or die $s3->err . ": " . $s3->errstr;

for my $key ( @{ $bucket_contents->{keys} } ) {
        print "$key->{key}\n";
}
```

#### Perl code that WORKS OK (i.e. prints out uploaded file "key")
```
#!/usr/bin/perl
use warnings;
use CGI::Carp;
use Amazon::S3;

use Config::IniFiles;

my $bucket_name = "/mybucket";
my $s3_endpoint = "localstack:4566";
my $homedir = "/usr/share/httpd";
my $aws_cfg = Config::IniFiles->new(-file => "$homedir/.aws/config");


my $s3 = Amazon::S3->new(
    {
        aws_access_key_id => $aws_cfg->val('default', 'aws_access_key_id'),
        aws_secret_access_key => $aws_cfg->val('default', 'aws_secret_access_key'),
        retry => 1,
        host => $s3_endpoint,
        secure => 0,
    }
);

$s3->add_bucket( { bucket => $bucket_name } )
    or die $s3->err . ": " . $s3->errstr;

my $bucket = $s3->bucket( $bucket_name );
my $keyname = 'testing.txt';
my $value   = 'T';
$bucket->add_key(
    $keyname, $value,
        {   content_type        => 'text/plain',
            'x-amz-meta-colour' => 'orange',
        }
   );

my $response = $bucket->list
     or die $s3->err . ": " . $s3->errstr;
print $response->{bucket}."\n";
for my $key (@{ $response->{keys} }) {
      print "\t".$key->{key}."\n";
}
```


### Environment

```markdown
- host OS: windows + WSL
- container OS (where perl is run): CentOS 7.9.2009
- LocalStack: 
localstack-main | LocalStack version: 3.0.3.dev
localstack-main | LocalStack build date: 2023-12-20
localstack-main | LocalStack build git hash: 5c3ef157
```


### Anything else?

Net::Amazon::S3 way works OK with real AWS S3 (eu-west-1)

sage>No need to escape quotes (like this: &quot;) with HTML entities in XML.</Message>
    None of the prominent XML frameworks for python allow HTML entity escapes when serializing XML.
    This  implements the following workaround:
    - Escape quotes and \r with their HTML entities (&quot; and &#xD;).
    - Since & is (correctly) escaped in XML, the serialized string contains &amp;quot; and &amp;#xD;
    - These double-escapes are corrected by replacing such strings with their original.
    """
    # those are deleted from the JSON specs, but need to be kept for legacy reason (sent in 'x-amzn-query-error')
    QUERY_PREFIXED_ERRORS = {
        "BatchEntryIdsNotDistinct",
        "BatchRequestTooLong",
        "EmptyBatchRequest",
        "InvalidBatchEntryId",
        "MessageNotInflight",
        "PurgeQueueInProgress",
        "QueueDeletedRecently",
        "TooManyEntriesInBatchRequest",
        "UnsupportedOperation",
    }
    # Some error code changed between JSON and query, and we need to have a way to map it for legacy reason
    JSON_TO_QUERY_ERROR_CODES = {
        "InvalidParameterValueException": "InvalidParameterValue",
        "MissingRequiredParameterException": "MissingParameter",
        "AccessDeniedException": "AccessDenied",
        e.NonExistentQueue",
        "QueueNameExists": "QueueAlreadyExists",
    }
    SENDER_FAULT_ERRORS = (
        QUERY_PREFIXED_ERRORS
        | JSON_TO_QUERY_ERROR_CODES.keys()
        | {"OverLimit", "ResourceNotFoundException"}
    )
    def _default_serialize(self, xmlnode: ETree.Element, params: str, _, name: str, __) -> None:
        """
        Ensures that we "mark" characters in the node's text which need to be specifically encoded.
        This is necessary to easily identify these specific characters later, after the standard XML serialization is
        done, while n
        """
        node = ETree.SubElement(xmlnode, name)
        node.text = (
            str(params)
            .replace('"', '__mark