Michael Morris wrote:

> Hi everyone,
>
> I wonder if anyone has any ideas how to do this.
>
> I am testing a piece of software with which the client creates an entity
> (i.e a new record in a database) and then edits it. The entity has an id
> which is sent back to the client as a hidden parameter. This id then needs
> to be included as one of the parameters sent to the server in order to
> access the editing page. My question is, how/if I can use JMeter to pick up
> the id and feed it back into the next controller to access the edit page.
>
> I hope this makes some sense.
>
> Michael
>
> --
> To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

I once had the same problem. I remember updating a lot of jmeter files an
finally i got it working.  (hidden fields are passed on from response to
request)

I remember having some trouble using a 'normal' modification manager, and i
created my own config element instead.
That' why i also had to update the HTTPSampler.

Anyway, i attached some files i updated in order to get it working.
/*

 * ====================================================================

 * The Apache Software License, Version 1.1

 *

 * Copyright (c) 2001 The Apache Software Foundation.  All rights

 * reserved.

 *

 * Redistribution and use in source and binary forms, with or without

 * modification, are permitted provided that the following conditions

 * are met:

 *

 * 1. Redistributions of source code must retain the above copyright

 * notice, this list of conditions and the following disclaimer.

 *

 * 2. Redistributions in binary form must reproduce the above copyright

 * notice, this list of conditions and the following disclaimer in

 * the documentation and/or other materials provided with the

 * distribution.

 *

 * 3. The end-user documentation included with the redistribution,

 * if any, must include the following acknowledgment:

 * "This product includes software developed by the

 * Apache Software Foundation (http://www.apache.org/)."

 * Alternately, this acknowledgment may appear in the software itself,

 * if and wherever such third-party acknowledgments normally appear.

 *

 * 4. The names "Apache" and "Apache Software Foundation" and

 * "Apache JMeter" must not be used to endorse or promote products

 * derived from this software without prior written permission. For

 * written permission, please contact [EMAIL PROTECTED]

 *

 * 5. Products derived from this software may not be called "Apache",

 * "Apache JMeter", nor may "Apache" appear in their name, without

 * prior written permission of the Apache Software Foundation.

 *

 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED

 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR

 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF

 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND

 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,

 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT

 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF

 * SUCH DAMAGE.

 * ====================================================================

 *

 * This software consists of voluntary contributions made by many

 * individuals on behalf of the Apache Software Foundation.  For more

 * information on the Apache Software Foundation, please see

 * <http://www.apache.org/>.

 */

package org.apache.jmeter.protocol.http.parser;



import java.net.*;

import java.util.*;



import org.apache.jmeter.config.*;

import org.apache.jmeter.protocol.http.config.UrlConfig;

import org.apache.jmeter.samplers.Entry;

import org.apache.jmeter.util.JMeterUtils;

import org.apache.jmeter.config.Argument;

import junit.framework.TestCase;



import org.apache.oro.text.regex.*;



import org.apache.log4j.*;



import org.w3c.tidy.Tidy;

import java.io.*;

import org.w3c.dom.*;

import org.xml.sax.SAXException;



/************************************************************

 *  Title: Description: Copyright: Copyright (c) 2001 Company:

 *

 *@author     Michael Stover

 *@created    June 14, 2001

 *@version    1.0

 ***********************************************************/



public class HtmlParser implements Serializable

{

        private int compilerOptions = Perl5Compiler.CASE_INSENSITIVE_MASK |

                        Perl5Compiler.MULTILINE_MASK | Perl5Compiler.READ_ONLY_MASK;



        protected static Category catClass =

                        Category.getInstance(HtmlParser.class.getName());

        protected static String utfEncodingName;

        private transient static Perl5Compiler compiler = new Perl5Compiler();

        private transient static Perl5Matcher matcher = new Perl5Matcher();





        /************************************************************

         *  Constructor for the HtmlParser object

         ***********************************************************/



        public HtmlParser()

        {

        }



        /************************************************************

         *  !ToDoo (Method description)

         *

         *@param  newLink                        !ToDo (Parameter description)

         *@param  config                         !ToDo (Parameter description)

         *@return                                !ToDo (Return description)

         *@exception  MalformedPatternException  !ToDo (Exception description)

         ***********************************************************/

        public static synchronized boolean isAnchorMatched(UrlConfig newLink, 
UrlConfig config) throws MalformedPatternException

        {

                boolean ok = true;

                Iterator iter = config.getArguments().iterator();

                String query = newLink.getQueryString();

                if (query == null && config.getArguments().getArgumentCount() > 0)

                {

                        return false;

                }

                while (iter.hasNext())

                {

                        Argument item = (Argument)iter.next();

                        if (!(ok = ok && matcher.contains(query, 
compiler.compile(item.getName() + "=" + item.getValue()))))

                        {

                                return false;

                        }

                }

                if (!(ok = ok && matcher.matches(newLink.getDomain(),

                                compiler.compile(config.getDomain()))))

                {

                        return false;

                }

                if (!(ok = ok && matcher.matches(newLink.getPath(), 
compiler.compile("[/]*"+config.getPath()))))

                {

                        return false;

                }

                if (!(ok = ok && matcher.matches(newLink.getProtocol(), 
compiler.compile(config.getProtocol()))))

                {

                        return false;

                }

                return ok;

        }



