GitHub user squarebracket opened a pull request:

    https://github.com/apache/jmeter/pull/261

    Clear querystring args on each call to setPath

    I use the `HTTPSamplerBase` class as a base class for an HTTP sampler 
class. I recently found a bug with the way handling of query strings is 
implemented. Specifically, each call to `setPath()` on the sampler adds the 
query string arguments to the current set of query string arguments. That means 
calling `setPath()` multiple times accumulates all the query string arguments.
    
    From the source code:
    ```java
        // 
src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java:453
        public void setPath(String path, String contentEncoding) {
            boolean fullUrl = path.startsWith(HTTP_PREFIX) || 
path.startsWith(HTTPS_PREFIX);
            boolean getOrDelete = HTTPConstants.GET.equals(getMethod()) || 
HTTPConstants.DELETE.equals(getMethod());
            if (!fullUrl && getOrDelete) {
                int index = path.indexOf(QRY_PFX);
                if (index > -1) {
                    setProperty(PATH, path.substring(0, index));
                    // Parse the arguments in querystring, assuming specified 
encoding for values
                    parseArguments(path.substring(index + 1), contentEncoding);
                } else {
                    setProperty(PATH, path);
                }
            } else {
                setProperty(PATH, path);
            }
        }
    ```
    
    As you can see, if there's a query string, it calls {{parseArguments}} to 
set the query string. That function just adds every argument to the sampler's 
arguments, whether it exists or not:
    ```java
        // 
src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java:1090
        public void parseArguments(String queryString, String contentEncoding) {
            String[] args = JOrphanUtils.split(queryString, QRY_SEP);
            final boolean isDebug = log.isDebugEnabled();
            for (String arg : args) {
                if (isDebug) {
                    log.debug("Arg: " + arg);
                }
                // need to handle four cases:
                // - string contains name=value
                // - string contains name=
                // - string contains name
                // - empty string
    
                String metaData; // records the existence of an equal sign
                String name;
                String value;
                int length = arg.length();
                int endOfNameIndex = arg.indexOf(ARG_VAL_SEP);
                if (endOfNameIndex != -1) {// is there a separator?
                    // case of name=value, name=
                    metaData = ARG_VAL_SEP;
                    name = arg.substring(0, endOfNameIndex);
                    value = arg.substring(endOfNameIndex + 1, length);
                } else {
                    metaData = "";
                    name = arg;
                    value = "";
                }
                if (name.length() > 0) {
                    if (isDebug) {
                        log.debug("Name: " + name + " Value: " + value + " 
Metadata: " + metaData);
                    }
                    // If we know the encoding, we can decode the argument 
value,
                    // to make it easier to read for the user
                    if (!StringUtils.isEmpty(contentEncoding)) {
                        addEncodedArgument(name, value, metaData, 
contentEncoding);
                    } else {
                        // If we do not know the encoding, we just use the 
encoded value
                        // The browser has already done the encoding, so save 
the values as is
                        addNonEncodedArgument(name, value, metaData);
                    }
                }
            }
        }
    ```
    
    My solution is very simple -- just clear the arguments before the call to 
`parseArguments`:
    ```java
        // 
src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java:453
        public void setPath(String path, String contentEncoding) {
            boolean fullUrl = path.startsWith(HTTP_PREFIX) || 
path.startsWith(HTTPS_PREFIX);
            boolean getOrDelete = HTTPConstants.GET.equals(getMethod()) || 
HTTPConstants.DELETE.equals(getMethod());
            if (!fullUrl && getOrDelete) {
                int index = path.indexOf(QRY_PFX);
                if (index > -1) {
                    setProperty(PATH, path.substring(0, index));
                    // Zero out the arguments, so we don't include query 
strings from previous calls
                    getArguments().clear();
                    // Parse the arguments in querystring, assuming specified 
encoding for values
                    parseArguments(path.substring(index + 1), contentEncoding);
                } else {
                    setProperty(PATH, path);
                }
            } else {
                setProperty(PATH, path);
            }
        }
    ```

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/squarebracket/jmeter fix-httpsamplerbase

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/jmeter/pull/261.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #261
    
----
commit ca84f7faac6df4ee73259c5b8ba22676f9361895
Author: Chuck Wilson <charles.wil...@vantrix.com>
Date:   2017-02-01T21:36:06Z

    Clear querystring args on each call to setPath()

----


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastruct...@apache.org or file a JIRA ticket
with INFRA.
---

Reply via email to