apache / jmeter

Apache JMeter open-source load testing tool for analyzing and measuring the performance of a variety of services
https://jmeter.apache.org/
Apache License 2.0
8.25k stars 2.09k forks source link

On the fly request body gzipping is broken by utf-8 default encoding #6171

Open dsankouski opened 9 months ago

dsankouski commented 9 months ago

Expected behavior

Given API under test requires gzipped json body, And I created HTTPSampler with a JSR223 preprocessor, which compresses request When I run tests Then server returns 200 reponse code.

Actual behavior

Then server returns 500 code, and says 'not in gzip format'

Steps to reproduce the problem

Test Plan.jmx.gz

Was broken in 7450e4b0497c9a37c44852912e8d3dc2d0ee644e(fix: use UTF-8 as a default encoding in HTTP sampler)

JMeter Version

5.6.1

Java Version

openjdk 17.0.8 2023-07-18

OS Version

Debian GNU/Linux 12 (bookworm)

vlsi commented 9 months ago

Please provide a reproducer. What are you trying to achieve?

dsankouski commented 9 months ago

I'm trying to send http request with gzipped body, however I wish to keep request body in plain text file. I.e. my need is to compress request body just before sending.

I attached Test Plan, and slightly changed the description. However, I did not find any public api to test gzipped request body. I guess it's better to have a unit test for that.

vlsi commented 8 months ago

The code in the sample is

import org.apache.commons.io.IOUtils;
import java.util.zip.GZIPOutputStream;

String bodyString = sampler.getArguments().getArgument(0).getValue();
byte [] requestBody = bodyString.getBytes();

ByteArrayOutputStream out = new ByteArrayOutputStream(requestBody.length);
GZIPOutputStream gzip = new GZIPOutputStream(out);
gzip.write(requestBody);
gzip.close();

sampler.getArguments().getArgument(0).setValue(out.toString(0));

Note that bodyString.getBytes(); uses "default encoding" which is not recommended, and I would suggest using explicit encodings always, or at least use Java 21+ which integrates JEP 400 UTF-8 by default.

I am afraid this is not going to work as it attempts using String where byte[] should be used. Note .toString(0) deprecated method.

As a workaround, you might try iso-8859-1 encoding. That encoding is bytesafe (== it converts byte -> char -> byte without losing contents), however, in any case it would be a workaround only, and the proper solution would be to support byte[] in HTTPArgument.