        public static synchronized boolean isArgumentMatched(Argument arg,Argument 
patternArg) throws MalformedPatternException

        {

                return 
matcher.matches(arg.getName(),compiler.compile(patternArg.getName())) &&

                                
matcher.matches((String)arg.getValue(),compiler.compile((String)patternArg.getValue()));

        }





        /************************************************************

         *  Returns <code>tidy</code> as HTML parser

         *

         *@return    a <code>tidy</code> HTML parser

         ***********************************************************/

        public static Tidy getParser()

        {

                catClass.debug("Start : getParser1");

                Tidy tidy = new Tidy();

                tidy.setCharEncoding(org.w3c.tidy.Configuration.UTF8);

                tidy.setQuiet(true);

                tidy.setShowWarnings(false);

                if (catClass.isDebugEnabled())

                {

                        catClass.debug("getParser1 : tidy parser created - " + tidy);

                }

                catClass.debug("End : getParser1");

                return tidy;

        }



        /************************************************************

         *  Returns a node representing a whole xml given an xml document

         *

         *@param  text              an xml document

         *@return                   a node representing a whole xml

         *@exception  SAXException  !ToDo (Exception description)

         ***********************************************************/

        public static Node getDOM(String text) throws SAXException

        {

                catClass.debug("Start : getDOM1");

                try

                {

                        Node node = getParser().parseDOM(new

                                        
ByteArrayInputStream(text.getBytes(getUTFEncodingName())), null);

                        if (catClass.isDebugEnabled())

                        {

                                catClass.debug("node : " + node);

                        }

                        catClass.debug("End : getDOM1");

                        return node;

                }

                catch (UnsupportedEncodingException e)

                {

                        catClass.error("getDOM1 : Unsupported encoding exception - " + 
e);

                        catClass.debug("End : getDOM1");

                        throw new RuntimeException("UTF-8 encoding failed");

                }

        }



        /************************************************************

         *  Returns the encoding type which is different for different jdks even though

         *  the mean the same thing i.e. UTF8 or UTF-8

         *

         *@return    either UTF8 or UTF-8 depending on the jdk version

         ***********************************************************/

        public static String getUTFEncodingName()

        {

                catClass.debug("Start : getUTFEncodingName1");

                if (utfEncodingName == null)

                {

                        String versionNum = System.getProperty("java.version");

                        if (catClass.isDebugEnabled())

                        {

                                catClass.debug("getUTFEncodingName1 : versionNum - " + 
versionNum);

                        }

                        if (versionNum.startsWith("1.1"))

                        {

                                utfEncodingName = "UTF8";

                        }

                        else

                        {

                                utfEncodingName = "UTF-8";

                        }

                }

                if (catClass.isDebugEnabled())

                {

                        catClass.debug("getUTFEncodingName1 : Returning 
utfEncodingName - " +

                                        utfEncodingName);

                }

                catClass.debug("End : getUTFEncodingName1");

                return utfEncodingName;

        }



        /************************************************************

         *  !ToDo (Method description)

         *

         *@return    !ToDo (Return description)

         ***********************************************************/

        public static Document createEmptyDoc()

        {

                return new Tidy().createEmptyDocument();

        }





        /************************************************************

         *  Create a new URL based on an HREF string plus a contextual URL object.

         *  Given that an HREF string might be of three possible forms, some processing

         *  is required.

         *

         *@param  parsedUrlString            !ToDo (Parameter description)

         *@param  context                    !ToDo (Parameter description)

         *@return                            !ToDo (Return description)

         *@exception  MalformedURLException  !ToDo (Exception description)

         ***********************************************************/

        public static UrlConfig createUrlFromAnchor(String parsedUrlString, URL 
context) throws MalformedURLException

        {

                UrlConfig url = new UrlConfig();

                url.setDomain(context.getHost());

                url.setProtocol(context.getProtocol());

                url.setPort(context.getPort());

                int queryStarts = parsedUrlString.indexOf("?");

                if (queryStarts == -1)

                {

                        queryStarts = parsedUrlString.length();

                }

                if (parsedUrlString.startsWith("/"))

                {

                        url.setPath(parsedUrlString.substring(0, queryStarts));

                }

                else if (parsedUrlString.startsWith(".."))

                {

                        url.setPath(context.getPath().substring(0, 
context.getPath().substring(0,

                                        
context.getPath().lastIndexOf("/")).lastIndexOf("/")) +

                                        parsedUrlString.substring(2, queryStarts));

                }

                else if (!parsedUrlString.toLowerCase().startsWith("http"))

                {

                        url.setPath(context.getPath().substring(0, 
context.getPath().lastIndexOf("/")) +

                                        "/" + parsedUrlString.substring(0, 
queryStarts));

                }

                else

                {

                        URL u = new URL(parsedUrlString);

                        url.setPath(u.getPath());

                        url.setDomain(u.getHost());

                        url.setProtocol(u.getProtocol());

                        url.setPort(u.getPort());

                }

                if (queryStarts < parsedUrlString.length())

                {

                        url.parseArguments(parsedUrlString.substring(queryStarts + 1));

                }

                return url;

        }



