From 637e0188a2ab81bf3a72b7ddae2677f235c50973 Mon Sep 17 00:00:00 2001 From: Olivier Parent Colombel Date: Mon, 20 Apr 2020 20:54:31 +0200 Subject: [PATCH 1/2] Allow S3 keys to start with leading slashes. --- moto/s3/responses.py | 3 ++- moto/s3/urls.py | 2 +- tests/test_s3/test_s3.py | 22 ++++++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 442489a8a..ce1e6128d 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -134,7 +134,8 @@ ACTION_MAP = { def parse_key_name(pth): - return pth.lstrip("/") + # strip the first '/' left by urlparse + return pth[1:] if pth.startswith('/') else pth def is_delete_keys(request, path, bucket_name): diff --git a/moto/s3/urls.py b/moto/s3/urls.py index 752762184..4c4e9ea76 100644 --- a/moto/s3/urls.py +++ b/moto/s3/urls.py @@ -15,5 +15,5 @@ url_paths = { # path-based bucket + key "{0}/(?P[^/]+)/(?P.+)": S3ResponseInstance.key_or_control_response, # subdomain bucket + key with empty first part of path - "{0}//(?P.*)$": S3ResponseInstance.key_or_control_response, + "{0}/(?P/.*)$": S3ResponseInstance.key_or_control_response, } diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index ffbd73966..3048f6507 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -3744,6 +3744,28 @@ def test_root_dir_with_empty_name_works(): store_and_read_back_a_key("/") +@parameterized(['mybucket', 'my.bucket']) +@mock_s3 +def test_leading_slashes_not_removed(bucket_name): + """Make sure that leading slashes are not removed internally.""" + s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME) + s3.create_bucket(Bucket=bucket_name) + + uploaded_key = '/key' + invalid_key_1 = 'key' + invalid_key_2 = '//key' + + s3.put_object(Bucket=bucket_name, Key=uploaded_key, Body=b'Some body') + + with assert_raises(ClientError) as e: + s3.get_object(Bucket=bucket_name, Key=invalid_key_1) + e.exception.response["Error"]["Code"].should.equal("NoSuchKey") + + with assert_raises(ClientError) as e: + s3.get_object(Bucket=bucket_name, Key=invalid_key_2) + e.exception.response["Error"]["Code"].should.equal("NoSuchKey") + + @parameterized( [("foo/bar/baz",), ("foo",), ("foo/run_dt%3D2019-01-01%252012%253A30%253A00",)] ) From d852f7dd063ae17cc1fa7f97bc3510e3daef55e9 Mon Sep 17 00:00:00 2001 From: Olivier Parent Colombel Date: Sat, 25 Apr 2020 15:10:23 +0200 Subject: [PATCH 2/2] Fixing lint errors. --- moto/s3/responses.py | 2 +- tests/test_s3/test_s3.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/moto/s3/responses.py b/moto/s3/responses.py index ce1e6128d..71c424244 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -135,7 +135,7 @@ ACTION_MAP = { def parse_key_name(pth): # strip the first '/' left by urlparse - return pth[1:] if pth.startswith('/') else pth + return pth[1:] if pth.startswith("/") else pth def is_delete_keys(request, path, bucket_name): diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index 3048f6507..fea76b9e3 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -3744,18 +3744,18 @@ def test_root_dir_with_empty_name_works(): store_and_read_back_a_key("/") -@parameterized(['mybucket', 'my.bucket']) +@parameterized(["mybucket", "my.bucket"]) @mock_s3 def test_leading_slashes_not_removed(bucket_name): """Make sure that leading slashes are not removed internally.""" s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME) s3.create_bucket(Bucket=bucket_name) - uploaded_key = '/key' - invalid_key_1 = 'key' - invalid_key_2 = '//key' + uploaded_key = "/key" + invalid_key_1 = "key" + invalid_key_2 = "//key" - s3.put_object(Bucket=bucket_name, Key=uploaded_key, Body=b'Some body') + s3.put_object(Bucket=bucket_name, Key=uploaded_key, Body=b"Some body") with assert_raises(ClientError) as e: s3.get_object(Bucket=bucket_name, Key=invalid_key_1)