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 | ||||
| 
 | ||||
|     def _bucket_response(self, request, full_url): | ||||
|         querystring = self._get_querystring(full_url) | ||||
|         querystring = self._get_querystring(request, full_url) | ||||
|         method = request.method | ||||
|         region_name = parse_region_from_url(full_url, use_default_region=False) | ||||
|         if region_name is None: | ||||
| @ -297,7 +297,17 @@ class S3Response(BaseResponse): | ||||
|             ) | ||||
| 
 | ||||
|     @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) | ||||
|         # full_url can be one of two formats, depending on the version of werkzeug used: | ||||
|         # http://foobaz.localhost:5000/?prefix=bar%2Bbaz | ||||
|  | ||||
| @ -3285,7 +3285,9 @@ if settings.TEST_SERVER_MODE: | ||||
| 
 | ||||
| 
 | ||||
| @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): | ||||
|     bucket_name = "testbucket-3113" | ||||
|     s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME) | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| import io | ||||
| from urllib.parse import urlparse, parse_qs | ||||
| import sure  # noqa # pylint: disable=unused-import | ||||
| import pytest | ||||
| import xmltodict | ||||
| 
 | ||||
| from flask.testing import FlaskClient | ||||
| import moto.server as server | ||||
| @ -32,7 +34,8 @@ def test_s3_server_get(): | ||||
|     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() | ||||
| 
 | ||||
|     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.data.should.contain(b"ListBucketResult") | ||||
| 
 | ||||
|     for key_name in ("bar_baz", "bar+baz"): | ||||
|         res = test_client.put( | ||||
|             f"/{key_name}", "http://foobaz.localhost:5000/", data="test value" | ||||
|         ) | ||||
|         res.status_code.should.equal(200) | ||||
|         assert "ETag" in dict(res.headers) | ||||
|     res = test_client.put( | ||||
|         f"/{key_name}", "http://foobaz.localhost:5000/", data="test value" | ||||
|     ) | ||||
|     res.status_code.should.equal(200) | ||||
|     assert "ETag" in dict(res.headers) | ||||
| 
 | ||||
|         res = test_client.get( | ||||
|             "/", "http://foobaz.localhost:5000/", query_string={"prefix": key_name} | ||||
|         ) | ||||
|         res.status_code.should.equal(200) | ||||
|         res.data.should.contain(b"Contents") | ||||
|     res = test_client.get( | ||||
|         "/", "http://foobaz.localhost:5000/", query_string={"prefix": key_name} | ||||
|     ) | ||||
|     res.status_code.should.equal(200) | ||||
|     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.status_code.should.equal(200) | ||||
|         res.data.should.equal(b"test value") | ||||
|     res = test_client.get(f"/{key_name}", "http://foobaz.localhost:5000/") | ||||
|     res.status_code.should.equal(200) | ||||
|     res.data.should.equal(b"test value") | ||||
| 
 | ||||
| 
 | ||||
| def test_s3_server_ignore_subdomain_for_bucketnames(): | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user