        /************************************************************

         *  !ToDo (Method description)

         *

         *@param  formNode                   !ToDo (Parameter description)

         *@param  context                    !ToDo (Parameter description)

         *@return                            !ToDo (Return description)

         *@exception  MalformedURLException  !ToDo (Exception description)

         ***********************************************************/

        public static UrlConfig createURLFromForm(Node formNode, URL context) throws 
MalformedURLException

        {

                String selectName = null;

                NodeList childNodes = formNode.getChildNodes();

                NamedNodeMap atts = formNode.getAttributes();

                
                String action = "";
                if (atts.getNamedItem("action") != null){
                    action = atts.getNamedItem("action").getNodeValue();
                } else{
                    action = context.getFile();
                }
                

                UrlConfig url = createUrlFromAnchor(action, context);

                recurseForm(childNodes, url, selectName);

                return url;

        }



        /************************************************************

         *  !ToDo (Class description)

         *

         *@author     $Author: mstover1 $

         *@created    $Date: 2001/09/24 12:02:27 $

         *@version    $Revision: 1.13 $

         ***********************************************************/

        public static class Test extends TestCase

        {



                private static Category catClass =

                                Category.getInstance(Test.class.getName());



                /************************************************************

                 *  !ToDo (Constructor description)

                 *

                 *@param  name  !ToDo (Parameter description)

                 ***********************************************************/

                public Test(String name)

                {

                        super(name);

                }



                /************************************************************

                 *  !ToDo

                 ***********************************************************/

                public void testGetUTFEncodingName()

                {

                        catClass.debug("Start : testGetUTFEncodingName1");

                        String javaVersion = System.getProperty("java.version");

                        utfEncodingName = null;

                        System.setProperty("java.version", "1.1");

                        assertEquals("UTF8", HtmlParser.getUTFEncodingName());

                        // need to clear utfEncodingName variable first 'cos

                        // getUTFEncodingName checks to see if it's null

                        utfEncodingName = null;

                        System.setProperty("java.version", "1.2");

                        assertEquals("UTF-8", HtmlParser.getUTFEncodingName());

                        System.setProperty("java.version", javaVersion);

                        catClass.debug("End : testGetUTFEncodingName1");

                }



                /************************************************************

                 *  !ToDo

                 ***********************************************************/

                protected void setUp()

                {

                }

        }



        private static void recurseForm(NodeList childNodes, UrlConfig url, String 
selectName)

