diff --git a/.env.dist b/.env.dist index cc1bc3b..f80a64b 100644 --- a/.env.dist +++ b/.env.dist @@ -2,3 +2,7 @@ # part of the url S3_URL= S3_REGION= +# don't use the same bucket as the properties don't expect a file and a +# directory to have the same name (which can be generated by other proofs) +S3_PROPERTIES_URL= +S3_PROPERTIES_REGION= diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7eceeb3..63ad570 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,8 @@ jobs: env: S3_URL: ${{ secrets.S3_URL_PROOFS }} S3_REGION: ${{ secrets.S3_REGION_PROOFS }} + S3_PROPERTIES_URL: ${{ secrets.S3_PROPERTIES_URL_PROOFS }} + S3_PROPERTIES_REGION: ${{ secrets.S3_PROPERTIES_REGION_PROOFS }} blackbox_coverage: runs-on: ${{ matrix.os }} concurrency: @@ -58,6 +60,8 @@ jobs: ENABLE_COVERAGE: 'true' S3_URL: ${{ secrets.S3_URL_COVERAGE }} S3_REGION: ${{ secrets.S3_REGION_COVERAGE }} + S3_PROPERTIES_URL: ${{ secrets.S3_PROPERTIES_URL_COVERAGE }} + S3_PROPERTIES_REGION: ${{ secrets.S3_PROPERTIES_REGION_COVERAGE }} - uses: codecov/codecov-action@v1 with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/periodic.yml b/.github/workflows/periodic.yml index 494c4af..4193377 100644 --- a/.github/workflows/periodic.yml +++ b/.github/workflows/periodic.yml @@ -35,3 +35,5 @@ jobs: env: S3_URL: ${{ secrets.S3_URL_PROOFS }} S3_REGION: ${{ secrets.S3_REGION_PROOFS }} + S3_PROPERTIES_URL: ${{ secrets.S3_PROPERTIES_URL_PROOFS }} + S3_PROPERTIES_REGION: ${{ secrets.S3_PROPERTIES_REGION_PROOFS }} diff --git a/README.md b/README.md index b6014f7..be34053 100644 --- a/README.md +++ b/README.md @@ -58,3 +58,6 @@ $data static fn() => null, // do something if there is no images ); ``` + +> [!WARNING] +> A bucket can contain a file and a directory with the same name. This is not supported by `innmind/filesystem` adapters. This means that if you use `Innmind\S3\Filesystem\Adapter` on a bucket where there is a file and a directory with the same name it will result in unexpected behaviour or an exception. diff --git a/proofs/adapter.php b/proofs/adapter.php index 07d075f..e55131f 100644 --- a/proofs/adapter.php +++ b/proofs/adapter.php @@ -29,8 +29,8 @@ $os = Resilient::of(OSFactory::build()); $bucket = Factory::of($os)->build( - Url::of(\getenv('S3_URL') ?? throw new Exception('Env var missing')), - Region::of(\getenv('S3_REGION') ?? throw new Exception('Env var missing')), + Url::of(\getenv('S3_PROPERTIES_URL') ?? throw new Exception('Env var missing')), + Region::of(\getenv('S3_PROPERTIES_REGION') ?? throw new Exception('Env var missing')), ); yield properties( diff --git a/src/Bucket/OverHttp.php b/src/Bucket/OverHttp.php index 4c10136..6eb3975 100644 --- a/src/Bucket/OverHttp.php +++ b/src/Bucket/OverHttp.php @@ -119,11 +119,14 @@ public function list(Path $path): Sequence throw new LogicException("Only a directory can be listed, got '{$path->toString()}'"); } - if ($path->equals(Path::none())) { - $query = 'delimiter=%2F&list-type=2'; - $prefixLength = 0; - } else { - $query = 'delimiter=%2F&list-type=2&prefix='.\rawurlencode($path->toString()); + $query = [ + 'delimiter' => '/', + 'list-type' => 2, + ]; + $prefixLength = 0; + + if (!$path->equals(Path::none())) { + $query['prefix'] = $path->toString(); $prefixLength = Str::of($path->toString(), Str\Encoding::ascii)->length(); } @@ -144,18 +147,28 @@ public function list(Path $path): Sequence */ private function paginate( Path $path, - string $query, + array $query, string $next = null, ): Sequence { if (\is_string($next)) { - $next = '&continuation-token='.$next; + $next = ['continuation-token' => $next]; + } else { + $next = []; } return ($this->fulfill)($this->request( Method::get, $this->bucket->path(), null, - Query::of($query.(string) $next), + Query::of(\http_build_query( + [ + ...$next, + ...$query, + ], + '', + '&', + \PHP_QUERY_RFC3986, + )), )) ->maybe() ->map(static fn($success) => $success->response()->body())