You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2018/04/05 19:10:44 UTC
svn commit: r1828467 - in /jmeter/trunk: bin/
src/core/org/apache/jmeter/resources/
src/protocol/http/org/apache/jmeter/protocol/http/config/
src/protocol/http/org/apache/jmeter/protocol/http/config/gui/
src/protocol/http/org/apache/jmeter/protocol/htt...
Author: pmouawad
Date: Thu Apr 5 19:10:44 2018
New Revision: 1828467
URL: http://svn.apache.org/viewvc?rev=1828467&view=rev
Log:
Bug 62260 - Improve Rest support
This also fixes:
- Bug 60190 - Content-Type is added for POST unconditionally
Bug 60015 - Multipart/form-data works only for POST using HTTPClient4 while it should for PUT, DELETE...
Contributed by UbikLoadPack
Bugzilla Id: 62260
Modified:
jmeter/trunk/bin/jmeter.properties
jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/config/MultipartUrlConfig.java
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/config/gui/UrlConfigGui.java
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/HTTPArgumentsPanel.java
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/DefaultSamplerCreator.java
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPAbstractImpl.java
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPHC4Impl.java
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPJavaImpl.java
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/PostWriter.java
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/HTTPArgument.java
jmeter/trunk/test/src/org/apache/jmeter/protocol/http/sampler/PostWriterTest.java
jmeter/trunk/test/src/org/apache/jmeter/protocol/http/sampler/TestHTTPSamplersAgainstHttpMirrorServer.java
jmeter/trunk/xdocs/changes.xml
jmeter/trunk/xdocs/usermanual/properties_reference.xml
Modified: jmeter/trunk/bin/jmeter.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/jmeter.properties?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/bin/jmeter.properties (original)
+++ jmeter/trunk/bin/jmeter.properties Thu Apr 5 19:10:44 2018
@@ -336,6 +336,16 @@ remote_hosts=127.0.0.1
#includecontroller.prefix=
#---------------------------------------------------------------------------
+# Shared HTTP configuration between HC4 and Java Implementations
+#---------------------------------------------------------------------------
+
+#
+# Should JMeter add to POST request content-type header if missing:
+# Content-Type: application/x-www-form-urlencoded
+# Was true before version 4.1
+#post_add_content_type_if_missing=false
+
+#---------------------------------------------------------------------------
# HTTP Java configuration
#---------------------------------------------------------------------------
Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Thu Apr 5 19:10:44 2018
@@ -220,6 +220,7 @@ constant_timer_delay=Thread Delay (in mi
constant_timer_memo=Add a constant delay between sampling
constant_timer_title=Constant Timer
content_encoding=Content encoding\:
+content_type=Content-Type
controller=Controller
cookie_implementation_choose=Implementation:
cookie_manager_policy=Cookie Policy:
@@ -303,7 +304,7 @@ email_results_title=Email Results
en=English
enable=Enable
encode=URL Encode
-encode?=Encode?
+encode?=URL Encode?
encoded_value=URL Encoded Value
entry_dn=Entry DN
entrydn=Entry DN
@@ -1284,7 +1285,7 @@ urlencode_string=String to encode in URL
use_custom_dns_resolver=Use custom DNS resolver
use_expires=Use Cache-Control/Expires header when processing GET requests
use_keepalive=Use KeepAlive
-use_multipart_for_http_post=Use multipart/form-data for POST
+use_multipart_for_http_post=Use multipart/form-data
use_multipart_mode_browser=Browser-compatible headers
use_recording_controller=Use Recording Controller
use_system_dns_resolver=Use system DNS resolver
Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties Thu Apr 5 19:10:44 2018
@@ -215,6 +215,7 @@ constant_timer_delay=D\u00E9lai d'attent
constant_timer_memo=Ajouter un d\u00E9lai fixe entre les \u00E9chantillions de test
constant_timer_title=Compteur de temps fixe
content_encoding=Encodage contenu \:
+content_type=Content-Type
controller=Contr\u00F4leur
cookie_implementation_choose=Impl\u00E9mentation \:
cookie_manager_policy=Politique des cookies \:
@@ -298,7 +299,7 @@ email_results_title=R\u00E9sultat d'emai
en=Anglais
enable=Activer
encode=URL Encoder
-encode?=Encodage
+encode?=URL Encoder
encoded_value=Valeur de l'URL encod\u00E9e
entry_dn=Entr\u00E9e DN \:
entrydn=Entr\u00E9e DN
Modified: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/config/MultipartUrlConfig.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/config/MultipartUrlConfig.java?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/config/MultipartUrlConfig.java (original)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/config/MultipartUrlConfig.java Thu Apr 5 19:10:44 2018
@@ -20,6 +20,7 @@ package org.apache.jmeter.protocol.http.
import java.io.Serializable;
+import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.http.util.HTTPArgument;
import org.apache.jmeter.protocol.http.util.HTTPFileArgs;
@@ -36,6 +37,12 @@ public class MultipartUrlConfig implemen
private static final long serialVersionUID = 240L;
+ private static final String CRLF = "\r\n";
+ private static final String CRLFCRLF = "\r\n\r\n";
+ // Code also allows for LF only (not sure why - perhaps because the test code uses it?)
+ private static final String LF = "\n";
+ private static final String LFLF = "\n\n";
+
private final String boundary;
private final Arguments args;
@@ -89,11 +96,20 @@ public class MultipartUrlConfig implemen
*
* @param name
* @param value
+ * @param contentType can include charset or not, for example: "application/json; charset=UTF-8" or "application/json"
*/
- private void addNonEncodedArgument(String name, String value) {
+ private void addNonEncodedArgument(String name, String value, String contentType) {
Arguments myArgs = getArguments();
// The value is not encoded
HTTPArgument arg = new HTTPArgument(name, value, false);
+ if(!StringUtils.isEmpty(contentType)) {
+ int indexOfSemiColon = contentType.indexOf(';');
+ if(indexOfSemiColon > 0) {
+ arg.setContentType(contentType.substring(0, indexOfSemiColon));
+ } else {
+ arg.setContentType(contentType);
+ }
+ }
// Let the GUI show that it will not be encoded
arg.setAlwaysEncoded(false);
myArgs.addArgument(arg);
@@ -131,11 +147,6 @@ public class MultipartUrlConfig implemen
} else {
// Find the first empty line of the multipart, it signals end of headers for multipart
// Agents are supposed to terminate lines in CRLF:
- final String CRLF = "\r\n";
- final String CRLFCRLF = "\r\n\r\n";
- // Code also allows for LF only (not sure why - perhaps because the test code uses it?)
- final String LF = "\n";
- final String LFLF = "\n\n";
int indexEmptyCrLfCrLfLinePos = part.indexOf(CRLFCRLF); //$NON-NLS-1$
int indexEmptyLfLfLinePos = part.indexOf(LFLF); //$NON-NLS-1$
String value = null;
@@ -144,13 +155,13 @@ public class MultipartUrlConfig implemen
} else if (indexEmptyLfLfLinePos > -1) { // LF blank line found
value = part.substring(indexEmptyLfLfLinePos + LFLF.length(), part.lastIndexOf(LF));
}
- this.addNonEncodedArgument(name, value);
+ this.addNonEncodedArgument(name, value, contentType);
}
}
}
}
-
- private String getHeaderValue(String headerName, String multiPart) {
+
+ private static String getHeaderValue(String headerName, String multiPart) {
String regularExpression = headerName + "\\s*:\\s*(.*)$"; //$NON-NLS-1$
Perl5Matcher localMatcher = JMeterUtils.getMatcher();
Pattern pattern = JMeterUtils.getPattern(regularExpression,
Modified: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/config/gui/UrlConfigGui.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/config/gui/UrlConfigGui.java?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/config/gui/UrlConfigGui.java (original)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/config/gui/UrlConfigGui.java Thu Apr 5 19:10:44 2018
@@ -26,7 +26,6 @@ import java.awt.Font;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
-import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;
@@ -43,7 +42,6 @@ import org.apache.jmeter.protocol.http.g
import org.apache.jmeter.protocol.http.gui.HTTPFileArgsPanel;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
import org.apache.jmeter.protocol.http.util.HTTPArgument;
-import org.apache.jmeter.protocol.http.util.HTTPConstants;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.property.BooleanProperty;
import org.apache.jmeter.testelement.property.JMeterProperty;
@@ -95,7 +93,7 @@ public class UrlConfigGui extends JPanel
private JCheckBox useKeepAlive;
- private JCheckBox useMultipartForPost;
+ private JCheckBox useMultipart;
private JCheckBox useBrowserCompatibleMultipartMode;
@@ -162,7 +160,7 @@ public class UrlConfigGui extends JPanel
autoRedirects.setSelected(false);
method.setText(HTTPSamplerBase.DEFAULT_METHOD);
useKeepAlive.setSelected(true);
- useMultipartForPost.setSelected(false);
+ useMultipart.setSelected(false);
useBrowserCompatibleMultipartMode.setSelected(HTTPSamplerBase.BROWSER_COMPATIBLE_MULTIPART_MODE_DEFAULT);
}
path.setText(""); // $NON-NLS-1$
@@ -195,7 +193,7 @@ public class UrlConfigGui extends JPanel
* @param element {@link TestElement} to modify
*/
public void modifyTestElement(TestElement element) {
- boolean useRaw = postContentTabbedPane.getSelectedIndex()==tabRawBodyIndex;
+ boolean useRaw = !postBodyContent.getText().isEmpty();
Arguments args;
if(useRaw) {
args = new Arguments();
@@ -213,9 +211,9 @@ public class UrlConfigGui extends JPanel
} else {
args = (Arguments) argsPanel.createTestElement();
HTTPArgument.convertArgumentsToHTTP(args);
- if(showFileUploadPane) {
- filesPanel.modifyTestElement(element);
- }
+ }
+ if(showFileUploadPane) {
+ filesPanel.modifyTestElement(element);
}
element.setProperty(HTTPSamplerBase.POST_BODY_RAW, useRaw, HTTPSamplerBase.POST_BODY_RAW_DEFAULT);
element.setProperty(new TestElementProperty(HTTPSamplerBase.ARGUMENTS, args));
@@ -229,14 +227,13 @@ public class UrlConfigGui extends JPanel
element.setProperty(new BooleanProperty(HTTPSamplerBase.FOLLOW_REDIRECTS, followRedirects.isSelected()));
element.setProperty(new BooleanProperty(HTTPSamplerBase.AUTO_REDIRECTS, autoRedirects.isSelected()));
element.setProperty(new BooleanProperty(HTTPSamplerBase.USE_KEEPALIVE, useKeepAlive.isSelected()));
- element.setProperty(new BooleanProperty(HTTPSamplerBase.DO_MULTIPART_POST, useMultipartForPost.isSelected()));
+ element.setProperty(new BooleanProperty(HTTPSamplerBase.DO_MULTIPART_POST, useMultipart.isSelected()));
element.setProperty(HTTPSamplerBase.BROWSER_COMPATIBLE_MULTIPART,
useBrowserCompatibleMultipartMode.isSelected(),
HTTPSamplerBase.BROWSER_COMPATIBLE_MULTIPART_MODE_DEFAULT);
}
}
- // FIXME FACTOR WITH HTTPHC4Impl, HTTPHC3Impl
// Just append all the parameter values, and use that as the post body
/**
* Compute body data from arguments
@@ -281,13 +278,15 @@ public class UrlConfigGui extends JPanel
String postBody = computePostBody(arguments, true); // Convert CRLF to CR, see modifyTestElement
postBodyContent.setInitialText(postBody);
postBodyContent.setCaretPosition(0);
+ argsPanel.clear();
postContentTabbedPane.setSelectedIndex(tabRawBodyIndex, false);
} else {
+ postBodyContent.setInitialText("");
argsPanel.configure(arguments);
postContentTabbedPane.setSelectedIndex(TAB_PARAMETERS, false);
- if(showFileUploadPane) {
- filesPanel.configure(el);
- }
+ }
+ if(showFileUploadPane) {
+ filesPanel.configure(el);
}
domain.setText(el.getPropertyAsString(HTTPSamplerBase.DOMAIN));
@@ -308,7 +307,7 @@ public class UrlConfigGui extends JPanel
followRedirects.setSelected(el.getPropertyAsBoolean(HTTPSamplerBase.FOLLOW_REDIRECTS));
autoRedirects.setSelected(el.getPropertyAsBoolean(HTTPSamplerBase.AUTO_REDIRECTS));
useKeepAlive.setSelected(el.getPropertyAsBoolean(HTTPSamplerBase.USE_KEEPALIVE));
- useMultipartForPost.setSelected(el.getPropertyAsBoolean(HTTPSamplerBase.DO_MULTIPART_POST));
+ useMultipart.setSelected(el.getPropertyAsBoolean(HTTPSamplerBase.DO_MULTIPART_POST));
useBrowserCompatibleMultipartMode.setSelected(el.getPropertyAsBoolean(
HTTPSamplerBase.BROWSER_COMPATIBLE_MULTIPART, HTTPSamplerBase.BROWSER_COMPATIBLE_MULTIPART_MODE_DEFAULT));
}
@@ -385,9 +384,9 @@ public class UrlConfigGui extends JPanel
useKeepAlive.setFont(null);
useKeepAlive.setSelected(true);
- useMultipartForPost = new JCheckBox(JMeterUtils.getResString("use_multipart_for_http_post")); // $NON-NLS-1$
- useMultipartForPost.setFont(null);
- useMultipartForPost.setSelected(false);
+ useMultipart = new JCheckBox(JMeterUtils.getResString("use_multipart_for_http_post")); // $NON-NLS-1$
+ useMultipart.setFont(null);
+ useMultipart.setSelected(false);
useBrowserCompatibleMultipartMode = new JCheckBox(JMeterUtils.getResString("use_multipart_mode_browser")); // $NON-NLS-1$
useBrowserCompatibleMultipartMode.setFont(null);
@@ -410,7 +409,7 @@ public class UrlConfigGui extends JPanel
optionPanel.add(autoRedirects);
optionPanel.add(followRedirects);
optionPanel.add(useKeepAlive);
- optionPanel.add(useMultipartForPost);
+ optionPanel.add(useMultipart);
optionPanel.add(useBrowserCompatibleMultipartMode);
optionPanel.setMinimumSize(optionPanel.getPreferredSize());
panel.add(optionPanel);
@@ -434,7 +433,7 @@ public class UrlConfigGui extends JPanel
if(showFileUploadPane) {
tabFileUploadIndex = ++indx;
filesPanel = new HTTPFileArgsPanel();
- postContentTabbedPane.add(JMeterUtils.getResString("post_files_upload"), filesPanel);
+ postContentTabbedPane.add(JMeterUtils.getResString("post_files_upload"), filesPanel);
}
return postContentTabbedPane;
}
@@ -468,107 +467,63 @@ public class UrlConfigGui extends JPanel
int oldSelectedIndex = this.getSelectedIndex();
if(!check || oldSelectedIndex == -1) {
super.setSelectedIndex(index);
+ } else if(index == tabFileUploadIndex) { // We're going to File, no problem
+ super.setSelectedIndex(index);
}
- else if(index != oldSelectedIndex)
- {
- // If there is no data, then switching between Parameters/file upload and Raw should be
- // allowed with no further user interaction.
- if(noData(oldSelectedIndex)) {
- argsPanel.clear();
- postBodyContent.setInitialText("");
- if(showFileUploadPane) {
- filesPanel.clear();
+ // We're moving to Raw or Parameters
+ else if(index != oldSelectedIndex) {
+ // If the Parameter data can be converted (i.e. no names)
+ // we switch
+ if(index == tabRawBodyIndex) {
+ if(canSwitchToRawBodyPane()) {
+ convertParametersToRaw();
+ super.setSelectedIndex(index);
+ } else {
+ super.setSelectedIndex(TAB_PARAMETERS);
}
- super.setSelectedIndex(index);
}
else {
- boolean filePanelHasData = false;
- if(showFileUploadPane) {
- filePanelHasData = filesPanel.hasData();
- }
-
- if(oldSelectedIndex == tabRawBodyIndex) {
-
- // If RAW data and Parameters match we allow switching
- if(index == TAB_PARAMETERS && postBodyContent.getText().equals(computePostBody((Arguments)argsPanel.createTestElement()).trim())) {
- super.setSelectedIndex(index);
- }
- else {
- // If there is data in the Raw panel, then the user should be
- // prevented from switching (that would be easy to track).
- JOptionPane.showConfirmDialog(this,
- JMeterUtils.getResString("web_cannot_switch_tab"), // $NON-NLS-1$
- JMeterUtils.getResString("warning"), // $NON-NLS-1$
- JOptionPane.DEFAULT_OPTION,
- JOptionPane.ERROR_MESSAGE);
- return;
- }
- }
- else {
- // can switch from parameter to fileupload
- if((oldSelectedIndex == TAB_PARAMETERS
- && index == tabFileUploadIndex)
- || (oldSelectedIndex == tabFileUploadIndex
- && index == TAB_PARAMETERS)) {
- super.setSelectedIndex(index);
- return;
- }
-
- // If the Parameter data can be converted (i.e. no names) and there is no data in file upload
- // we warn the user that the Parameter data will be lost.
- if(oldSelectedIndex == TAB_PARAMETERS && !filePanelHasData && canConvertParameters()) {
- Object[] options = {
- JMeterUtils.getResString("confirm"), // $NON-NLS-1$
- JMeterUtils.getResString("cancel")}; // $NON-NLS-1$
- int n = JOptionPane.showOptionDialog(this,
- JMeterUtils.getResString("web_parameters_lost_message"), // $NON-NLS-1$
- JMeterUtils.getResString("warning"), // $NON-NLS-1$
- JOptionPane.YES_NO_CANCEL_OPTION,
- JOptionPane.QUESTION_MESSAGE,
- null,
- options,
- options[1]);
- if(n == JOptionPane.YES_OPTION) {
- convertParametersToRaw();
- super.setSelectedIndex(index);
- }
- else{
- return;
- }
- }
- else {
- // If the Parameter data cannot be converted to Raw, then the user should be
- // prevented from doing so raise an error dialog
- String messageKey = filePanelHasData?"web_cannot_switch_tab":"web_cannot_convert_parameters_to_raw";
- JOptionPane.showConfirmDialog(this,
- JMeterUtils.getResString(messageKey), // $NON-NLS-1$
- JMeterUtils.getResString("warning"), // $NON-NLS-1$
- JOptionPane.DEFAULT_OPTION,
- JOptionPane.ERROR_MESSAGE);
- return;
- }
+ // If the Parameter data cannot be converted to Raw, then the user should be
+ // prevented from doing so raise an error dialog
+ if(canSwitchToParametersTab()) {
+ super.setSelectedIndex(index);
+ } else {
+ super.setSelectedIndex(tabRawBodyIndex);
}
}
}
}
+
+ /**
+ * @return false if one argument has a name
+ */
+ private boolean canSwitchToRawBodyPane() {
+ Arguments arguments = (Arguments) argsPanel.createTestElement();
+ for (int i = 0; i < arguments.getArgumentCount(); i++) {
+ if(!StringUtils.isEmpty(arguments.getArgument(i).getName())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return true if postBodyContent is empty
+ */
+ private boolean canSwitchToParametersTab() {
+ return postBodyContent.getText().isEmpty();
+ }
}
+
// autoRedirects and followRedirects cannot both be selected
@Override
public void stateChanged(ChangeEvent e) {
- if (e.getSource() == autoRedirects){
- if (autoRedirects.isSelected()) {
- followRedirects.setSelected(false);
- }
- }
- else if (e.getSource() == followRedirects){
- if (followRedirects.isSelected()) {
- autoRedirects.setSelected(false);
- }
+ Object source = e.getSource();
+ if (source == autoRedirects && autoRedirects.isSelected()) {
+ followRedirects.setSelected(false);
}
- // disable the multi-part if not a post request
- else if(e.getSource() == method) {
- boolean isPostMethod = HTTPConstants.POST.equals(method.getText());
- useMultipartForPost.setEnabled(isPostMethod);
+ else if (source == followRedirects && followRedirects.isSelected()) {
+ autoRedirects.setSelected(false);
}
}
@@ -577,43 +532,9 @@ public class UrlConfigGui extends JPanel
* Convert Parameters to Raw Body
*/
void convertParametersToRaw() {
- postBodyContent.setInitialText(computePostBody((Arguments)argsPanel.createTestElement()));
- postBodyContent.setCaretPosition(0);
- }
-
- /**
- *
- * @return true if no argument has a name
- */
- boolean canConvertParameters() {
- Arguments arguments = (Arguments) argsPanel.createTestElement();
- for (int i = 0; i < arguments.getArgumentCount(); i++) {
- if(!StringUtils.isEmpty(arguments.getArgument(i).getName())) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Checks if no data is available in the selected tab
- *
- * @param oldSelectedIndex the tab to check for data
- * @return true if neither Parameters tab nor Raw Body tab contain data
- */
- boolean noData(int oldSelectedIndex) {
- if(oldSelectedIndex == tabRawBodyIndex) {
- return StringUtils.isEmpty(postBodyContent.getText().trim());
- }
- else {
- boolean noData = true;
- Arguments element = (Arguments) argsPanel.createTestElement();
-
- if(showFileUploadPane) {
- noData &= !filesPanel.hasData();
- }
-
- return noData && StringUtils.isEmpty(computePostBody(element));
- }
+ if(postBodyContent.getText().isEmpty()) {
+ postBodyContent.setInitialText(computePostBody((Arguments)argsPanel.createTestElement()));
+ postBodyContent.setCaretPosition(0);
+ }
}
}
Modified: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/HTTPArgumentsPanel.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/HTTPArgumentsPanel.java?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/HTTPArgumentsPanel.java (original)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/HTTPArgumentsPanel.java Thu Apr 5 19:10:44 2018
@@ -49,6 +49,8 @@ public class HTTPArgumentsPanel extends
private static final String ENCODE_OR_NOT = "encode?"; //$NON-NLS-1$
private static final String INCLUDE_EQUALS = "include_equals"; //$NON-NLS-1$
+
+ private static final String CONTENT_TYPE = "content_type";
/** When pasting from the clipboard, split lines on linebreak or '&' */
private static final String CLIPBOARD_LINE_DELIMITERS = "\n|&"; //$NON-NLS-1$
@@ -59,19 +61,21 @@ public class HTTPArgumentsPanel extends
@Override
protected void initializeTableModel() {
tableModel = new ObjectTableModel(new String[] {
- ArgumentsPanel.COLUMN_RESOURCE_NAMES_0, ArgumentsPanel.COLUMN_RESOURCE_NAMES_1, ENCODE_OR_NOT, INCLUDE_EQUALS },
+ ArgumentsPanel.COLUMN_RESOURCE_NAMES_0, ArgumentsPanel.COLUMN_RESOURCE_NAMES_1, ENCODE_OR_NOT, CONTENT_TYPE, INCLUDE_EQUALS },
HTTPArgument.class,
new Functor[] {
new Functor("getName"), //$NON-NLS-1$
new Functor("getValue"), //$NON-NLS-1$
new Functor("isAlwaysEncoded"), //$NON-NLS-1$
+ new Functor("getContentType"), //$NON-NLS-1$
new Functor("isUseEquals") }, //$NON-NLS-1$
new Functor[] {
new Functor("setName"), //$NON-NLS-1$
new Functor("setValue"), //$NON-NLS-1$
new Functor("setAlwaysEncoded"), //$NON-NLS-1$
- new Functor("setUseEquals") }, //$NON-NLS-1$
- new Class[] {String.class, String.class, Boolean.class, Boolean.class });
+ new Functor("setContentType"),
+ new Functor("setUseEquals")}, //$NON-NLS-1$
+ new Class[] {String.class, String.class, Boolean.class, String.class, Boolean.class });
}
public static boolean testFunctors(){
Modified: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/DefaultSamplerCreator.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/DefaultSamplerCreator.java?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/DefaultSamplerCreator.java (original)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/DefaultSamplerCreator.java Thu Apr 5 19:10:44 2018
@@ -184,7 +184,7 @@ public class DefaultSamplerCreator exten
if (urlConfig != null) {
urlConfig.parseArguments(postData);
// Tell the sampler to do a multipart post
- sampler.setDoMultipartPost(true);
+ sampler.setDoMultipart(true);
// Remove the header for content-type and content-length, since
// those values will most likely be incorrect when the sampler
// performs the multipart request, because the boundary string
Modified: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPAbstractImpl.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPAbstractImpl.java?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPAbstractImpl.java (original)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPAbstractImpl.java Thu Apr 5 19:10:44 2018
@@ -55,6 +55,14 @@ public abstract class HTTPAbstractImpl i
}
/**
+ * Should we add to POST request content-type header if missing:
+ * Content-Type: application/x-www-form-urlencoded
+ */
+ protected static final boolean ADD_CONTENT_TYPE_TO_POST_IF_MISSING =
+ JMeterUtils.getPropDefault("http.post_add_content_type_if_missing", //$NON-NLS-1$
+ false);
+
+ /**
* If true create a SampleResult with empty content and 204 response code
*/
private static final CachedResourceMode CACHED_RESOURCE_MODE =
@@ -345,10 +353,24 @@ public abstract class HTTPAbstractImpl i
*
* @return <code>true</code> if <code>multipart/form-data</code> should be
* used and method is POST
+ * @deprecated Use {@link HTTPAbstractImpl#getUseMultipart()}
*/
+ @Deprecated
protected boolean getUseMultipartForPost() {
return testElement.getUseMultipartForPost();
}
+
+ /**
+ * Determine if we should use <code>multipart/form-data</code> or
+ * <code>application/x-www-form-urlencoded</code> for the method
+ * <p>
+ * Invokes {@link HTTPSamplerBase#getUseMultipart()}
+ *
+ * @return <code>true</code> if <code>multipart/form-data</code> should be used
+ */
+ protected boolean getUseMultipart() {
+ return testElement.getUseMultipart();
+ }
/**
* Invokes {@link HTTPSamplerBase#getDoBrowserCompatibleMultipart()}
Modified: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPHC4Impl.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPHC4Impl.java?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPHC4Impl.java (original)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPHC4Impl.java Thu Apr 5 19:10:44 2018
@@ -45,8 +45,6 @@ import java.util.zip.GZIPInputStream;
import javax.security.auth.Subject;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.input.BoundedInputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.http.Header;
@@ -469,6 +467,8 @@ public class HTTPHC4Impl extends HTTPHCA
// Scheme used for slow HTTP sockets. Cannot be set as a default, because must be set on an HttpClient instance.
private static final ConnectionSocketFactory SLOW_CONNECTION_SOCKET_FACTORY;
+ private static final ViewableFileBody[] EMPTY_FILE_BODIES = new ViewableFileBody[0];
+
static {
log.info("HTTP request retry count = {}", RETRY_COUNT);
@@ -546,40 +546,10 @@ public class HTTPHC4Impl extends HTTPHCA
HttpContext localContext = new BasicHttpContext();
HttpClientContext clientContext = HttpClientContext.adapt(localContext);
clientContext.setAttribute(CONTEXT_ATTRIBUTE_AUTH_MANAGER, getAuthManager());
-
try {
httpClient = setupClient(jMeterVariables, url, clientContext);
URI uri = url.toURI();
- if (method.equals(HTTPConstants.POST)) {
- httpRequest = new HttpPost(uri);
- } else if (method.equals(HTTPConstants.GET)) {
- // Some servers fail if Content-Length is equal to 0
- // so to avoid this we use HttpGet when there is no body (Content-Length will not be set)
- // otherwise we use HttpGetWithEntity
- if ( !areFollowingRedirect
- && ((!hasArguments() && getSendFileAsPostBody())
- || getSendParameterValuesAsPostBody()) ) {
- httpRequest = new HttpGetWithEntity(uri);
- } else {
- httpRequest = new HttpGet(uri);
- }
- } else if (method.equals(HTTPConstants.PUT)) {
- httpRequest = new HttpPut(uri);
- } else if (method.equals(HTTPConstants.HEAD)) {
- httpRequest = new HttpHead(uri);
- } else if (method.equals(HTTPConstants.TRACE)) {
- httpRequest = new HttpTrace(uri);
- } else if (method.equals(HTTPConstants.OPTIONS)) {
- httpRequest = new HttpOptions(uri);
- } else if (method.equals(HTTPConstants.DELETE)) {
- httpRequest = new HttpDelete(uri);
- } else if (method.equals(HTTPConstants.PATCH)) {
- httpRequest = new HttpPatch(uri);
- } else if (HttpWebdav.isWebdavMethod(method)) {
- httpRequest = new HttpWebdav(method, uri);
- } else {
- throw new IllegalArgumentException("Unexpected method: '"+method+"'");
- }
+ httpRequest = createHttpRequest(uri, method, areFollowingRedirect);
setupRequest(url, httpRequest, res); // can throw IOException
} catch (Exception e) {
res.sampleStart();
@@ -619,7 +589,7 @@ public class HTTPHC4Impl extends HTTPHCA
if (contentType != null){
String ct = contentType.getValue();
res.setContentType(ct);
- res.setEncodingAndType(ct);
+ res.setEncodingAndType(ct);
}
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
@@ -715,6 +685,45 @@ public class HTTPHC4Impl extends HTTPHCA
}
/**
+ * @param uri {@link URI}
+ * @param method HTTP Method
+ * @param areFollowingRedirect Are we following redirects
+ * @return {@link HttpRequestBase}
+ */
+ private HttpRequestBase createHttpRequest(URI uri, String method, boolean areFollowingRedirect) {
+ if (method.equals(HTTPConstants.POST)) {
+ return new HttpPost(uri);
+ } else if (method.equals(HTTPConstants.GET)) {
+ // Some servers fail if Content-Length is equal to 0
+ // so to avoid this we use HttpGet when there is no body (Content-Length will not be set)
+ // otherwise we use HttpGetWithEntity
+ if ( !areFollowingRedirect
+ && ((!hasArguments() && getSendFileAsPostBody())
+ || getSendParameterValuesAsPostBody()) ) {
+ return new HttpGetWithEntity(uri);
+ } else {
+ return new HttpGet(uri);
+ }
+ } else if (method.equals(HTTPConstants.PUT)) {
+ return new HttpPut(uri);
+ } else if (method.equals(HTTPConstants.HEAD)) {
+ return new HttpHead(uri);
+ } else if (method.equals(HTTPConstants.TRACE)) {
+ return new HttpTrace(uri);
+ } else if (method.equals(HTTPConstants.OPTIONS)) {
+ return new HttpOptions(uri);
+ } else if (method.equals(HTTPConstants.DELETE)) {
+ return new HttpDelete(uri);
+ } else if (method.equals(HTTPConstants.PATCH)) {
+ return new HttpPatch(uri);
+ } else if (HttpWebdav.isWebdavMethod(method)) {
+ return new HttpWebdav(method, uri);
+ } else {
+ throw new IllegalArgumentException("Unexpected method: '"+method+"'");
+ }
+ }
+
+ /**
* Store in JMeter Variables the UserToken so that the SSL context is reused
* See <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=57804">Bug 57804</a>
* @param jMeterVariables {@link JMeterVariables}
@@ -757,10 +766,7 @@ public class HTTPHC4Impl extends HTTPHCA
}
/**
- * Calls {@link #sendPostData(HttpPost)} if method is <code>POST</code> and
- * {@link #sendEntityData(HttpEntityEnclosingRequestBase)} if method is
- * <code>PUT</code> or <code>PATCH</code>
- * <p>
+ * Setup Body of request if different from GET.
* Field HTTPSampleResult#queryString of result is modified in the 2 cases
*
* @param method
@@ -777,11 +783,8 @@ public class HTTPHC4Impl extends HTTPHCA
protected void handleMethod(String method, HTTPSampleResult result,
HttpRequestBase httpRequest, HttpContext localContext) throws IOException {
// Handle the various methods
- if (httpRequest instanceof HttpPost) {
- String postBody = sendPostData((HttpPost)httpRequest);
- result.setQueryString(postBody);
- } else if (httpRequest instanceof HttpEntityEnclosingRequestBase) {
- String entityBody = sendEntityData((HttpEntityEnclosingRequestBase) httpRequest);
+ if (httpRequest instanceof HttpEntityEnclosingRequestBase) {
+ String entityBody = setupHttpEntityEnclosingRequestData((HttpEntityEnclosingRequestBase)httpRequest);
result.setQueryString(entityBody);
}
}
@@ -1155,9 +1158,7 @@ public class HTTPHC4Impl extends HTTPHCA
// with the last request to an HTTP server. Instead, most browsers
// leave it to the server to close the connection after their
// timeout period. Leave it to the JMeter user to decide.
- if (getUseKeepAlive()) {
- httpRequest.setHeader(HTTPConstants.HEADER_CONNECTION, HTTPConstants.KEEP_ALIVE);
- } else {
+ if (!getUseKeepAlive()) {
httpRequest.setHeader(HTTPConstants.HEADER_CONNECTION, HTTPConstants.CONNECTION_CLOSE);
}
@@ -1386,12 +1387,11 @@ public class HTTPHC4Impl extends HTTPHCA
}
/**
- *
- * @param post {@link HttpPost}
- * @return String posted body if computable
+ * @param entityEnclosingRequest {@link HttpEntityEnclosingRequestBase}
+ * @return String body sent if computable
* @throws IOException if sending the data fails due to I/O
*/
- protected String sendPostData(HttpPost post) throws IOException {
+ protected String setupHttpEntityEnclosingRequestData(HttpEntityEnclosingRequestBase entityEnclosingRequest) throws IOException {
// Buffer to hold the post body, except file content
StringBuilder postedBody = new StringBuilder(1000);
HTTPFileArg[] files = getHTTPFiles();
@@ -1401,7 +1401,7 @@ public class HTTPHC4Impl extends HTTPHCA
// Check if we should do a multipart/form-data or an
// application/x-www-form-urlencoded post request
- if(getUseMultipartForPost()) {
+ if(getUseMultipart()) {
// If a content encoding is specified, we use that as the
// encoding of any parameter values
Charset charset;
@@ -1430,7 +1430,7 @@ public class HTTPHC4Impl extends HTTPHCA
if (arg.isSkippable(parameterName)) {
continue;
}
- StringBody stringBody = new StringBody(arg.getValue(), ContentType.create("text/plain", charset));
+ StringBody stringBody = new StringBody(arg.getValue(), ContentType.create(arg.getContentType(), charset));
FormBodyPart formPart = FormBodyPartBuilder.create(
parameterName, stringBody).build();
multipartEntityBuilder.addPart(formPart);
@@ -1448,30 +1448,12 @@ public class HTTPHC4Impl extends HTTPHCA
}
HttpEntity entity = multipartEntityBuilder.build();
- post.setEntity(entity);
-
- if (entity.isRepeatable()){
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- for(ViewableFileBody fileBody : fileBodies){
- fileBody.hideFileData = true;
- }
- entity.writeTo(bos);
- for(ViewableFileBody fileBody : fileBodies){
- fileBody.hideFileData = false;
- }
- bos.flush();
- // We get the posted bytes using the encoding used to create it
- postedBody.append(bos.toString(
- contentEncoding == null ? "US-ASCII" // $NON-NLS-1$ this is the default used by HttpClient
- : contentEncoding));
- bos.close();
- } else {
- postedBody.append("<Multipart was not repeatable, cannot view what was sent>"); // $NON-NLS-1$
- }
+ entityEnclosingRequest.setEntity(entity);
+ writeEntityToSB(postedBody, entity, fileBodies, contentEncoding);
} else { // not multipart
// Check if the header manager had a content type header
// This allows the user to specify his own content-type for a POST request
- Header contentTypeHeader = post.getFirstHeader(HTTPConstants.HEADER_CONTENT_TYPE);
+ Header contentTypeHeader = entityEnclosingRequest.getFirstHeader(HTTPConstants.HEADER_CONTENT_TYPE);
boolean hasContentTypeHeader = contentTypeHeader != null && contentTypeHeader.getValue() != null && contentTypeHeader.getValue().length() > 0;
// If there are no arguments, we can send a file as the body of the request
// TODO: needs a multiple file upload scenerio
@@ -1481,15 +1463,15 @@ public class HTTPHC4Impl extends HTTPHCA
if(!hasContentTypeHeader) {
// Allow the mimetype of the file to control the content type
if(file.getMimeType() != null && file.getMimeType().length() > 0) {
- post.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, file.getMimeType());
+ entityEnclosingRequest.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, file.getMimeType());
}
- else {
- post.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED);
+ else if(ADD_CONTENT_TYPE_TO_POST_IF_MISSING) {
+ entityEnclosingRequest.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED);
}
}
FileEntity fileRequestEntity = new FileEntity(new File(file.getPath()),(ContentType) null);
- post.setEntity(fileRequestEntity);
+ entityEnclosingRequest.setEntity(fileRequestEntity);
// We just add placeholder text for file content
postedBody.append("<actual file content, not shown here>");
@@ -1507,11 +1489,10 @@ public class HTTPHC4Impl extends HTTPHCA
if(!hasContentTypeHeader) {
HTTPFileArg file = files.length > 0? files[0] : null;
if(file != null && file.getMimeType() != null && file.getMimeType().length() > 0) {
- post.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, file.getMimeType());
+ entityEnclosingRequest.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, file.getMimeType());
}
- else {
- // TODO - is this the correct default? no
- post.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED);
+ else if(ADD_CONTENT_TYPE_TO_POST_IF_MISSING) {
+ entityEnclosingRequest.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED);
}
}
@@ -1528,28 +1509,18 @@ public class HTTPHC4Impl extends HTTPHCA
}
// Let StringEntity perform the encoding
StringEntity requestEntity = new StringEntity(postBody.toString(), contentEncoding);
- post.setEntity(requestEntity);
+ entityEnclosingRequest.setEntity(requestEntity);
postedBody.append(postBody.toString());
} else {
// It is a normal post request, with parameter names and values
// Set the content type
- if(!hasContentTypeHeader) {
- post.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED);
+ if(!hasContentTypeHeader && ADD_CONTENT_TYPE_TO_POST_IF_MISSING) {
+ entityEnclosingRequest.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED);
}
String urlContentEncoding = contentEncoding;
UrlEncodedFormEntity entity = createUrlEncodedFormEntity(urlContentEncoding);
- post.setEntity(entity);
- if (entity.isRepeatable()){
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- post.getEntity().writeTo(bos);
- bos.flush();
- // We get the posted bytes using the encoding used to create it
- postedBody.append(bos.toString(contentEncoding != null?contentEncoding:SampleResult.DEFAULT_HTTP_ENCODING));
-
- bos.close();
- } else {
- postedBody.append("<RequestEntity was not repeatable, cannot view what was sent>");
- }
+ entityEnclosingRequest.setEntity(entity);
+ writeEntityToSB(postedBody, entity, EMPTY_FILE_BODIES, contentEncoding);
}
}
}
@@ -1557,6 +1528,37 @@ public class HTTPHC4Impl extends HTTPHCA
}
/**
+ * @param postedBody
+ * @param entity
+ * @param fileBodies Array of {@link ViewableFileBody}
+ * @param contentEncoding
+ * @throws IOException
+ * @throws UnsupportedEncodingException
+ */
+ private void writeEntityToSB(final StringBuilder postedBody, final HttpEntity entity,
+ final ViewableFileBody[] fileBodies, final String contentEncoding)
+ throws IOException {
+ if (entity.isRepeatable()){
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ for(ViewableFileBody fileBody : fileBodies){
+ fileBody.hideFileData = true;
+ }
+ entity.writeTo(bos);
+ for(ViewableFileBody fileBody : fileBodies){
+ fileBody.hideFileData = false;
+ }
+ bos.flush();
+ // We get the posted bytes using the encoding used to create it
+ postedBody.append(bos.toString(
+ contentEncoding == null ? SampleResult.DEFAULT_HTTP_ENCODING
+ : contentEncoding));
+ bos.close();
+ } else {
+ postedBody.append("<Entity was not repeatable, cannot view what was sent>"); // $NON-NLS-1$
+ }
+ }
+
+ /**
* Creates the entity data to be sent.
* <p>
* If there is a file entry with a non-empty MIME type we use that to
@@ -1629,22 +1631,8 @@ public class HTTPHC4Impl extends HTTPHCA
// our own stream, so we can return it
final HttpEntity entityEntry = entity.getEntity();
// Buffer to hold the entity body
- StringBuilder entityBody = null;
- if(entityEntry.isRepeatable()) {
- entityBody = new StringBuilder(1000);
- try (InputStream in = entityEntry.getContent();
- InputStream bounded = new BoundedInputStream(in, MAX_BODY_RETAIN_SIZE)) {
- entityBody.append(IOUtils.toString(bounded, charset));
- }
- if (entityEntry.getContentLength() > MAX_BODY_RETAIN_SIZE) {
- entityBody.append("<actual file content shortened>");
- }
- }
- else {
- entityBody = new StringBuilder(65);
- // this probably cannot happen
- entityBody.append("<RequestEntity was not repeatable, cannot view what was sent>");
- }
+ StringBuilder entityBody = new StringBuilder(65);
+ writeEntityToSB(entityBody, entityEntry, EMPTY_FILE_BODIES, charset);
return entityBody.toString();
}
return ""; // may be the empty string
Modified: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPJavaImpl.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPJavaImpl.java?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPJavaImpl.java (original)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPJavaImpl.java Thu Apr 5 19:10:44 2018
@@ -185,8 +185,6 @@ public class HTTPJavaImpl extends HTTPAb
// such as "Host" and "Connection" to be passed through.
// See http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6996110
if (getUseKeepAlive()) {
- conn.setRequestProperty(HTTPConstants.HEADER_CONNECTION, HTTPConstants.KEEP_ALIVE);
- } else {
conn.setRequestProperty(HTTPConstants.HEADER_CONNECTION, HTTPConstants.CONNECTION_CLOSE);
}
Modified: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java (original)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java Thu Apr 5 19:10:44 2018
@@ -409,9 +409,32 @@ public abstract class HTTPSamplerBase ex
// and the files should not be send as the post body
HTTPFileArg[] files = getHTTPFiles();
return HTTPConstants.POST.equals(getMethod())
- && (getDoMultipartPost() || (files.length > 0 && !getSendFileAsPostBody()));
+ && (getDoMultipart() || (files.length > 0 && hasNoMissingFile(files) && !getSendFileAsPostBody()));
+ }
+
+ /**
+ * Determine if we should use multipart/form-data or
+ * application/x-www-form-urlencoded for the post
+ *
+ * @return true if multipart/form-data should be used and method is POST
+ */
+ public boolean getUseMultipart() {
+ // We use multipart if we have been told so, or files are present
+ // and the files should not be send as the post body
+ HTTPFileArg[] files = getHTTPFiles();
+ return (getDoMultipart() || (files.length>0 && hasNoMissingFile(files) && !getSendFileAsPostBody()));
}
+ private boolean hasNoMissingFile(HTTPFileArg[] files) {
+ for (HTTPFileArg httpFileArg : files) {
+ if(StringUtils.isEmpty(httpFileArg.getPath())) {
+ log.warn("File {} is invalid as no path is defined", httpFileArg);
+ return false;
+ }
+ }
+ return true;
+ }
+
public void setProtocol(String value) {
setProperty(PROTOCOL, value.toLowerCase(java.util.Locale.ENGLISH));
}
@@ -523,11 +546,29 @@ public abstract class HTTPSamplerBase ex
return getPropertyAsBoolean(USE_KEEPALIVE);
}
+ /**
+ * @deprecated use {@link HTTPSamplerBase#setDoMultipartPost(boolean)}
+ * @param value
+ */
+ @Deprecated
public void setDoMultipartPost(boolean value) {
- setProperty(new BooleanProperty(DO_MULTIPART_POST, value));
+ setDoMultipart(value);
}
+ /**
+ * @deprecated use {@link HTTPSamplerBase#getDoMultipartPost()}
+ * @param value
+ */
+ @Deprecated
public boolean getDoMultipartPost() {
+ return getDoMultipart();
+ }
+
+ public void setDoMultipart(boolean value) {
+ setProperty(new BooleanProperty(DO_MULTIPART_POST, value));
+ }
+
+ public boolean getDoMultipart() {
return getPropertyAsBoolean(DO_MULTIPART_POST, false);
}
Modified: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/PostWriter.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/PostWriter.java?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/PostWriter.java (original)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/PostWriter.java Thu Apr 5 19:10:44 2018
@@ -101,7 +101,7 @@ public class PostWriter {
// Check if we should do a multipart/form-data or an
// application/x-www-form-urlencoded post request
- if(sampler.getUseMultipartForPost()) {
+ if(sampler.getUseMultipart()) {
OutputStream out = connection.getOutputStream();
// Write the form data post body, which we have constructed
@@ -180,7 +180,7 @@ public class PostWriter {
// Check if we should do a multipart/form-data or an
// application/x-www-form-urlencoded post request
- if(sampler.getUseMultipartForPost()) {
+ if(sampler.getUseMultipart()) {
// Set the content type
connection.setRequestProperty(
HTTPConstants.HEADER_CONTENT_TYPE,
@@ -266,7 +266,9 @@ public class PostWriter {
connection.setRequestProperty(HTTPConstants.HEADER_CONTENT_TYPE, file.getMimeType());
}
else {
- connection.setRequestProperty(HTTPConstants.HEADER_CONTENT_TYPE, HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED);
+ if(HTTPAbstractImpl.ADD_CONTENT_TYPE_TO_POST_IF_MISSING) {
+ connection.setRequestProperty(HTTPConstants.HEADER_CONTENT_TYPE, HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED);
+ }
}
}
// Create the content length we are going to write
Modified: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/HTTPArgument.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/HTTPArgument.java?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/HTTPArgument.java (original)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/HTTPArgument.java Thu Apr 5 19:10:44 2018
@@ -38,6 +38,8 @@ import org.slf4j.LoggerFactory;
* Represents an Argument for HTTP requests.
*/
public class HTTPArgument extends Argument implements Serializable {
+ private static final String DEFAULT_CONTENT_TYPE = "text/plain";
+
private static final Logger log = LoggerFactory.getLogger(HTTPArgument.class);
private static final long serialVersionUID = 241L;
@@ -45,6 +47,8 @@ public class HTTPArgument extends Argume
private static final String ALWAYS_ENCODE = "HTTPArgument.always_encode";
private static final String USE_EQUALS = "HTTPArgument.use_equals";
+
+ private static final String CONTENT_TYPE = "HTTPArgument.content_type";
private static final EncoderCache cache = new EncoderCache(1000);
@@ -84,6 +88,14 @@ public class HTTPArgument extends Argume
}
+ public void setContentType(String ct) {
+ setProperty(CONTENT_TYPE, ct, HTTPArgument.DEFAULT_CONTENT_TYPE);
+ }
+
+ public String getContentType() {
+ return getPropertyAsString(CONTENT_TYPE, HTTPArgument.DEFAULT_CONTENT_TYPE);
+ }
+
public void setAlwaysEncoded(boolean ae) {
setProperty(new BooleanProperty(ALWAYS_ENCODE, ae));
}
Modified: jmeter/trunk/test/src/org/apache/jmeter/protocol/http/sampler/PostWriterTest.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/protocol/http/sampler/PostWriterTest.java?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/test/src/org/apache/jmeter/protocol/http/sampler/PostWriterTest.java (original)
+++ jmeter/trunk/test/src/org/apache/jmeter/protocol/http/sampler/PostWriterTest.java Thu Apr 5 19:10:44 2018
@@ -322,7 +322,7 @@ public class PostWriterTest {
String descriptionValue = "mydescription";
setupFormData(sampler, titleValue, descriptionValue);
// Tell sampler to do multipart, even if we have no files to upload
- sampler.setDoMultipartPost(true);
+ sampler.setDoMultipart(true);
// Test sending data with default encoding
String contentEncoding = "";
Modified: jmeter/trunk/test/src/org/apache/jmeter/protocol/http/sampler/TestHTTPSamplersAgainstHttpMirrorServer.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/protocol/http/sampler/TestHTTPSamplersAgainstHttpMirrorServer.java?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/test/src/org/apache/jmeter/protocol/http/sampler/TestHTTPSamplersAgainstHttpMirrorServer.java (original)
+++ jmeter/trunk/test/src/org/apache/jmeter/protocol/http/sampler/TestHTTPSamplersAgainstHttpMirrorServer.java Thu Apr 5 19:10:44 2018
@@ -347,7 +347,7 @@ public class TestHTTPSamplersAgainstHttp
String contentEncoding = "";
setupUrl(sampler, contentEncoding);
setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue);
- sampler.setDoMultipartPost(true);
+ sampler.setDoMultipart(true);
HTTPSampleResult res = executeSampler(sampler);
checkPostRequestFormMultipart(sampler, res, samplerDefaultEncoding,
contentEncoding, titleField, titleValue, descriptionField,
@@ -358,7 +358,7 @@ public class TestHTTPSamplersAgainstHttp
contentEncoding = ISO_8859_1;
setupUrl(sampler, contentEncoding);
setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue);
- sampler.setDoMultipartPost(true);
+ sampler.setDoMultipart(true);
res = executeSampler(sampler);
checkPostRequestFormMultipart(sampler, res, samplerDefaultEncoding,
contentEncoding, titleField, titleValue, descriptionField,
@@ -371,7 +371,7 @@ public class TestHTTPSamplersAgainstHttp
descriptionValue = "mydescription\u0153\u20a1\u0115\u00c5";
setupUrl(sampler, contentEncoding);
setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue);
- sampler.setDoMultipartPost(true);
+ sampler.setDoMultipart(true);
res = executeSampler(sampler);
checkPostRequestFormMultipart(sampler, res, samplerDefaultEncoding,
contentEncoding, titleField, titleValue, descriptionField,
@@ -385,7 +385,7 @@ public class TestHTTPSamplersAgainstHttp
descriptionValue = "mydescription /\\";
setupUrl(sampler, contentEncoding);
setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue);
- sampler.setDoMultipartPost(true);
+ sampler.setDoMultipart(true);
res = executeSampler(sampler);
checkPostRequestFormMultipart(sampler, res, samplerDefaultEncoding,
contentEncoding, titleField, titleValue, descriptionField,
@@ -398,7 +398,7 @@ public class TestHTTPSamplersAgainstHttp
descriptionValue = "mydescription+++%2F%5C";
setupUrl(sampler, contentEncoding);
setupFormData(sampler, true, titleField, titleValue, descriptionField, descriptionValue);
- sampler.setDoMultipartPost(true);
+ sampler.setDoMultipart(true);
res = executeSampler(sampler);
String expectedTitleValue = "mytitle/=";
String expectedDescriptionValue = "mydescription /\\";
@@ -413,7 +413,7 @@ public class TestHTTPSamplersAgainstHttp
descriptionValue = "mydescription";
setupUrl(sampler, contentEncoding);
setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue);
- sampler.setDoMultipartPost(true);
+ sampler.setDoMultipart(true);
res = executeSampler(sampler);
checkPostRequestFormMultipart(sampler, res, samplerDefaultEncoding,
contentEncoding, titleField, titleValue, descriptionField,
@@ -437,7 +437,7 @@ public class TestHTTPSamplersAgainstHttp
descriptionValue = "mydescription\u0153\u20a1\u0115\u00c5${description_suffix}";
setupUrl(sampler, contentEncoding);
setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue);
- sampler.setDoMultipartPost(true);
+ sampler.setDoMultipart(true);
// Replace the variables in the sampler
replacer.replaceValues(sampler);
res = executeSampler(sampler);
@@ -869,7 +869,7 @@ public class TestHTTPSamplersAgainstHttp
contentEncoding, titleField, titleValue, descriptionField,
descriptionValue, true, true);
// Check request headers
- checkHeaderTypeLength(res.getRequestHeaders(), "multipart/form-data" + "; boundary=" + boundaryString, expectedPostBody.length);
+ checkHeaderContentType(res.getRequestHeaders(), "multipart/form-data" + "; boundary=" + boundaryString);
// Check post body from the result query string
checkArraysHaveSameContent(expectedPostBody, res.getQueryString().getBytes(contentEncoding), contentEncoding, res);
@@ -887,7 +887,7 @@ public class TestHTTPSamplersAgainstHttp
fail("No header and body section found");
}
// Check response headers
- checkHeaderTypeLength(headersSent, "multipart/form-data" + "; boundary=" + boundaryString, expectedPostBody.length);
+ checkHeaderContentType(headersSent, "multipart/form-data" + "; boundary=" + boundaryString);
// Check post body which was sent to the mirror server, and
// sent back by the mirror server
checkArraysHaveSameContent(expectedPostBody, bodySent.getBytes(contentEncoding), contentEncoding, res);
@@ -920,7 +920,7 @@ public class TestHTTPSamplersAgainstHttp
descriptionField, descriptionValue, fileField, fileValue,
fileMimeType, fileContent);
// Check request headers
- checkHeaderTypeLength(res.getRequestHeaders(), "multipart/form-data" + "; boundary=" + boundaryString, expectedPostBody.length);
+ checkHeaderContentType(res.getRequestHeaders(), "multipart/form-data" + "; boundary=" + boundaryString);
// We cannot check post body from the result query string, since that will not contain
// the actual file content, but placeholder text for file content
//checkArraysHaveSameContent(expectedPostBody, res.getQueryString().getBytes(contentEncoding));
@@ -931,7 +931,7 @@ public class TestHTTPSamplersAgainstHttp
fail("No header and body section found");
}
// Check response headers
- checkHeaderTypeLength(headersSent, "multipart/form-data" + "; boundary=" + boundaryString, expectedPostBody.length);
+ checkHeaderContentType(headersSent, "multipart/form-data" + "; boundary=" + boundaryString);
byte[] bodySent = getBodySent(res.getResponseData());
assertNotNull("Sent body should not be null", bodySent);
// Check post body which was sent to the mirror server, and
@@ -953,9 +953,7 @@ public class TestHTTPSamplersAgainstHttp
// Check URL
assertEquals(sampler.getUrl(), res.getURL());
// Check request headers
- checkHeaderTypeLength(res.getRequestHeaders(),
- HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED,
- expectedPostBody.getBytes(contentEncoding).length);
+ checkHeaderContentType(res.getRequestHeaders(), null);
// Check post body from the result query string
checkArraysHaveSameContent(expectedPostBody.getBytes(contentEncoding),
res.getQueryString().getBytes(contentEncoding), contentEncoding,
@@ -975,9 +973,7 @@ public class TestHTTPSamplersAgainstHttp
fail("No header and body section found");
}
// Check response headers
- checkHeaderTypeLength(headersSent,
- HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED,
- expectedPostBody.getBytes(contentEncoding).length);
+ checkHeaderContentType(headersSent, null);
// Check post body which was sent to the mirror server, and
// sent back by the mirror server
checkArraysHaveSameContent(expectedPostBody.getBytes(contentEncoding),
@@ -1161,11 +1157,13 @@ public class TestHTTPSamplersAgainstHttp
// Java 1.6.0_22+ no longer allows Content-Length to be set, so don't check it.
// See: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6996110
- // TODO any point in checking the other headers?
- private void checkHeaderTypeLength(String requestHeaders, String contentType, int contentLen) {
- boolean typeOK = isInRequestHeaders(requestHeaders, HTTPConstants.HEADER_CONTENT_TYPE, contentType);
- if (!typeOK){
- fail("Expected type:" + contentType + " in:\n"+ requestHeaders);
+ private void checkHeaderContentType(String requestHeaders, String contentType) {
+ if(contentType == null) {
+ boolean isPresent = checkRegularExpression(requestHeaders, HTTPConstants.HEADER_CONTENT_TYPE+": .*");
+ assertTrue("Expected no Content-Type in request headers:\n"+ requestHeaders, isPresent);
+ } else {
+ boolean typeOK = isInRequestHeaders(requestHeaders, HTTPConstants.HEADER_CONTENT_TYPE, contentType);
+ assertTrue("Expected type:" + contentType + " in request headers:\n"+ requestHeaders, typeOK);
}
}
Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml [utf-8] (original)
+++ jmeter/trunk/xdocs/changes.xml [utf-8] Thu Apr 5 19:10:44 2018
@@ -84,9 +84,11 @@ this behaviour, set <code>httpclient.res
<h3>HTTP Samplers and Test Script Recorder</h3>
<ul>
+ <li><bug>62260</bug>Improve Rest support. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
<li><bug>58757</bug>Fix deprecated methods of HTTPCLIENT after migration to httpclient-4.5.X. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
<li><bug>62212</bug>Recorder : Improve UX by providing a popup above all windows to be able to change Transaction names and pauses while using Browser. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
<li><bug>62248</bug>HTTP Request : Parameters entered in Parameters Tab should be used in body instead of being ignored. Partly based on a patch by Artem Fedorov contributed by Blazemeter.</li>
+ <li><bug>60015</bug>Multipart/form-data works only for POST using HTTPClient4 while it should for PUT, DELETE... Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
</ul>
<h3>Other samplers</h3>
@@ -157,6 +159,7 @@ this behaviour, set <code>httpclient.res
<li><bug>62114</bug>HTTP(S) Test Script Recorder : Client certificate authentication uses the first SSLManager created. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
<li><bug>61058</bug>HTTP Request : Deflate triggers "Unexpected end of ZLIB input stream". Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
<li><bug>43612</bug>HTTP PUT does not honor request parameters. Implemented by Artem Fedorov (artem.fedorov at blazemeter.com) and contributed by BlazeMeter Ltd.</li>
+ <li><bug>60190</bug>Content-Type is added for POST unconditionally. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
</ul>
<h3>Other Samplers</h3>
Modified: jmeter/trunk/xdocs/usermanual/properties_reference.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/properties_reference.xml?rev=1828467&r1=1828466&r2=1828467&view=diff
==============================================================================
--- jmeter/trunk/xdocs/usermanual/properties_reference.xml (original)
+++ jmeter/trunk/xdocs/usermanual/properties_reference.xml Thu Apr 5 19:10:44 2018
@@ -416,6 +416,11 @@ JMETER-SERVER</source>
</section>
<section name="§-num;.10 Apache HttpClient common properties" anchor="httpclient_common_properties">
<properties>
+<property name="http.post_add_content_type_if_missing">
+ Should JMeter add to POST request a Header <code>Content-type: application/x-www-form-urlencoded</code> if missing? <br/>
+ Was true before version 4.1.<br/>
+ Defaults to: <code>false</code>
+</property>
<property name="httpclient.timeout">
Set the socket timeout (or use the parameter <code>http.socket.timeout</code>) for
AJP Sampler.<br/>
@@ -1500,7 +1505,7 @@ JMETER-SERVER</source>
</property>
<property name="user.classpath">
List of directories that JMeter will search for utility and plugin dependency classes.<br/>
- Use your platform path separator to separate multiple paths.<br/>
+ Use your platform path separator (<code>java.io.File.pathSeparatorChar</code> in Java) to separate multiple paths.<br/>
Any jar file in such a directory will be automatically included; jar files in sub directories are ignored.<br/>
The given value is in addition to any jars found in the <code>lib</code> directory.<br/>
All entries will be added to the class path of the system class loader and also to the path