        {

                for (int x = 0; x < childNodes.getLength(); x++)

                {

                        Node tempNode = childNodes.item(x);

                        NamedNodeMap nodeAtts = tempNode.getAttributes();

                        String tag = tempNode.getNodeName();

                        try

                        {

                                if (tag.equalsIgnoreCase("input"))

                                {

                                        
url.addArgument(getAttributeValue(nodeAtts,"name"),

                                                        
getAttributeValue(nodeAtts,"value"));

                                }

                                else if (tag.equalsIgnoreCase("textarea"))

                                {

                                        
url.addArgument(getAttributeValue(nodeAtts,"name"),

                                                        
tempNode.getFirstChild().getNodeValue());

                                }

                                else if (tag.equalsIgnoreCase("select"))

                                {

                                        selectName = 
getAttributeValue(nodeAtts,"name");

                                }

                                else if (tag.equalsIgnoreCase("option"))

                                {

                                        String value = 
getAttributeValue(nodeAtts,"value");

                                        if (value == null || value.equals(""))

                                        {

                                                value = 
tempNode.getFirstChild().getNodeValue();

                                        }

                                        url.addArgument(selectName, value);

                                }

                        }

                        catch (Exception ex) {

                                System.out.println("Some bad HTML 
"+printNode(tempNode));

                        }

                        recurseForm(tempNode.getChildNodes(),url,selectName);

                }

        }


    public static Arguments findHiddenFormAttributes(Document html){
        NodeList nodeList = html.getElementsByTagName("form");
        Arguments args = new Arguments();
        for(int x = 0;x < nodeList.getLength();x++){
            Node tempNode = nodeList.item(x);
            Node form = tempNode.cloneNode(true);
            findHiddenFormAttributes(form.getChildNodes(), args);           
        }
        return args;
    }
    /**
     * Usefull for silverstream
     */
   private static void findHiddenFormAttributes(NodeList childNodes, Arguments res){   
 
        for (int x = 0; x < childNodes.getLength(); x++){
            Node tempNode = childNodes.item(x);     
            String tag = tempNode.getNodeName();
            try{                                
                if (tag.equalsIgnoreCase("input")){
                    NamedNodeMap nodeAtts = tempNode.getAttributes();
                    String type = getAttributeValue(nodeAtts,"type");
                    if ((type != null) && type.equalsIgnoreCase("hidden")){
                        
res.addArgument(getAttributeValue(nodeAtts,"name"),getAttributeValue(nodeAtts,"value"));
                    }
                }
            }catch (Exception ex) {
                System.out.println("Some bad HTML "+printNode(tempNode));
            }
            findHiddenFormAttributes(tempNode.getChildNodes(),res);
        }
    }


        private static String getAttributeValue(NamedNodeMap att,String attName)

        {

                try {

                        return att.getNamedItem(attName).getNodeValue();

                }

                catch (Exception ex)

                {

                        return "";

                }

        }





        private static String printNode(Node node)

        {

                StringBuffer buf = new StringBuffer();

                buf.append("<");

                buf.append(node.getNodeName());

                NamedNodeMap atts = node.getAttributes();

                for(int x = 0;x < atts.getLength();x++)

                {

                        buf.append(" ");

                        buf.append(atts.item(x).getNodeName());

                        buf.append("=\"");

                        buf.append(atts.item(x).getNodeValue());

                        buf.append("\"");

                }

                buf.append(">");

                return buf.toString();

        }



}




package org.apache.jmeter.protocol.http.control;


import java.io.*;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import org.apache.jmeter.config.*;
import org.apache.jmeter.gui.JMeterComponentModel;
import org.apache.jmeter.protocol.http.save.*;
import org.apache.jmeter.protocol.http.config.*;
import org.apache.jmeter.protocol.http.parser.*;
import org.apache.jmeter.protocol.http.sampler.*;
import org.apache.jmeter.save.Saveable;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.net.*;
import org.apache.jmeter.samplers.*;

/**
 * Kind of reponse based modifier, but better.
 * A response based modifier does not save correctly. 
 
 *
 * @author  Koen Janssens
 * @version $Revision: 1.12 $ $Date: 2001/08/30 17:19:02 $
 */

import com.sssw.shr.aghttp.AgoHttpURLConnection;

public class HiddenFieldManager extends AbstractConfigElement implements 
JMeterComponentModel,Saveable,Serializable
{

         private SampleResult currentResult;

         private static List addableList = new LinkedList();

    public static class AgHttpURLConnectionWrapper implements 
HTTPSampler.URLConnectionWrapper{
        
        public void setFollowRedirects(URLConnection con, boolean r){
            if (con instanceof AgoHttpURLConnection){
                ((AgoHttpURLConnection)con).setFollowRedirects(r);
            }
        }

        public void setRequestMethod(URLConnection con, String method) throws 
ProtocolException{
            if (con instanceof AgoHttpURLConnection){
                ((AgoHttpURLConnection)con).setRequestMethod(method);
            }
        }
        public int getResponseCode(URLConnection con) throws IOException{
            if (con instanceof AgoHttpURLConnection){
                return ((AgoHttpURLConnection)con).getResponseCode();
            }
            return -1;
        }

        public String getResponseMessage(URLConnection con) throws IOException{
            if (con instanceof AgoHttpURLConnection){
                return ((AgoHttpURLConnection)con).getResponseMessage();
            }
            return null;
        }
    }

         public HiddenFieldManager () {
          //  com.sssw.rt.util.AgRuntime.init(null);
          //  HTTPSampler.WRAPPER=new AgHttpURLConnectionWrapper();
         }                  
        
         

         public Object clone()
         {
                  HiddenFieldManager ck = new HiddenFieldManager();
                  ck.currentResult = currentResult;
                  if (getName() != null){
                      ck.setName(getName());
                  }
                  return ck;
         }

    public boolean expectsModification()
    {
        return true;
    }

    public Collection getAddList()
    {
        return addableList;
    }

    public boolean isEditable()
    {
        return true;
    }
    
    
    /************************************************************
     *  This allows config elements to combine and give a "layered" effect. for
     *  example, say there are two HTTPConfigElements, which have properties for
     *  domain, path, method, and parameters. If element A has everything filled
     *  in, but null for domain, and element B is added, which has only domain
     *  filled in, then after adding B to A, A will have the domain from B. If A
     *  already had a domain, then the correct behavior is for A to ignore the
     *  addition of element B.
     *
     *@param  config  !ToDo
     ***********************************************************/
    public void addConfigElement(ConfigElement config)
    {
        
        /*if (config instanceof CookieManager)
            {
                this.cookies.addAll(((CookieManager)config).getCookies());
            }*/
    }


    public void setCurrentResult(SampleResult res){
        currentResult = res;
    }

    public boolean modifyEntry(Entry entry){
            SampleResult result = currentResult;
            try{
                if (result == null) return false;
                UrlConfig entryConfig = 
(UrlConfig)entry.getConfigElement(UrlConfig.class);
                if (entryConfig == null) return false;
                if (entryConfig.getMethod().equals(UrlConfig.GET)) return false;
                String url = entryConfig.getUrl().toString();
                int i = 0;
                if ((i = url.indexOf("?")) > 0) url = url.substring(0, i);
                String s = (String)result.getValue(SampleResult.SAMPLE_LABEL);
                if ((i = s.indexOf(",")) > 0) s = s.substring(0, i);
                if ((i = s.indexOf("?")) > 0) s = s.substring(0, i);
                if (!url.equals(s)) return false;
                
                
                List potentialLinks = new ArrayList();
                Document html;
                String responseText = 
(String)result.getValue(SampleResult.TEXT_RESPONSE);
                try{
                    html = (Document)HtmlParser.getDOM(responseText);
                }
                catch (SAXException e){
                    e.printStackTrace();
                    return false;
                }
                
                Arguments args = HtmlParser.findHiddenFormAttributes(html);
                System.out.println("Following hidden field will be posted " + args);
                boolean modified = false;
                for (i = 0; i < args.getArgumentCount();i++){
                    Argument arg=args.getArgument(i);
                    entryConfig.addArgument(arg.getName(), arg.getValue().toString());
                    modified = true;
                }
                return modified;   
            }catch (Exception ex){
                ex.printStackTrace();
            }
            return false;
    }
        

         public String getClassLabel()
         {
                return "Hidden Field Manager";
         }

}
/*
 * ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in
 * the documentation and/or other materials provided with the
 * distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 * if any, must include the following acknowledgment:
 * "This product includes software developed by the
 * Apache Software Foundation (http://www.apache.org/)."
 * Alternately, this acknowledgment may appear in the software itself,
 * if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and
 * "Apache JMeter" must not be used to endorse or promote products
 * derived from this software without prior written permission. For
 * written permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 * "Apache JMeter", nor may "Apache" appear in their name, without
 * prior written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
package org.apache.jmeter.protocol.http.sampler;

import java.io.*;
import java.net.*;
import java.security.Security;
import java.util.*;

import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.protocol.http.control.*;
import org.apache.jmeter.protocol.http.config.UrlConfig;
import org.apache.jmeter.config.*;
import org.apache.jmeter.samplers.Sampler;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.HttpSampleResult;
import org.apache.jmeter.samplers.Entry;

import org.apache.log4j.*;

/**
 *  A sampler which understands all the parts necessary to read statistics about
 *  HTTP requests, including cookies and authentication.
 *
 *@author     Michael Stover
 *@created    $Date: 2001/09/13 14:41:16 $
 *@version    $Revision: 1.27 $
 */
public class HTTPSampler implements Sampler
{

