Advanced multipart request Doesn't work Correctly

Hi

I used the example given in this Link https://k6.io/docs/examples/data-uploads/ to send multi part uploads but It is not working in k6. I tried same using Browser it works fine. Here is the screenshot of the Wireshark Capture I took for reference:

Non Working One Using K6 Tool:

Below is the K6 Java Script I have written for sending Traffic:

import http from "k6/http";
import { check } from "k6";
import { FormData } from './../index.js';

const image = open("/home/testuser/POSTFORMDATA/QRCode.png","b");
const fd = new FormData();
export default function() {
fd.append('images', http.file(image, "QRCode.png", "image/png"));
check(http.post("http://server_ip:80/psm/POST/post1.php", fd.body(), {headers: {'Content-Type': 'multipart/form-data; boundary=' + fd.boundary}}), {
  "status is 200": (r) => r.status == 200,
  "protocol is HTTP/1": (r) => r.proto == "HTTP/1.1",
});
}

K6 Command:

k6 run --insecure-skip-tls-verify -d 10s --rps 1 -u 1  /home/testuser/K6JS/http1.js

Attached is the Working PCAP Screenshot taken using Browser

Thanks

Hi there, welcome to the forum :slight_smile:

What do you mean by “non-working”? What is the response you get in both cases? Which version of k6 are you using (output of k6 version)?

I tested against a local httpbin instance, and the form was read correctly.

The sent request copied from Wireshark:

POST /post HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: k6/0.34.1 (https://k6.io/)
Content-Length: 1319
Content-Type: multipart/form-data; boundary=------RWWorkerFormDataBoundary0.cl2y23605do

--------RWWorkerFormDataBoundary0.cl2y23605do
Content-Disposition: form-data; name="images"; filename="logo1.png"
Content-Type: image/png

PNG

IHDROc[...]
--------RWWorkerFormDataBoundary0.cl2y23605do--

And the httpbin response:

{
  "args": {},
  "data": "",
  "files": {
    "images": "data:image/png;base64,iVBORw0[...]"
  },
  "form": {},
  "headers": {
    "Content-Length": "11469",
    "Content-Type": "multipart/form-data; boundary=------RWWorkerFormDataBoundary0.cl2y23605do",
    "Host": "127.0.0.1:8080",
    "User-Agent": "k6/0.34.1 (https://k6.io/)"
  },
  "json": null,
  "origin": "10.0.2.100",
  "url": "http://127.0.0.1:8080/post"
}

One mistake I see in your script is that you’re creating FormData in the init context. This should be done inside the default function, otherwise new iterations will keep appending the same image to the form data. Maybe this is messing up how your server reads it?

Try testing against a local httpbin instance or https://httpbin.test.k6.io/ to confirm you get a valid response.

Thanks for the Warm Welcome. Appreciate that.
What I mean by non working is My Server Says its a Bad Request with 500 HTTP Response Code.
I am using following k6 version:

k6 version

k6 v0.26.0-dev (dev build, go1.12.7, linux/amd64)

Based on your suggestion I tried changing the script as follows again same result:
import http from “k6/http”;
import { check } from “k6”;
import { FormData } from ‘./…/index.js’;

const image = open("/home/aviuser/POSTFORMDATA/QRCode.png",“b”);
export default function() {
const fd = new FormData();
fd.append(‘images’, http.file(image, “QRCode.png”, “image/png”));
check(http.post(“http://server_ip:80/psm/POST/post1.php”, fd.body(), {headers: {‘Content-Type’: ‘multipart/form-data; boundary=’ + fd.boundary}}), {
“status is 200”: (r) => r.status == 200,
“protocol is HTTP/1”: (r) => r.proto == “HTTP/1.1”,
});
}

Below is the Wireshark Capture Screenshot I am seeing from Client Capture

Hi imiric,

The issue here is that packet sent out by k6 is not decodable by both wireshark and my server. If you see the attached screenshot of the Client Capture the MIME Header Data is not getting decoded correctly by wireshark like the way you have shown in your screenshot, which makes me to think client is not sending the POST Request Correctly. Any Idea why this is happening? FYI I am ignoring the Server Response as I see Client itself is not sending the Data Correctly. Also is this below line correct in the Script
import { FormData } from ‘./…/index.js’;
I basically downloaded the index.js from the link: https://jslib.k6.io/formdata/0.0.2/index.js and placed in local directory for reference in the script, I presume the reference made in the script is correct and also I think the index.js file I am using will work with my k6 version?
Here is the HTTP Packet Screenshot:

You are using a very old k6 version. Please upgrade to the latest v0.34.1 and try again.

I was able to reproduce your issue with v0.26.0, so upgrading should fix it.

Sure imiric will try and get back to you.

Thanks
Srikanth

I validated in following k6 version for HTTP Version 1.1, Everything worked as expected.
k6 v0.34.1 (2021-09-16T08:24:44+0000/0628db0, go1.16.8, linux/amd64)

Can you let me know how the same Packets Looks like for HTTP2 Traffic as I see some Packets in Wireshark but I am not seeing multiparts in packet headers for HTTP2. If you can share some screenshots for HTTP2 Traffic just as the way you did for HTTP1.1 Traffic it would be really great.

Below is the screenshot for HTTP2 Post Traffic, I am not sure this is how multipart in HTTP2 should look like or is it a issue in Tool?

Thanks
Srikanth

Since HTTP/2 uses TLS by default and k6 doesn’t support h2c yet, and I don’t have TLS decryption setup in Wireshark, I can’t really capture the HTTP/2 payload to show you an example.

That said, the request body should be exactly the same regardless of the HTTP version used, k6 handles that transparently for you. Wireshark should decode it properly, handle multiplexing, etc. and show you the HTTP conversation. If you right click on a packet and select Follow > HTTP/2 stream it will show you the raw packets, which makes it easier to see how the multipart payload is structured.

Ok No Problem imiric, Finally I was able to Look at the multiparts in the Capture by Filtering Based on Stream ID, Also as you Suggested by Following HTTP/2 Streams. Below is the Screenshot. K6 Latest Version worked as expected with both HTTP1.1 and HTTP2

Thanks
Srikanth