Merge pull request #2155 from gtmanfred/master
set default status for s3 posts and add success_action_redirect support
This commit is contained in:
commit
4575f359c1
@ -5,9 +5,10 @@ import sys
|
|||||||
|
|
||||||
import six
|
import six
|
||||||
from botocore.awsrequest import AWSPreparedRequest
|
from botocore.awsrequest import AWSPreparedRequest
|
||||||
|
from werkzeug.wrappers import Request
|
||||||
|
|
||||||
from moto.core.utils import str_to_rfc_1123_datetime, py2_strip_unicode_keys
|
from moto.core.utils import str_to_rfc_1123_datetime, py2_strip_unicode_keys
|
||||||
from six.moves.urllib.parse import parse_qs, urlparse, unquote
|
from six.moves.urllib.parse import parse_qs, urlparse, unquote, parse_qsl
|
||||||
|
|
||||||
import xmltodict
|
import xmltodict
|
||||||
|
|
||||||
@ -777,6 +778,7 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
|
|||||||
return 409, {}, template.render(bucket=removed_bucket)
|
return 409, {}, template.render(bucket=removed_bucket)
|
||||||
|
|
||||||
def _bucket_response_post(self, request, body, bucket_name):
|
def _bucket_response_post(self, request, body, bucket_name):
|
||||||
|
response_headers = {}
|
||||||
if not request.headers.get("Content-Length"):
|
if not request.headers.get("Content-Length"):
|
||||||
return 411, {}, "Content-Length required"
|
return 411, {}, "Content-Length required"
|
||||||
|
|
||||||
@ -795,14 +797,18 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
|
|||||||
if hasattr(request, "form"):
|
if hasattr(request, "form"):
|
||||||
# Not HTTPretty
|
# Not HTTPretty
|
||||||
form = request.form
|
form = request.form
|
||||||
|
elif request.headers.get("Content-Type").startswith("multipart/form-data"):
|
||||||
|
request = Request.from_values(
|
||||||
|
input_stream=six.BytesIO(request.body),
|
||||||
|
content_length=request.headers["Content-Length"],
|
||||||
|
content_type=request.headers["Content-Type"],
|
||||||
|
method="POST",
|
||||||
|
)
|
||||||
|
form = request.form
|
||||||
else:
|
else:
|
||||||
# HTTPretty, build new form object
|
# HTTPretty, build new form object
|
||||||
body = body.decode()
|
body = body.decode()
|
||||||
|
form = dict(parse_qsl(body))
|
||||||
form = {}
|
|
||||||
for kv in body.split("&"):
|
|
||||||
k, v = kv.split("=")
|
|
||||||
form[k] = v
|
|
||||||
|
|
||||||
key = form["key"]
|
key = form["key"]
|
||||||
if "file" in form:
|
if "file" in form:
|
||||||
@ -810,13 +816,23 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
|
|||||||
else:
|
else:
|
||||||
f = request.files["file"].stream.read()
|
f = request.files["file"].stream.read()
|
||||||
|
|
||||||
|
if "success_action_redirect" in form:
|
||||||
|
response_headers["Location"] = form["success_action_redirect"]
|
||||||
|
|
||||||
|
if "success_action_status" in form:
|
||||||
|
status_code = form["success_action_status"]
|
||||||
|
elif "success_action_redirect" in form:
|
||||||
|
status_code = 303
|
||||||
|
else:
|
||||||
|
status_code = 204
|
||||||
|
|
||||||
new_key = self.backend.set_key(bucket_name, key, f)
|
new_key = self.backend.set_key(bucket_name, key, f)
|
||||||
|
|
||||||
# Metadata
|
# Metadata
|
||||||
metadata = metadata_from_headers(form)
|
metadata = metadata_from_headers(form)
|
||||||
new_key.set_metadata(metadata)
|
new_key.set_metadata(metadata)
|
||||||
|
|
||||||
return 200, {}, ""
|
return status_code, response_headers, ""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_path(request):
|
def _get_path(request):
|
||||||
|
@ -14,6 +14,7 @@ from io import BytesIO
|
|||||||
import mimetypes
|
import mimetypes
|
||||||
import zlib
|
import zlib
|
||||||
import pickle
|
import pickle
|
||||||
|
import uuid
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import boto
|
import boto
|
||||||
@ -4428,3 +4429,41 @@ def test_s3_config_dict():
|
|||||||
assert not logging_bucket["supplementaryConfiguration"].get(
|
assert not logging_bucket["supplementaryConfiguration"].get(
|
||||||
"BucketTaggingConfiguration"
|
"BucketTaggingConfiguration"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_s3
|
||||||
|
def test_creating_presigned_post():
|
||||||
|
bucket = "presigned-test"
|
||||||
|
s3 = boto3.client("s3", region_name="us-east-1")
|
||||||
|
s3.create_bucket(Bucket=bucket)
|
||||||
|
success_url = "http://localhost/completed"
|
||||||
|
fdata = b"test data\n"
|
||||||
|
file_uid = uuid.uuid4()
|
||||||
|
conditions = [
|
||||||
|
{"Content-Type": "text/plain"},
|
||||||
|
{"x-amz-server-side-encryption": "AES256"},
|
||||||
|
{"success_action_redirect": success_url},
|
||||||
|
]
|
||||||
|
conditions.append(["content-length-range", 1, 30])
|
||||||
|
data = s3.generate_presigned_post(
|
||||||
|
Bucket=bucket,
|
||||||
|
Key="{file_uid}.txt".format(file_uid=file_uid),
|
||||||
|
Fields={
|
||||||
|
"content-type": "text/plain",
|
||||||
|
"success_action_redirect": success_url,
|
||||||
|
"x-amz-server-side-encryption": "AES256",
|
||||||
|
},
|
||||||
|
Conditions=conditions,
|
||||||
|
ExpiresIn=1000,
|
||||||
|
)
|
||||||
|
resp = requests.post(
|
||||||
|
data["url"], data=data["fields"], files={"file": fdata}, allow_redirects=False
|
||||||
|
)
|
||||||
|
assert resp.headers["Location"] == success_url
|
||||||
|
assert resp.status_code == 303
|
||||||
|
assert (
|
||||||
|
s3.get_object(Bucket=bucket, Key="{file_uid}.txt".format(file_uid=file_uid))[
|
||||||
|
"Body"
|
||||||
|
].read()
|
||||||
|
== fdata
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user