    public static interface URLConnectionWrapper{

        public void setFollowRedirects(URLConnection con, boolean r);

        public void setRequestMethod(URLConnection con, String method) throws 
ProtocolException;

        public int getResponseCode(URLConnection con) throws IOException;

        public String getResponseMessage(URLConnection con) throws IOException;

    }

    public static class HttpURLConnectionWrapper implements URLConnectionWrapper{
        
        public void setFollowRedirects(URLConnection con, boolean r){
            if (con instanceof HttpURLConnection){
                ((HttpURLConnection)con).setFollowRedirects(r);
            }
        }

        public void setRequestMethod(URLConnection con, String method) throws 
ProtocolException{
            if (con instanceof HttpURLConnection){
                ((HttpURLConnection)con).setRequestMethod(method);
            }
        }
        public int getResponseCode(URLConnection con) throws IOException{
            if (con instanceof HttpURLConnection){
                return ((HttpURLConnection)con).getResponseCode();
            }
            return -1;
        }

        public String getResponseMessage(URLConnection con) throws IOException{
            if (con instanceof HttpURLConnection){
                return ((HttpURLConnection)con).getResponseMessage();
            }
            return null;
        }
    }               
        

    public static URLConnectionWrapper WRAPPER = new HttpURLConnectionWrapper();

 
        /**
         *  Description of the Field
         */
        public final static String ARGUMENTS = "httpsampler.Arguments";
        /**
         *  Description of the Field
         */
        public final static String URL = "httpsampler.URL";
        /**
         *  Description of the Field
         */
        public final static String POST = "httpsampler.POST";
        /**
         *  Description of the Field
         */
        public final static String GET = "httpsampler.GET";
        /**
         *  Description of the Field
         */
        public final static String FILE_NAME = "httpsampler.FILE_NAME";
        /**
         *  Description of the Field
         */
        public final static String FILE_FIELD = "httpsampler.FILE_FIELD";
        /**
         *  Description of the Field
         */
        public final static String FILE_DATA = "httpsampler.FILE_DATA";
        /**
         *  Description of the Field
         */
        public final static String FILE_MIMETYPE = "httpsampler.FILE_MIMETYPE";
        /**
         *  Description of the Field
         */
        public final static String CONTENT_TYPE = "httpsampler.CONTENT_TYPE";
        /**
         *  Description of the Field
         */
        public final static String NORMAL_FORM = "normal_form";
        /**
         *  Description of the Field
         */
        public final static String MULTIPART_FORM = "multipart_form";

        protected static String encoding = "iso-8859-1";

        protected static final String NON_HTTP_RESPONSE_CODE = 
                "Non HTTP response code";
        protected static final String NON_HTTP_RESPONSE_MESSAGE = 
                "Non HTTP response message";

        private static Category catClass = Category.getInstance(
                HTTPSampler.class.getName());

        /**
         *  Constructor for the HTTPSampler object
         */
        public HTTPSampler()
        {
            System.getProperties().list(System.out);
        }

        /**
         *  A convenience method to call <code>sample</code> with no redirection
         *
         * @param  e  <code>Entry</code> to be sampled
         * @return    results of the sampling
         * @see       
org.apache.jmeter.protocol.http.sampler.HTTPSampler.sample(org.apache.jmeter.samplers.Entry,
 boolean)
         */
        public SampleResult sample(Entry e)
        {
                return sample(e, false);
        }

