S3: Allow keynames with spaces (#5701)
This commit is contained in:
		
							parent
							
								
									d6c438400e
								
							
						
					
					
						commit
						740f1f103e
					
				| @ -261,7 +261,7 @@ class S3Response(BaseResponse): | |||||||
|             return status_code, headers, response_content |             return status_code, headers, response_content | ||||||
| 
 | 
 | ||||||
|     def _bucket_response(self, request, full_url): |     def _bucket_response(self, request, full_url): | ||||||
|         querystring = self._get_querystring(full_url) |         querystring = self._get_querystring(request, full_url) | ||||||
|         method = request.method |         method = request.method | ||||||
|         region_name = parse_region_from_url(full_url, use_default_region=False) |         region_name = parse_region_from_url(full_url, use_default_region=False) | ||||||
|         if region_name is None: |         if region_name is None: | ||||||
| @ -297,7 +297,17 @@ class S3Response(BaseResponse): | |||||||
|             ) |             ) | ||||||
| 
 | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def _get_querystring(full_url): |     def _get_querystring(request, full_url): | ||||||
|  |         # Flask's Request has the querystring already parsed | ||||||
|  |         # In ServerMode, we can use this, instead of manually parsing this | ||||||
|  |         if hasattr(request, "args"): | ||||||
|  |             query_dict = dict() | ||||||
|  |             for key, val in dict(request.args).items(): | ||||||
|  |                 # The parse_qs-method returns List[str, List[Any]] | ||||||
|  |                 # Ensure that we confirm to the same response-type here | ||||||
|  |                 query_dict[key] = val if isinstance(val, list) else [val] | ||||||
|  |             return query_dict | ||||||
|  | 
 | ||||||
|         parsed_url = urlparse(full_url) |         parsed_url = urlparse(full_url) | ||||||
|         # full_url can be one of two formats, depending on the version of werkzeug used: |         # full_url can be one of two formats, depending on the version of werkzeug used: | ||||||
|         # http://foobaz.localhost:5000/?prefix=bar%2Bbaz |         # http://foobaz.localhost:5000/?prefix=bar%2Bbaz | ||||||
|  | |||||||
| @ -3285,7 +3285,9 @@ if settings.TEST_SERVER_MODE: | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @mock_s3 | @mock_s3 | ||||||
| @pytest.mark.parametrize("prefix", ["file", "file+else", "file&another"]) | @pytest.mark.parametrize( | ||||||
|  |     "prefix", ["file", "file+else", "file&another", "file another"] | ||||||
|  | ) | ||||||
| def test_get_object_versions_with_prefix(prefix): | def test_get_object_versions_with_prefix(prefix): | ||||||
|     bucket_name = "testbucket-3113" |     bucket_name = "testbucket-3113" | ||||||
|     s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME) |     s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME) | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| import io | import io | ||||||
| from urllib.parse import urlparse, parse_qs | from urllib.parse import urlparse, parse_qs | ||||||
| import sure  # noqa # pylint: disable=unused-import | import sure  # noqa # pylint: disable=unused-import | ||||||
|  | import pytest | ||||||
|  | import xmltodict | ||||||
| 
 | 
 | ||||||
| from flask.testing import FlaskClient | from flask.testing import FlaskClient | ||||||
| import moto.server as server | import moto.server as server | ||||||
| @ -32,7 +34,8 @@ def test_s3_server_get(): | |||||||
|     res.data.should.contain(b"ListAllMyBucketsResult") |     res.data.should.contain(b"ListAllMyBucketsResult") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_s3_server_bucket_create(): | @pytest.mark.parametrize("key_name", ["bar_baz", "bar+baz", "baz bar"]) | ||||||
|  | def test_s3_server_bucket_create(key_name): | ||||||
|     test_client = authenticated_client() |     test_client = authenticated_client() | ||||||
| 
 | 
 | ||||||
|     res = test_client.put("/", "http://foobaz.localhost:5000/") |     res = test_client.put("/", "http://foobaz.localhost:5000/") | ||||||
| @ -45,22 +48,25 @@ def test_s3_server_bucket_create(): | |||||||
|     res.status_code.should.equal(200) |     res.status_code.should.equal(200) | ||||||
|     res.data.should.contain(b"ListBucketResult") |     res.data.should.contain(b"ListBucketResult") | ||||||
| 
 | 
 | ||||||
|     for key_name in ("bar_baz", "bar+baz"): |     res = test_client.put( | ||||||
|         res = test_client.put( |         f"/{key_name}", "http://foobaz.localhost:5000/", data="test value" | ||||||
|             f"/{key_name}", "http://foobaz.localhost:5000/", data="test value" |     ) | ||||||
|         ) |     res.status_code.should.equal(200) | ||||||
|         res.status_code.should.equal(200) |     assert "ETag" in dict(res.headers) | ||||||
|         assert "ETag" in dict(res.headers) |  | ||||||
| 
 | 
 | ||||||
|         res = test_client.get( |     res = test_client.get( | ||||||
|             "/", "http://foobaz.localhost:5000/", query_string={"prefix": key_name} |         "/", "http://foobaz.localhost:5000/", query_string={"prefix": key_name} | ||||||
|         ) |     ) | ||||||
|         res.status_code.should.equal(200) |     res.status_code.should.equal(200) | ||||||
|         res.data.should.contain(b"Contents") |     content = xmltodict.parse(res.data)["ListBucketResult"]["Contents"] | ||||||
|  |     # If we receive a dict, we only received one result | ||||||
|  |     # If content is of type list, our call returned multiple results - which is not correct | ||||||
|  |     content.should.be.a(dict) | ||||||
|  |     content["Key"].should.equal(key_name) | ||||||
| 
 | 
 | ||||||
|         res = test_client.get(f"/{key_name}", "http://foobaz.localhost:5000/") |     res = test_client.get(f"/{key_name}", "http://foobaz.localhost:5000/") | ||||||
|         res.status_code.should.equal(200) |     res.status_code.should.equal(200) | ||||||
|         res.data.should.equal(b"test value") |     res.data.should.equal(b"test value") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_s3_server_ignore_subdomain_for_bucketnames(): | def test_s3_server_ignore_subdomain_for_bucketnames(): | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user