Multipart form with file upload - problem with ordering

Hi fellow Gatling users!

I need to upload a file to AWS S3 using Gatling 3.1.1. In Gatling 2.3.x below code worked like a charm:

`
http(“S3 file upload”)
.post(url)
.formParamMap(fields(_).get.asScala.toMap.success)
.formUpload(“file”, “file.wav”)

`

It worked fine, because the attached file was sent as last part in the multipart body (before dynamic form params).

In Gatling 3.1.1 however, the behaviour changed and now the attached file is sent first, before dynamic form param fields. It breaks S3 authorisation mechanism - S3 expects key and signature fields before actual file contents.

The reason is in the below Gatling source code (io/gatling/http/request/builder/HttpRequestExpressionBuilder.scala):

`
private def configureBodyParts(session: Session, requestBuilder: AhcRequestBuilder, bodyParts: List[BodyPart]): Validation[AhcRequestBuilder] =
for {
params ← httpAttributes.formParams.mergeWithFormIntoParamJList(httpAttributes.form, session)
stringParts = params.asScala.map(param => new StringPart(param.getName, param.getValue, charset, null, null, null, null, null))
parts ← Validation.sequence(bodyParts.map(_.toMultiPart(session)))
} yield requestBuilder.setBodyBuilder(new MultipartFormDataRequestBodyBuilder((parts ++ stringParts).asJava))
// ^^^^^ - file contents go first

`

If I send the form params manually, it works fine:

`
.bodyPart(StringBodyPart(“key”, fields().toOption.get(“key”)))
.bodyPart(StringBodyPart(“policy”, fields(
).toOption.get(“policy”)))
// etc.

`

But the form params are dynamic (retrieved from earlier request and saved in a session) and I cannot put the static list of these params in the source code (different S3 regions require different auth fields).

There is no method I’m aware of to set body parts from a Map or Seq. I can only get them from the user session variable using formParamMap(map: Expression[Map[String, Any]]) method.

I’ve tried to use signature calculator and request body processor to maybe reorder the parts before sending the request, but without success.

Is there any other way I could ensure the dynamic form fields go always before file part in the multipart body?

Thanks in advance,
Adam

Looks like a pretty easy fix to contribute, doesn’t it?

Hi Stéphane,

If you mean to only switch the order here:

`
(parts ++ stringParts).asJava

`

then yeah, pretty easy - even for me :wink:

But technically speaking, I’m not sure if it’s a bug whatsoever - maybe it’s just an S3 quirk and shouldn’t be solved this way…?

Adam

If you mean to only switch the order here:

`
(parts ++ stringParts).asJava

`

then yeah, pretty easy - even for me :wink:

Yep, that’s what I had in mind for now :slight_smile:
We want to release Gatling 3.1.2 within a week as there are a few nasty bugs we want to get fixed.

But technically speaking, I’m not sure if it’s a bug whatsoever - maybe it’s just an S3 quirk and shouldn’t be solved this way…?

The actual issue is probably that Gatling should preserve parameters order.
I’m fine with going for a quick workaround, and go with a proper fix later when we’re not in a rush and have time to refactor, check perf impact, etc…

Stéphane Landelle

GatlingCorp CTO
slandelle@gatling.io

No problem, here’s the temporary workaround:
https://github.com/gatling/gatling/pull/3729

Cheers,
Adam