        /**
         *  Send POST data from <code>Entry</code> to the open connection.
         *
         * @param  connection   <code>URLConnection</code> of where POST data should be
         *                              sent
         * @param  url          contains the query string for POST
         * @exception  IOException  if an I/O exception occurs
         */
        public void sendPostData(URLConnection connection, UrlConfig url)
                         throws IOException
        {
                //((HttpURLConnection) connection).setRequestMethod("POST");
                WRAPPER.setRequestMethod(connection, "POST");
                String postData = url.getQueryString();
                connection.setRequestProperty("Content-length", "" + 
postData.length());
                connection.setRequestProperty("Content-type", 
"application/x-www-form-urlencoded");
                connection.setDoOutput(true);

                PrintWriter out = new PrintWriter(connection.getOutputStream());
                out.print(postData);
                out.close();
        }

        /**
         * Returns a <code>HttpURLConnection</code> with request method(GET or POST),
         * headers, cookies, authorization properly set for the URL request
         *
         * @param  u    <code>URL</code> of the URL request
         * @param  url  <code>UrlConfig</code> of the URL request
         * @param  e    <code>Entry</code> from which all other info can
       *                        be derived from e.g. cookies, header, authorization
         * @return              <code>HttpURLConnection</code> of the URL request
         * @exception  IOException  if an I/O Exception occurs
         */
        protected URLConnection setupConnection(URL u, UrlConfig url, Entry e) throws 
IOException
        {
                URLConnection conn;
                conn = u.openConnection();
//              conn.setFollowRedirects(false);
//              conn.setRequestMethod((String) url.getProperty(UrlConfig.METHOD));
                WRAPPER.setFollowRedirects(conn, false);
                WRAPPER.setRequestMethod(conn, (String) 
url.getProperty(UrlConfig.METHOD));
                
                setConnectionHeaders(conn, u, (HeaderManager) 
e.getConfigElement(HeaderManager.class));
                setConnectionCookie(conn, u, (CookieManager) 
e.getConfigElement(CookieManager.class));
                setConnectionAuthorization(conn, u, (AuthManager) 
e.getConfigElement(AuthManager.class));
                return conn;
        }

        /**
         *  Gets the UrlConfig attribute of the HTTPSampler object
         *
         * @param  e  Description of Parameter
         * @return    The UrlConfig value
         */
        public UrlConfig getUrlConfig(Entry e)
        {
                UrlConfig urlConfig = (UrlConfig)e.getConfigElement(UrlConfig.class);
                catClass.debug("getUrlConfig1 : Returning urlConfig - " + urlConfig);
                return urlConfig;
        }

        /**
         * This method will setup <code>HttpURLConnection</code> to handle post using 
         * <code>sendPostData</code> method if the URL request is actually a html form
         * that needs to be posted
         *
         * @param  redirected       does <code>HttpURLConnection</code> allow 
redirection
         * @param  url              contains query string for POST
         * @param  conn             <HttpURLConnection> of the URL request
         * @exception  IOException  if 
         */
        protected void writeToStream(boolean redirected, UrlConfig url, URLConnection 
conn) throws IOException
        {
                if (!redirected && 
url.getProperty(UrlConfig.METHOD).equals(UrlConfig.POST))
                {
                        sendPostData(conn, url);
                }
        }

        /*
         * Uploading a file - put in separate sampler
         * else if (contentType.equals(MULTIPART_FORM))
         * {
         *
         * }
         * }
         */

        /**
         * Extracts all the required cookies for that particular URL request and set 
them
         * in the <code>HttpURLConnection</code> passed in
         *
         * @param conn          <code>HttpUrlConnection</code> which represents the 
         *                              URL request
         * @param u                     <code>URL</code> of the URL request
         * @param cookieManager the <code>CookieManager</code> containing all the 
         *                              cookies for this <code>UrlConfig</code>
         */
        private void setConnectionCookie(URLConnection conn, URL u, CookieManager 
cookieManager)
        {
                if (cookieManager != null)
                {
                        String cookieHeader = cookieManager.getCookieHeaderForURL(u);
                        if (cookieHeader != null)
                        {
                                conn.setRequestProperty("Cookie", cookieHeader);
                        }
                }
        }

        /**
         * Extracts all the required headers for that particular URL request and set 
them
         * in the <code>HttpURLConnection</code> passed in
         *
         * @param conn          <code>HttpUrlConnection</code> which represents the 
         *                              URL request
         * @param u                     <code>URL</code> of the URL request
         * @param headerManager the <code>HeaderManager</code> containing all the 
         *                              cookies for this <code>UrlConfig</code>
         */
        private void setConnectionHeaders(URLConnection conn, URL u, HeaderManager 
headerManager)
        {
                if (headerManager != null)
                {
                        Collection headers = headerManager.getHeaders();
                        if (headers != null)
                        {
                                Iterator i = headers.iterator();
                                while (i.hasNext())
                                {
                                        Header header = (Header) i.next();
                                        conn.setRequestProperty(header.getName(), 
header.getValue());
                                }
                        }
                }
        }

