| /* |
| * 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(); |
| } |
| } |
| } |