blob: bd5b36bceb36331f7bf7e713d4abb0be0db0dad1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jmeter.protocol.http.sampler;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.http.util.HTTPArgument;
import org.apache.jmeter.protocol.http.util.HTTPConstants;
import org.apache.jmeter.protocol.http.util.HTTPFileArg;
import org.apache.jorphan.util.JOrphanUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PostWriterTest {
private static final Logger log = LoggerFactory.getLogger(PostWriterTest.class);
private static final String UTF_8 = "UTF-8";
private static final String HTTP_ENCODING = "ISO-8859-1";
private static final byte[] CRLF = { 0x0d, 0x0A };
private static byte[] TEST_FILE_CONTENT;
private StubURLConnection connection;
private HTTPSampler sampler;
private File temporaryFile;
private PostWriter postWriter;
@BeforeEach
public void setUp() throws Exception {
establishConnection();
sampler = new HTTPSampler();// This must be the original (Java) HTTP sampler
postWriter=new PostWriter();
// Create the test file content
TEST_FILE_CONTENT = "foo content &?=01234+56789-|\u2aa1\u266a\u0153\u20a1\u0115\u0364\u00c5\u2052"
.getBytes(UTF_8);
// create a temporary file to make sure we always have a file to give to the PostWriter
// Whereever we are or Whatever the current path is.
temporaryFile = File.createTempFile("foo", "txt");
OutputStream output = null;
try {
output = new FileOutputStream(temporaryFile);
output.write(TEST_FILE_CONTENT);
output.flush();
} finally {
JOrphanUtils.closeQuietly(output);
}
}
@AfterEach
public void tearDown() throws Exception {
// delete temporay file
if(!temporaryFile.delete()) {
fail("Could not delete file:"+temporaryFile.getAbsolutePath());
}
}
/*
* Test method for 'org.apache.jmeter.protocol.http.sampler.postWriter.sendPostData(URLConnection, HTTPSampler)'
* This method test sending a request which contains both formdata and file content
*/
@Test
public void testSendPostData() throws IOException {
sampler.setMethod(HTTPConstants.POST);
setupFilepart(sampler);
String titleValue = "mytitle";
String descriptionValue = "mydescription";
setupFormData(sampler, titleValue, descriptionValue);
// Test sending data with default encoding
String contentEncoding = "";
sampler.setContentEncoding(contentEncoding);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
byte[] expectedFormBody = createExpectedOutput(PostWriter.BOUNDARY, null, titleValue, descriptionValue, TEST_FILE_CONTENT);
checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent());
checkContentLength(connection, expectedFormBody.length);
connection.disconnect();
// Test sending data as ISO-8859-1
establishConnection();
contentEncoding = "ISO-8859-1";
sampler.setContentEncoding(contentEncoding);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
expectedFormBody = createExpectedOutput(PostWriter.BOUNDARY, contentEncoding, titleValue, descriptionValue, TEST_FILE_CONTENT);
checkContentLength(connection, expectedFormBody.length);
checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent());
connection.disconnect();
// Test sending data as UTF-8
establishConnection();
titleValue = "mytitle\u0153\u20a1\u0115\u00c5";
descriptionValue = "mydescription\u0153\u20a1\u0115\u00c5";
contentEncoding = UTF_8;
sampler.setContentEncoding(contentEncoding);
setupFormData(sampler, titleValue, descriptionValue);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
expectedFormBody = createExpectedOutput(PostWriter.BOUNDARY, contentEncoding, titleValue, descriptionValue, TEST_FILE_CONTENT);
checkContentLength(connection, expectedFormBody.length);
checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent());
connection.disconnect();
// Test sending UTF-8 data with ISO-8859-1 content encoding
establishConnection();
contentEncoding = UTF_8;
sampler.setContentEncoding("ISO-8859-1");
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
expectedFormBody = createExpectedOutput(PostWriter.BOUNDARY, contentEncoding, titleValue, descriptionValue, TEST_FILE_CONTENT);
checkContentLength(connection, expectedFormBody.length);
checkArraysHaveDifferentContent(expectedFormBody, connection.getOutputStreamContent());
connection.disconnect();
}
/*
* Test method for 'org.apache.jmeter.protocol.http.sampler.postWriter.sendPostData(URLConnection, HTTPSampler)'
* This method test sending a HTTPSampler with form parameters, and only
* the filename of a file.
*/
@Test
public void testSendPostData_NoFilename() throws IOException {
setupNoFilename(sampler);
sampler.setMethod(HTTPConstants.POST);
String titleValue = "mytitle";
String descriptionValue = "mydescription";
setupFormData(sampler, titleValue, descriptionValue);
// Test sending data with default encoding
String contentEncoding = "";
sampler.setContentEncoding(contentEncoding);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkNoContentType(connection);
byte[] expectedUrl = "title=mytitle&description=mydescription".getBytes(StandardCharsets.UTF_8);
checkContentLength(connection, expectedUrl.length);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
expectedUrl = "title=mytitle&description=mydescription".getBytes(UTF_8);
checkContentLength(connection, expectedUrl.length);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
connection.disconnect();
// Test sending data as ISO-8859-1
establishConnection();
contentEncoding = "ISO-8859-1";
sampler.setContentEncoding(contentEncoding);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkNoContentType(connection);
expectedUrl = "title=mytitle&description=mydescription".getBytes(contentEncoding);
checkContentLength(connection, expectedUrl.length);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
expectedUrl = "title=mytitle&description=mydescription".getBytes(UTF_8);
checkContentLength(connection, expectedUrl.length);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
connection.disconnect();
}
/*
* Test method for 'org.apache.jmeter.protocol.http.sampler.postWriter.sendPostData(URLConnection, HTTPSampler)'
* This method test sending file content as the only content of the post body
*/
@Test
public void testSendPostData_FileAsBody() throws IOException {
sampler.setMethod(HTTPConstants.POST);
setupFilepart(sampler, "", temporaryFile, "");
// Check using default encoding
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentLength(connection, TEST_FILE_CONTENT.length);
checkArraysHaveSameContent(TEST_FILE_CONTENT, connection.getOutputStreamContent());
connection.disconnect();
// Check using a different encoding
String otherEncoding;
final String fileEncoding = System.getProperty( "file.encoding");// $NON-NLS-1$
log.info("file.encoding: {}", fileEncoding);
if (UTF_8.equalsIgnoreCase(fileEncoding) || "UTF8".equalsIgnoreCase(fileEncoding)){// $NON-NLS-1$
otherEncoding="ISO-8859-1"; // $NON-NLS-1$
} else {
otherEncoding=UTF_8;
}
log.info("Using other encoding: {}", otherEncoding);
establishConnection();
sampler.setContentEncoding(otherEncoding);
// File content is sent as binary, so the content encoding should not change the file data
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentLength(connection, TEST_FILE_CONTENT.length);
checkArraysHaveSameContent(TEST_FILE_CONTENT, connection.getOutputStreamContent());
// Check that other encoding is not the current encoding
checkArraysHaveDifferentContent(new String(TEST_FILE_CONTENT, Charset.defaultCharset()) // TODO - charset?
.getBytes(otherEncoding), connection.getOutputStreamContent());
// If we have both file as body, and form data, then only form data will be sent
setupFormData(sampler);
establishConnection();
sampler.setContentEncoding("");
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkNoContentType(connection);
byte[] expectedUrl = "title=mytitle&description=mydescription"
.getBytes(Charset.defaultCharset()); // TODO - charset?
checkContentLength(connection, expectedUrl.length);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
}
/*
* Test method for 'org.apache.jmeter.protocol.http.sampler.postWriter.sendPostData(URLConnection, HTTPSampler)'
* This method test sending only a file multipart.
*/
@Test
public void testSendFileData_Multipart() throws IOException {
sampler.setMethod(HTTPConstants.POST);
String fileField = "upload";
String mimeType = "text/plain";
File file = temporaryFile;
byte[] fileContent = TEST_FILE_CONTENT;
setupFilepart(sampler, fileField, file, mimeType);
// Test sending data with default encoding
String contentEncoding = "";
sampler.setContentEncoding(contentEncoding);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
byte[] expectedFormBody = createExpectedFilepartOutput(PostWriter.BOUNDARY, fileField, file, mimeType, fileContent, true, true);
checkContentLength(connection, expectedFormBody.length);
checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent());
connection.disconnect();
// Test sending data as ISO-8859-1
establishConnection();
contentEncoding = "ISO-8859-1";
sampler.setContentEncoding(contentEncoding);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
expectedFormBody = createExpectedFilepartOutput(PostWriter.BOUNDARY, fileField, file, mimeType, fileContent, true, true);
checkContentLength(connection, expectedFormBody.length);
checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent());
connection.disconnect();
// Test sending data as UTF-8
establishConnection();
fileField = "some_file_field";
mimeType = "image/png";
contentEncoding = UTF_8;
sampler.setContentEncoding(contentEncoding);
setupFilepart(sampler, fileField, file, mimeType);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
expectedFormBody = createExpectedFilepartOutput(PostWriter.BOUNDARY, fileField, file, mimeType, fileContent, true, true);
checkContentLength(connection, expectedFormBody.length);
checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent());
connection.disconnect();
}
/*
* Test method for 'org.apache.jmeter.protocol.http.sampler.postWriter.sendPostData(URLConnection, HTTPSampler)'
* This method test sending only a formdata, as a multipart/form-data request.
*/
@Test
public void testSendFormData_Multipart() throws IOException {
sampler.setMethod(HTTPConstants.POST);
String titleField = "title";
String titleValue = "mytitle";
String descriptionField = "description";
String descriptionValue = "mydescription";
setupFormData(sampler, titleValue, descriptionValue);
// Tell sampler to do multipart, even if we have no files to upload
sampler.setDoMultipart(true);
// Test sending data with default encoding
String contentEncoding = "";
sampler.setContentEncoding(contentEncoding);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
byte[] expectedFormBody = createExpectedFormdataOutput(
PostWriter.BOUNDARY, null, titleField, titleValue,
descriptionField, descriptionValue, true, true);
checkContentLength(connection, expectedFormBody.length);
checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent());
connection.disconnect();
// Test sending data as ISO-8859-1
establishConnection();
contentEncoding = "ISO-8859-1";
sampler.setContentEncoding(contentEncoding);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
expectedFormBody = createExpectedFormdataOutput(PostWriter.BOUNDARY,
contentEncoding, titleField, titleValue, descriptionField,
descriptionValue, true, true);
checkContentLength(connection, expectedFormBody.length);
checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent());
connection.disconnect();
// Test sending data as ISO-8859-1, with values that need to be urlencoded
establishConnection();
titleValue = "mytitle+123 456&yes";
descriptionValue = "mydescription and some spaces";
contentEncoding = "ISO-8859-1";
sampler.setContentEncoding(contentEncoding);
setupFormData(sampler, titleValue, descriptionValue);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
expectedFormBody = createExpectedFormdataOutput(PostWriter.BOUNDARY,
contentEncoding, titleField, titleValue, descriptionField,
descriptionValue, true, true);
checkContentLength(connection, expectedFormBody.length);
checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent());
connection.disconnect();
// Test sending data as UTF-8
establishConnection();
titleValue = "mytitle\u0153\u20a1\u0115\u00c5";
descriptionValue = "mydescription\u0153\u20a1\u0115\u00c5";
contentEncoding = UTF_8;
sampler.setContentEncoding(contentEncoding);
setupFormData(sampler, titleValue, descriptionValue);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
expectedFormBody = createExpectedFormdataOutput(PostWriter.BOUNDARY,
contentEncoding, titleField, titleValue, descriptionField,
descriptionValue, true, true);
checkContentLength(connection, expectedFormBody.length);
checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent());
connection.disconnect();
// Test sending data as UTF-8, with values that would have been urlencoded
// if it was not sent as multipart
establishConnection();
titleValue = "mytitle\u0153+\u20a1 \u0115&yes\u00c5";
descriptionValue = "mydescription \u0153 \u20a1 \u0115 \u00c5";
contentEncoding = UTF_8;
sampler.setContentEncoding(contentEncoding);
setupFormData(sampler, titleValue, descriptionValue);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
expectedFormBody = createExpectedFormdataOutput(PostWriter.BOUNDARY,
contentEncoding, titleField, titleValue, descriptionField,
descriptionValue, true, true);
checkContentLength(connection, expectedFormBody.length);
checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent());
connection.disconnect();
}
/*
* Test method for 'org.apache.jmeter.protocol.http.sampler.postWriter.sendPostData(URLConnection, HTTPSampler)'
* This method test sending only a formdata, as urlencoded data
*/
@Test
public void testSendFormData_Urlencoded() throws IOException {
String titleValue = "mytitle";
String descriptionValue = "mydescription";
setupFormData(sampler, titleValue, descriptionValue);
// Test sending data with default encoding
String contentEncoding = "";
sampler.setContentEncoding(contentEncoding);
sampler.setMethod(HTTPConstants.POST);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkNoContentType(connection);
byte[] expectedUrl = ("title=" + titleValue + "&description=" + descriptionValue).getBytes("US-ASCII");
checkContentLength(connection, expectedUrl.length);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
assertEquals(
URLDecoder.decode(new String(expectedUrl, "US-ASCII"), "ISO-8859-1"),
URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), "ISO-8859-1"));
connection.disconnect();
// Test sending data as ISO-8859-1
establishConnection();
contentEncoding = "ISO-8859-1";
sampler.setContentEncoding(contentEncoding);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkNoContentType(connection);
expectedUrl = new StringBuilder("title=").append(titleValue).append("&description=")
.append(descriptionValue).toString().getBytes("US-ASCII");
checkContentLength(connection, expectedUrl.length);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
assertEquals(
URLDecoder.decode(new String(expectedUrl, "US-ASCII"), contentEncoding),
URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), contentEncoding));
connection.disconnect();
// Test sending data as ISO-8859-1, with values that need to be urlencoded
establishConnection();
titleValue = "mytitle+123 456&yes";
descriptionValue = "mydescription and some spaces";
contentEncoding = "ISO-8859-1";
sampler.setContentEncoding(contentEncoding);
setupFormData(sampler, titleValue, descriptionValue);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkNoContentType(connection);
String expectedString = "title="
+ URLEncoder.encode(titleValue, contentEncoding)
+ "&description="
+ URLEncoder.encode(descriptionValue, contentEncoding);
expectedUrl = expectedString.getBytes(contentEncoding);
checkContentLength(connection, expectedUrl.length);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
assertEquals(
URLDecoder.decode(new String(expectedUrl, "US-ASCII"), contentEncoding),
URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), contentEncoding));
String unencodedString = "title=" + titleValue + "&description=" + descriptionValue;
byte[] unexpectedUrl = unencodedString.getBytes(UTF_8);
checkArraysHaveDifferentContent(unexpectedUrl, connection.getOutputStreamContent());
connection.disconnect();
// Test sending data as UTF-8
establishConnection();
titleValue = "mytitle\u0153\u20a1\u0115\u00c5";
descriptionValue = "mydescription\u0153\u20a1\u0115\u00c5";
contentEncoding = UTF_8;
sampler.setContentEncoding(contentEncoding);
setupFormData(sampler, titleValue, descriptionValue);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkNoContentType(connection);
expectedString = "title="
+ URLEncoder.encode(titleValue, contentEncoding)
+ "&description="
+ URLEncoder.encode(descriptionValue, contentEncoding);
expectedUrl = expectedString.getBytes("US-ASCII");
checkContentLength(connection, expectedUrl.length);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
assertEquals(
URLDecoder.decode(new String(expectedUrl, "US-ASCII"), contentEncoding),
URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), contentEncoding));
connection.disconnect();
// Test sending data as UTF-8, with values that needs to be urlencoded
establishConnection();
titleValue = "mytitle\u0153+\u20a1 \u0115&yes\u00c5";
descriptionValue = "mydescription \u0153 \u20a1 \u0115 \u00c5";
contentEncoding = UTF_8;
sampler.setContentEncoding(contentEncoding);
setupFormData(sampler, titleValue, descriptionValue);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkNoContentType(connection);
expectedString = "title=" + URLEncoder.encode(titleValue, UTF_8) + "&description=" + URLEncoder.encode(descriptionValue, UTF_8);
expectedUrl = expectedString.getBytes("US-ASCII");
checkContentLength(connection, expectedUrl.length);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
assertEquals(
URLDecoder.decode(new String(expectedUrl, "US-ASCII"), contentEncoding),
URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), contentEncoding));
unencodedString = "title=" + titleValue + "&description=" + descriptionValue;
unexpectedUrl = unencodedString.getBytes("US-ASCII");
checkArraysHaveDifferentContent(unexpectedUrl, connection.getOutputStreamContent());
connection.disconnect();
// Test sending parameters which are urlencoded beforehand
// The values must be URL encoded with UTF-8 encoding, because that
// is what the HTTPArgument assumes
// %C3%85 in UTF-8 is the same as %C5 in ISO-8859-1, which is the same as Å
titleValue = "mytitle%20and%20space%2Ftest%C3%85";
descriptionValue = "mydescription+and+plus+as+space%2Ftest%C3%85";
setupFormData(sampler, true, titleValue, descriptionValue);
// Test sending data with default encoding
establishConnection();
contentEncoding = "";
sampler.setContentEncoding(contentEncoding);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkNoContentType(connection);
StringBuilder sb = new StringBuilder();
expectedUrl = sb.append("title=").append(titleValue.replaceAll("%20", "+"))
.append("&description=").append(descriptionValue).toString().getBytes(StandardCharsets.UTF_8);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
checkContentLength(connection, expectedUrl.length);
assertEquals(
// HTTPSampler uses UTF-8 as default encoding
URLDecoder.decode(new String(expectedUrl, StandardCharsets.UTF_8), "UTF-8"),
URLDecoder.decode(new String(connection.getOutputStreamContent(), StandardCharsets.UTF_8), "UTF-8"));
connection.disconnect();
// Test sending data as ISO-8859-1
establishConnection();
contentEncoding = "ISO-8859-1";
sampler.setContentEncoding(contentEncoding);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkNoContentType(connection);
sb = new StringBuilder();
expectedUrl = sb.append("title=").append(titleValue.replaceAll("%20", "+").replaceAll("%C3%85", "%C5"))
.append("&description=").append(descriptionValue.replaceAll("%C3%85", "%C5")).toString().getBytes("US-ASCII");
checkContentLength(connection, expectedUrl.length);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
assertEquals(
URLDecoder.decode(new String(expectedUrl, "US-ASCII"), contentEncoding),
URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), contentEncoding));
connection.disconnect();
// Test sending data as UTF-8
establishConnection();
contentEncoding = UTF_8;
sampler.setContentEncoding(contentEncoding);
postWriter.setHeaders(connection, sampler);
postWriter.sendPostData(connection, sampler);
checkNoContentType(connection);
sb = new StringBuilder();
expectedUrl = sb.append("title=")
.append(titleValue.replaceAll("%20", "+"))
.append("&description=").append(descriptionValue).toString()
.getBytes("US-ASCII");
checkContentLength(connection, expectedUrl.length);
checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent());
assertEquals(
URLDecoder.decode(new String(expectedUrl, "US-ASCII"), contentEncoding),
URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), contentEncoding));
connection.disconnect();
}
/*
* Test method for 'org.apache.jmeter.protocol.http.sampler.postWriter.setHeaders(URLConnection, HTTPSampler)'
*/
@Test
public void testSetHeaders() throws IOException {
sampler.setMethod(HTTPConstants.POST);
setupFilepart(sampler);
setupFormData(sampler);
postWriter.setHeaders(connection, sampler);
checkContentTypeMultipart(connection, PostWriter.BOUNDARY);
}
/*
* Test method for 'org.apache.jmeter.protocol.http.sampler.postWriter.setHeaders(URLConnection, HTTPSampler)'
*/
@Test
public void testSetHeaders_NoFilename() throws IOException {
sampler.setMethod(HTTPConstants.POST);
setupNoFilename(sampler);
setupFormData(sampler);
postWriter.setHeaders(connection, sampler);
checkNoContentType(connection);
checkContentLength(connection, "title=mytitle&description=mydescription".length());
}
/** setup commons parts of HTTPSampler with a no filename. */
private void setupNoFilename(HTTPSampler httpSampler) {
setupFilepart(httpSampler, "upload", null, "application/octet-stream");
}
private void setupFilepart(HTTPSampler httpSampler) {
setupFilepart(httpSampler, "upload", temporaryFile, "text/plain");
}
private void setupFilepart(HTTPSampler httpSampler, String fileField, File file, String mimeType) {
HTTPFileArg[] hfa = {new HTTPFileArg(file == null ? "" : file.getAbsolutePath(), fileField, mimeType)};
httpSampler.setHTTPFiles(hfa);
}
private void setupFormData(HTTPSampler httpSampler) {
setupFormData(httpSampler, "mytitle", "mydescription");
}
private void setupFormData(HTTPSampler httpSampler, String titleValue, String descriptionValue) {
setupFormData(httpSampler, false, titleValue, descriptionValue);
}
private void setupFormData(HTTPSampler httpSampler, boolean isEncoded, String titleValue, String descriptionValue) {
Arguments args = new Arguments();
HTTPArgument argument1 = new HTTPArgument("title", titleValue, isEncoded);
HTTPArgument argument2 = new HTTPArgument("description", descriptionValue, isEncoded);
args.addArgument(argument1);
args.addArgument(argument2);
httpSampler.setArguments(args);
}
private void establishConnection() throws MalformedURLException {
connection = new StubURLConnection("http://fake_url/test");
}
/**
* Create the expected output post body for form data and file multiparts
* with default values for field names
*/
private byte[] createExpectedOutput(
String boundaryString,
String contentEncoding,
String titleValue,
String descriptionValue,
byte[] fileContent) throws IOException {
return createExpectedOutput(boundaryString, contentEncoding, "title",
titleValue, "description", descriptionValue, "upload",
fileContent);
}
/**
* Create the expected output post body for form data and file multiparts
* with specified values
*/
private byte[] createExpectedOutput(
String boundaryString,
String contentEncoding,
String titleField,
String titleValue,
String descriptionField,
String descriptionValue,
String fileField,
byte[] fileContent) throws IOException {
// Create the multiparts
byte[] formdataMultipart = createExpectedFormdataOutput(boundaryString,
contentEncoding, titleField, titleValue, descriptionField,
descriptionValue, true, false);
byte[] fileMultipart = createExpectedFilepartOutput(boundaryString,
fileField, temporaryFile, "text/plain", fileContent, false,
true);
// Join the two multiparts
ByteArrayOutputStream output = new ByteArrayOutputStream();
output.write(formdataMultipart);
output.write(fileMultipart);
output.flush();
output.close();
return output.toByteArray();
}
/**
* Create the expected output multipart/form-data, with only form data,
* and no file multipart
*
* @param lastMultipart true if this is the last multipart in the request
*/
private byte[] createExpectedFormdataOutput(
String boundaryString,
String contentEncoding,
String titleField,
String titleValue,
String descriptionField,
String descriptionValue,
boolean firstMultipart,
boolean lastMultipart) throws IOException {
final byte[] DASH_DASH = "--".getBytes(HTTP_ENCODING);
// All form parameter always have text/plain as mime type
final String mimeType="text/plain";//TODO make this a parameter?
final ByteArrayOutputStream output = new ByteArrayOutputStream();
if(firstMultipart) {
output.write(DASH_DASH);
output.write(boundaryString.getBytes(HTTP_ENCODING));
output.write(CRLF);
}
output.write("Content-Disposition: form-data; name=\"".getBytes(HTTP_ENCODING));
output.write(titleField.getBytes(HTTP_ENCODING));
output.write("\"".getBytes(HTTP_ENCODING));
output.write(CRLF);
output.write("Content-Type: ".getBytes(HTTP_ENCODING));
output.write(mimeType.getBytes(HTTP_ENCODING));
output.write("; charset=".getBytes(HTTP_ENCODING));
output.write((contentEncoding==null ? PostWriter.ENCODING : contentEncoding).getBytes(HTTP_ENCODING));
output.write(CRLF);
output.write("Content-Transfer-Encoding: 8bit".getBytes(HTTP_ENCODING));
output.write(CRLF);
output.write(CRLF);
if(contentEncoding != null) {
output.write(titleValue.getBytes(contentEncoding));
}
else {
output.write(titleValue.getBytes(Charset.defaultCharset())); // TODO - charset?
}
output.write(CRLF);
output.write(DASH_DASH);
output.write(boundaryString.getBytes(HTTP_ENCODING));
output.write(CRLF);
output.write("Content-Disposition: form-data; name=\"".getBytes(HTTP_ENCODING));
output.write(descriptionField.getBytes(HTTP_ENCODING));
output.write("\"".getBytes(HTTP_ENCODING));
output.write(CRLF);
output.write("Content-Type: ".getBytes(HTTP_ENCODING));
output.write(mimeType.getBytes(HTTP_ENCODING));
output.write("; charset=".getBytes(HTTP_ENCODING));
output.write((contentEncoding==null ? PostWriter.ENCODING : contentEncoding).getBytes(HTTP_ENCODING));
output.write(CRLF);
output.write("Content-Transfer-Encoding: 8bit".getBytes(HTTP_ENCODING));
output.write(CRLF);
output.write(CRLF);
if(contentEncoding != null) {
output.write(descriptionValue.getBytes(contentEncoding));
}
else {
output.write(descriptionValue.getBytes(Charset.defaultCharset())); // TODO - charset?
}
output.write(CRLF);
output.write(DASH_DASH);
output.write(boundaryString.getBytes(HTTP_ENCODING));
if(lastMultipart) {
output.write(DASH_DASH);
}
output.write(CRLF);
output.flush();
output.close();
return output.toByteArray();
}
/**
* Create the expected file multipart
*
* @param lastMultipart true if this is the last multipart in the request
*/
private byte[] createExpectedFilepartOutput(
String boundaryString,
String fileField,
File file,
String mimeType,
byte[] fileContent,
boolean firstMultipart,
boolean lastMultipart) throws IOException {
// The encoding used for http headers and control information
final String httpEncoding = "ISO-8859-1";
final byte[] DASH_DASH = "--".getBytes(httpEncoding);
final ByteArrayOutputStream output = new ByteArrayOutputStream();
if(firstMultipart) {
output.write(DASH_DASH);
output.write(boundaryString.getBytes(httpEncoding));
output.write(CRLF);
}
// replace all backslash with double backslash
String filename = file.getName();
output.write("Content-Disposition: form-data; name=\"".getBytes(httpEncoding));
output.write(fileField.getBytes(httpEncoding));
output.write(("\"; filename=\"" + filename + "\"").getBytes(httpEncoding));
output.write(CRLF);
output.write("Content-Type: ".getBytes(httpEncoding));
output.write(mimeType.getBytes(httpEncoding));
output.write(CRLF);
output.write("Content-Transfer-Encoding: binary".getBytes(httpEncoding));
output.write(CRLF);
output.write(CRLF);
output.write(fileContent);
output.write(CRLF);
output.write(DASH_DASH);
output.write(boundaryString.getBytes(httpEncoding));
if(lastMultipart) {
output.write(DASH_DASH);
}
output.write(CRLF);
output.flush();
output.close();
return output.toByteArray();
}
/**
* Check that the two byte arrays have identical content
*/
private void checkArraysHaveSameContent(byte[] expected, byte[] actual) throws UnsupportedEncodingException {
if(expected != null && actual != null) {
if(expected.length != actual.length) {
System.out.println(new String(expected,UTF_8));
System.out.println("--------------------");
System.out.println(new String(actual,UTF_8));
System.out.println("====================");
fail("arrays have different length, expected is " + expected.length + ", actual is " + actual.length);
}
else {
for(int i = 0; i < expected.length; i++) {
if(expected[i] != actual[i]) {
System.out.println(new String(expected,0,i+1, UTF_8));
System.out.println("--------------------");
System.out.println(new String(actual,0,i+1, UTF_8));
System.out.println("====================");
fail("byte at position " + i + " is different, expected is " + expected[i] + ", actual is " + actual[i]);
}
}
}
}
else {
fail("expected or actual byte arrays were null");
}
}
/**
* Check that the two byte arrays different content
*/
private void checkArraysHaveDifferentContent(byte[] expected, byte[] actual) {
if(expected != null && actual != null) {
if(expected.length == actual.length) {
boolean allSame = true;
for(int i = 0; i < expected.length; i++) {
if(expected[i] != actual[i]) {
allSame = false;
break;
}
}
if(allSame) {
fail("all bytes were equal");
}
}
}
else {
fail("expected or actual byte arrays were null");
}
}
private void checkContentTypeMultipart(HttpURLConnection conn, String boundaryString) {
assertEquals("multipart/form-data; boundary=" + boundaryString, conn.getRequestProperty(HTTPConstants.HEADER_CONTENT_TYPE));
}
private void checkNoContentType(HttpURLConnection conn) {
assertNull(conn.getRequestProperty(HTTPConstants.HEADER_CONTENT_TYPE));
}
private void checkContentLength(HttpURLConnection conn, int length) {
assertEquals(Integer.toString(length), conn.getRequestProperty(HTTPConstants.HEADER_CONTENT_LENGTH));
}
/**
* Mock an HttpURLConnection.
* extends HttpURLConnection instead of just URLConnection because there is a cast in PostWriter.
*/
private static class StubURLConnection extends HttpURLConnection {
private ByteArrayOutputStream output = new ByteArrayOutputStream();
private Map<String, String> properties = new HashMap<>();
public StubURLConnection(String url) throws MalformedURLException {
super(new URL(url));
}
@Override
public void connect() throws IOException {
}
@Override
public OutputStream getOutputStream() throws IOException {
return output;
}
@Override
public void disconnect() {
}
@Override
public boolean usingProxy() {
return false;
}
@Override
public String getRequestProperty(String key) {
return properties.get(key);
}
@Override
public void setRequestProperty(String key, String value) {
properties.put(key, value);
}
public byte[] getOutputStreamContent() {
return output.toByteArray();
}
}
}