        /**
         * Extracts all the required authorization for that particular URL request and 
set 
         * them in the <code>HttpURLConnection</code> passed in
         *
         * @param conn          <code>HttpUrlConnection</code> which represents the 
         *                              URL request
         * @param u                     <code>URL</code> of the URL request
         * @param authManager   the <code>AuthManager</code> containing all the 
         *                              cookies for this <code>UrlConfig</code>
         */
        private void setConnectionAuthorization(URLConnection conn, URL u, AuthManager 
authManager)
        {
                if (authManager != null)
                {
                        String authHeader = authManager.getAuthHeaderForURL(u);
                        if (authHeader != null)
                        {
                                conn.setRequestProperty("Authorization", authHeader);
                        }
                }
        }

        /**
         * Get the response code of the URL connection and divide it by 100 thus
         * returning 2(for 2xx response codes), 3(for 3xx reponse codes), etc
         *
         * @param conn          <code>HttpURLConnection</code> of URL request
         * @param res           where all results of sampling will be stored
         * @param time          time when the URL request was first started
         * @return                      HTTP response code divided by 100
         */
        private int getErrorLevel(URLConnection conn, SampleResult res, long time) 
throws IOException
        {
                int errorLevel = 2;
                int responseCode = 0;
                String message = null;
                try
                {
//                      responseCode = ((HttpURLConnection) conn).getResponseCode();
                        responseCode = WRAPPER.getResponseCode(conn);
                        errorLevel = responseCode / 100;
                        //message = ((HttpURLConnection) conn).getResponseMessage();
                        message = WRAPPER.getResponseMessage(conn);
                        res.putValue(this.RESPONSE_CODE, 
                                String.valueOf(responseCode));
                        res.putValue(this.RESPONSE_MESSAGE,
                                message);
                }
                catch (Exception e2)
                {
                    e2.printStackTrace();
                        res.putValue(SampleResult.TEXT_RESPONSE, e2.toString());
                        res.putValue(this.RESPONSE_CODE, e2.toString());
//                              NON_HTTP_RESPONSE_CODE);
                        res.putValue(this.RESPONSE_MESSAGE, 
                        NON_HTTP_RESPONSE_MESSAGE);
                        res.setTime(System.currentTimeMillis() - time);
                        res.putValue(SampleResult.SUCCESS, new Boolean(false));
                }
                return errorLevel;
        }

        /**
         * Follow redirection manually.  Normally if the web server does a redirection 
the
         * intermediate page is not returned.  Only the resultant page and the 
response code
         * for the page will be returned.  With redirection turned off, the response 
code of
         * 3xx will be returned together with a "Location" header-value pair to 
indicate
         * that the "Location" value needs to be followed to get the resultant page.
         *
         * @param conn          connection
         * @param u             
         * @exception MalformedURLException     if URL is not understood
         */
        private void redirectUrl(URLConnection conn, URL u, UrlConfig urlConfig) 
throws MalformedURLException
        {
                String loc = conn.getHeaderField("Location");
                if (loc != null)
                {
                        if (loc.indexOf("http") == -1)
                        {
                                String tempURL = u.toString();
                                if (loc.startsWith("/"))
                                {
                                        int ind = tempURL.indexOf("//") + 2;
                                        loc = tempURL.substring(0, 
tempURL.indexOf("/", ind) + 1) + loc.substring(1);
                                }
                                else
                                {
                                        loc = u.toString().substring(0,
                                                        u.toString().lastIndexOf('/') 
+ 1) + loc;
                                }
                        }
                }
                URL newUrl = new URL(loc);
                urlConfig.putProperty(UrlConfig.DOMAIN, newUrl.getHost());
                urlConfig.putProperty(UrlConfig.PATH, newUrl.getFile());
        }

