Support for PostObject #222
|
@ -56,21 +56,29 @@ pub async fn handle_post_object(
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if name != "file" {
|
if name == "file" {
|
||||||
|
break field;
|
||||||
|
}
|
||||||
|
|
||||||
if let Ok(content) = HeaderValue::from_str(&field.text().await?) {
|
if let Ok(content) = HeaderValue::from_str(&field.text().await?) {
|
||||||
match name.as_str() {
|
match name.as_str() {
|
||||||
"tag" => (/* tag need to be reencoded, but we don't support them yet anyway */),
|
"tag" => (/* tag need to be reencoded, but we don't support them yet anyway */),
|
||||||
"acl" => {
|
"acl" => {
|
||||||
params.append("x-amz-acl", content);
|
if params.insert("x-amz-acl", content).is_some() {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
"Field 'acl' provided more than one time".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// TODO actually that's illegal to have the same param multiple times
|
if params.insert(&name, content).is_some() {
|
||||||
params.append(name, content);
|
return Err(Error::BadRequest(format!(
|
||||||
|
"Field '{}' provided more than one time",
|
||||||
|
name
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
break field;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,7 +108,7 @@ pub async fn handle_post_object(
|
||||||
|
|
||||||
let key = if key.contains("${filename}") {
|
let key = if key.contains("${filename}") {
|
||||||
let filename = field.file_name();
|
let filename = field.file_name();
|
||||||
// is this correct? Maybe we should error instead of default?
|
// TODO is this correct? Maybe we should error instead of default?
|
||||||
key.replace("${filename}", filename.unwrap_or_default())
|
key.replace("${filename}", filename.unwrap_or_default())
|
||||||
} else {
|
} else {
|
||||||
key.to_owned()
|
key.to_owned()
|
||||||
trinity-1686a marked this conversation as resolved
Outdated
|
|||||||
|
@ -130,7 +138,7 @@ pub async fn handle_post_object(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let conditions = decoded_policy.into_conditions()?;
|
let mut conditions = decoded_policy.into_conditions()?;
|
||||||
|
|
||||||
for (param_key, value) in params.iter() {
|
for (param_key, value) in params.iter() {
|
||||||
let mut param_key = param_key.to_string();
|
let mut param_key = param_key.to_string();
|
||||||
lx marked this conversation as resolved
Outdated
lx
commented
I feel like we should add unit tests for the policy decoding logic (not just for into_conditions but end-to-end starting with JSON) I feel like we should add unit tests for the policy decoding logic (not just for into_conditions but end-to-end starting with JSON)
lx
commented
I'll write a test and post it in the comments of the PR so that you can copy and paste I'll write a test and post it in the comments of the PR so that you can copy and paste
|
|||||||
|
@ -154,13 +162,13 @@ pub async fn handle_post_object(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"key" => {
|
"key" => {
|
||||||
let conds = conditions.params.get("key").ok_or_else(|| {
|
let conds = conditions.params.remove("key").ok_or_else(|| {
|
||||||
Error::BadRequest(format!("Key '{}' is not allowed in policy", param_key))
|
Error::BadRequest(format!("Key '{}' is not allowed in policy", param_key))
|
||||||
})?;
|
})?;
|
||||||
for cond in conds {
|
for cond in conds {
|
||||||
let ok = match cond {
|
let ok = match cond {
|
||||||
Operation::Equal(s) => s == &key,
|
Operation::Equal(s) => s == key,
|
||||||
lx marked this conversation as resolved
Outdated
lx
commented
Can you point me to the documentation section which says that there must be a policy specified for the Can you point me to the documentation section which says that there must be a policy specified for the `key` field?
trinity-1686a
commented
Which means I have to add some code to ignore ~~this is not specified, it's however the behavior of AWS. `policy` and `x-amz-signature` are the only two fields I found to not be required in the policy. Even `x-amz-credential`, which is definitelly required to make a valid v4 signature, must be allowed in policy~~
this is in fact [specified somewhere](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html#sigv4-PolicyConditions)
> Each form field that you specify in a form (except x-amz-signature, file, policy, and field names that have an x-ignore- prefix) must appear in the list of conditions.
Which means I have to add some code to ignore `x-ignore-*`, others are already ignored
|
|||||||
Operation::StartsWith(s) => key.starts_with(s),
|
Operation::StartsWith(s) => key.starts_with(&s),
|
||||||
};
|
};
|
||||||
if !ok {
|
if !ok {
|
||||||
return Err(Error::BadRequest(format!(
|
return Err(Error::BadRequest(format!(
|
||||||
|
@ -171,13 +179,13 @@ pub async fn handle_post_object(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let conds = conditions.params.get(¶m_key).ok_or_else(|| {
|
let conds = conditions.params.remove(¶m_key).ok_or_else(|| {
|
||||||
Error::BadRequest(format!("Key '{}' is not allowed in policy", param_key))
|
Error::BadRequest(format!("Key '{}' is not allowed in policy", param_key))
|
||||||
})?;
|
})?;
|
||||||
for cond in conds {
|
for cond in conds {
|
||||||
let ok = match cond {
|
let ok = match cond {
|
||||||
Operation::Equal(s) => s == value,
|
Operation::Equal(s) => s.as_str() == value,
|
||||||
trinity-1686a marked this conversation as resolved
Outdated
lx
commented
Same here, can you point me to the doc which says a policy must be given for all fields? Same here, can you point me to the doc which says a policy must be given for all fields?
trinity-1686a
commented
see comment on see comment on `key`
|
|||||||
Operation::StartsWith(s) => value.to_str()?.starts_with(s),
|
Operation::StartsWith(s) => value.to_str()?.starts_with(s.as_str()),
|
||||||
};
|
};
|
||||||
if !ok {
|
if !ok {
|
||||||
return Err(Error::BadRequest(format!(
|
return Err(Error::BadRequest(format!(
|
||||||
|
@ -190,7 +198,12 @@ pub async fn handle_post_object(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO check that each policy item is used
|
if let Some((param_key, _)) = conditions.params.iter().next() {
|
||||||
|
return Err(Error::BadRequest(format!(
|
||||||
|
"Key '{}' is required in policy, but no value was provided",
|
||||||
|
param_key
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
let content_type = field
|
let content_type = field
|
||||||
.content_type()
|
.content_type()
|
||||||
|
|
This looks like it should rather be an error case: if the application builder put
${filename}
in the key field but the browser for some reason didn't include the name of the uploaded file, we probably want to reject the request.that was actually how a previous iteration worked. This behavior was added because it's exactly how AWS behave (not that I can say I agree with that behavior)
:/