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="&sect-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