        /**
         * Samples <code>Entry</code> passed in and stores the result in 
         * <code>SampleResult</code>
         *
         * @param e             <code>Entry</code> to be sampled
         * @param redirected    whether redirection is turned on
         * @return              results of the sampling
         */
        private SampleResult sample(Entry e, boolean redirected)
        {
                catClass.debug("Start : sample2");
                HiddenFieldManager man = ((HiddenFieldManager) 
e.getConfigElement(HiddenFieldManager.class));
                if (man != null){
                    man.modifyEntry(e);
                }
                long time;
                SampleResult res = new HttpSampleResult();
                if (man != null){
                    man.setCurrentResult(res);
                }
                UrlConfig url = getUrlConfig(e);

                URL u = null;
                try
                {
                        u = url.getUrl();
                        res.putValue(SampleResult.SAMPLE_LABEL, u.toString());
                        res.putValue(HTTPSampler.URL,u);
                        // specify the data to the result.
                        res.putValue(HttpSampleResult.DATA, url);
                        System.out.println("["+Thread.currentThread().getName()+"] 
Sampling url: "+ u);
                        if(catClass.isDebugEnabled())
                        {
                                catClass.debug("sample2 : sampling url - " + u);
                        }
                        URLConnection conn = null;
                        try{
                            conn = setupConnection(u, url, e);
//                          System.out.println(conn.getClass().getName());
                            writeToStream(redirected, url, conn);
                            time = System.currentTimeMillis();
                            res.putValue(SampleResult.START_TIME, 
String.valueOf(time));
                            conn.connect();
                            saveConnectionCookies(conn, u, (CookieManager) 
e.getConfigElement(CookieManager.class));
                            
                            int errorLevel = getErrorLevel(conn, res, time);
                            if (errorLevel == 2)
                                {
                                    String ret = readResponse(conn);
                                    time = System.currentTimeMillis() - time;
                                    res.putValue(SampleResult.TEXT_RESPONSE, ret);
                                    res.putValue(SampleResult.SUCCESS, new 
Boolean(true));
                                    getResponseHeaders(conn, res);
                                }
                            else if (errorLevel == 3)
                                {
                                    redirectUrl(conn, u, url);
                                    
                                    time = System.currentTimeMillis() - time;
                                    res = sample(e, true);
                                    time += res.getTime();
                                }
                            else
                                {
                                // Could not sample the URL
                                //time can be interesting even in case of error (eg 
timeout)
                                    time = System.currentTimeMillis() - time;
                                    res.setTime(time);
                                    System.out.println("URL = " + u);
//                                  int responseCode = ((HttpURLConnection) 
conn).getResponseCode();
//                                  String responseMessage = ((HttpURLConnection) 
conn).getResponseMessage();                               
                                    int responseCode = WRAPPER.getResponseCode(conn);
                                    String responseMessage = 
WRAPPER.getResponseMessage(conn);
                                    System.out.println(responseCode+" 
"+responseMessage);
                                    //throw new RuntimeException("Thread Stopped after 
error");
                                    //throw new IOException(responseMessage+" 
"+responseCode);
                                }
                            res.setTime(time);
                            return res;
                        }finally{
                            //05/01/2001 Added to decrease amount of open TCP 
connections.
                            if (conn != null){
//                              conn.disconnect();
                            }
                        }
                }
                catch (IOException ex)
                    {
                        ex.printStackTrace();
//                      res.putValue(this.RESPONSE_CODE, 
        //                      NON_HTTP_RESPONSE_CODE);
                //      res.putValue(this.RESPONSE_MESSAGE, 
                        //      NON_HTTP_RESPONSE_MESSAGE);
                        res.putValue(SampleResult.TEXT_RESPONSE, ex.toString());
                        res.putValue(SampleResult.SUCCESS, new Boolean(false));
                    }
                catClass.debug("End : sample2");
                return res;
        }

        /**
         * From the <code>HttpURLConnection</code>, store all the "set-cookie" key-pair
         * values in the cookieManager of the <code>UrlConfig</code>
         *
         * @param conn          <code>HttpUrlConnection</code> which represents the 
         *                      URL request
         * @param u             <code>URL</code> of the URL request
         * @param cookieManager the <code>CookieManager</code> containing all the 
         *                      cookies for this <code>UrlConfig</code>
         */
        private void saveConnectionCookies(URLConnection conn, URL u, CookieManager 
cookieManager)
        {
                if (cookieManager != null)
                {
                        for (int i = 1; conn.getHeaderFieldKey(i) != null; i++)
                        {
                                if 
(conn.getHeaderFieldKey(i).equalsIgnoreCase("set-cookie"))
                                {
                                        
cookieManager.addCookieFromHeader(conn.getHeaderField(i), u);
                                }
                        }
                }
        }

        /**
         * Reads the response from the URL connection
         *
         * @param conn                  URL from which to read response
         * @return                      response in <code>String</code>
         * @exception IOException       if an I/O exception occurs
         */
        protected String readResponse(URLConnection conn) throws IOException
        {
                byte[] buffer = new byte[4096];
                BufferedInputStream in = new 
BufferedInputStream(conn.getInputStream());
                java.io.ByteArrayOutputStream w = new ByteArrayOutputStream();
                int x = 0;
                while ((x = in.read(buffer)) != -1)
                {
                        w.write(buffer, 0, x);
                }
                in.close();
                return w.toString();
        }

        static
        {
                if (!JMeterUtils.getPropDefault("ssl.provider", "none").equals("none") 
&&
                                
!JMeterUtils.getPropDefault("ssl.pkgs","none").equals("none"))
                {
                        try
                        {
                                Class c = 
Class.forName("org.apache.jmeter.protocol.http.util.SSLStaticProvider");
                                c.newInstance();
                        }
                        catch (Exception ex)
                        {
                                System.err.println("Could not find SSL Provider");
                                ex.printStackTrace();
                        }
                }
        }

        /**
         *  Gets the ResponseHeaders from the URLConnection, save them to the 
SampleResults
         *  object.
         *
         *@param  conn          connection from which the headers are read
         *@param  res           where the headers read are stored
         */
        protected void getResponseHeaders(URLConnection conn, SampleResult res)
        {
                HashMap hValues = new HashMap(20);
                for (int i = 1; conn.getHeaderFieldKey(i) != null; i++)
                {
                        hValues.put(conn.getHeaderFieldKey(i), conn.getHeaderField(i));
                }
                res.putValue(Sampler.HEADER, hValues);
        }

}

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to