alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

JMeter example source code file (HTTPSampler.java)

This example JMeter source code file (HTTPSampler.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - JMeter tags/keywords

bufferedinputstream, httpsampleresult, httpurlconnection, httpurlconnection, io, ioexception, ioexception, list, max_conn_retries, net, network, non-nls-1, non-nls-1, string, string, stringbuilder, url, util, zip

The JMeter HTTPSampler.java source code

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.jmeter.protocol.http.sampler;

import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import java.net.BindException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;

import org.apache.jmeter.protocol.http.control.AuthManager;
import org.apache.jmeter.protocol.http.control.Authorization;
import org.apache.jmeter.protocol.http.control.CacheManager;
import org.apache.jmeter.protocol.http.control.CookieManager;
import org.apache.jmeter.protocol.http.control.Header;
import org.apache.jmeter.protocol.http.control.HeaderManager;

import org.apache.jmeter.samplers.Interruptible;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.property.CollectionProperty;
import org.apache.jmeter.testelement.property.PropertyIterator;

import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.util.SSLManager;

import org.apache.jorphan.logging.LoggingManager;

import org.apache.log.Logger;

/**
 * A sampler which understands all the parts necessary to read statistics about
 * HTTP requests, including cookies and authentication.
 *
 */
public class HTTPSampler extends HTTPSamplerBase implements Interruptible {
    private static final boolean OBEY_CONTENT_LENGTH =
        JMeterUtils.getPropDefault("httpsampler.obey_contentlength", false); // $NON-NLS-1$

    private static final long serialVersionUID = 233L;

    private static final Logger log = LoggingManager.getLoggerForClass();

    private static final int MAX_CONN_RETRIES =
        JMeterUtils.getPropDefault("http.java.sampler.retries" // $NON-NLS-1$
                ,10); // Maximum connection retries

    static {
        log.info("Maximum connection retries = "+MAX_CONN_RETRIES); // $NON-NLS-1$
        // Temporary copies, so can set the final ones
    }

    private static final byte[] NULL_BA = new byte[0];// can share these

    /** Handles writing of a post or put request */
    private transient PostWriter postOrPutWriter;

    private volatile HttpURLConnection savedConn;

    /**
     * Constructor for the HTTPSampler object.
     *
     * Consider using HTTPSamplerFactory.newInstance() instead
     */
    public HTTPSampler() {
    }

    /**
     * Set request headers in preparation to opening a connection.
     *
     * @param conn
     *            <code>URLConnection to set headers on
     * @exception IOException
     *                if an I/O exception occurs
     */
    protected void setPostHeaders(URLConnection conn) throws IOException {
        postOrPutWriter = new PostWriter();
        postOrPutWriter.setHeaders(conn, this);
    }

    private void setPutHeaders(URLConnection conn) throws IOException {
        postOrPutWriter = new PutWriter();
        postOrPutWriter.setHeaders(conn, this);
    }

    /**
     * Send POST data from <code>Entry to the open connection.
     * This also handles sending data for PUT requests
     *
     * @param connection
     *            <code>URLConnection where POST data should be sent
     * @return a String show what was posted. Will not contain actual file upload content
     * @exception IOException
     *                if an I/O exception occurs
     */
    protected String sendPostData(URLConnection connection) throws IOException {
        return postOrPutWriter.sendPostData(connection, this);
    }

    private String sendPutData(URLConnection connection) throws IOException {
        return postOrPutWriter.sendPostData(connection, this);
    }

    /**
     * Returns an <code>HttpURLConnection fully ready to attempt
     * connection. This means it sets the request method (GET or POST), headers,
     * cookies, and authorization for the URL request.
     * <p>
     * The request infos are saved into the sample result if one is provided.
     *
     * @param u
     *            <code>URL of the URL request
     * @param method
     *            GET, POST etc
     * @param res
     *            sample result to save request infos to
     * @return <code>HttpURLConnection ready for .connect
     * @exception IOException
     *                if an I/O Exception occurs
     */
    protected HttpURLConnection setupConnection(URL u, String method, HTTPSampleResult res) throws IOException {
        SSLManager sslmgr = null;
        if (PROTOCOL_HTTPS.equalsIgnoreCase(u.getProtocol())) {
            try {
                sslmgr=SSLManager.getInstance(); // N.B. this needs to be done before opening the connection
            } catch (Exception e) {
                log.warn("Problem creating the SSLManager: ", e);
            }
        }

        final HttpURLConnection conn;
        final String proxyHost = getProxyHost();
        final int proxyPort = getProxyPortInt();
        if (proxyHost.length() > 0 && proxyPort > 0){
            Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
            //TODO - how to define proxy authentication for a single connection?
            // It's not clear if this is possible
//            String user = getProxyUser();
//            if (user.length() > 0){
//                Authenticator auth = new ProxyAuthenticator(user, getProxyPass());
//            }
            conn = (HttpURLConnection) u.openConnection(proxy);
        } else {
            conn = (HttpURLConnection) u.openConnection();
        }

        // Update follow redirects setting just for this connection
        conn.setInstanceFollowRedirects(getAutoRedirects());

        int cto = getConnectTimeout();
        if (cto > 0){
            conn.setConnectTimeout(cto);
        }

        int rto = getResponseTimeout();
        if (rto > 0){
            conn.setReadTimeout(rto);
        }

        if (PROTOCOL_HTTPS.equalsIgnoreCase(u.getProtocol())) {
            try {
                if (null != sslmgr){
                    sslmgr.setContext(conn); // N.B. must be done after opening connection
                }
            } catch (Exception e) {
                log.warn("Problem setting the SSLManager for the connection: ", e);
            }
        }

        // a well-bahaved browser is supposed to send 'Connection: close'
        // 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()) {
            conn.setRequestProperty(HEADER_CONNECTION, KEEP_ALIVE);
        } else {
            conn.setRequestProperty(HEADER_CONNECTION, CONNECTION_CLOSE);
        }

        conn.setRequestMethod(method);
        setConnectionHeaders(conn, u, getHeaderManager(), getCacheManager());
        String cookies = setConnectionCookie(conn, u, getCookieManager());

        setConnectionAuthorization(conn, u, getAuthManager());

        if (method.equals(POST)) {
            setPostHeaders(conn);
        } else if (method.equals(PUT)) {
            setPutHeaders(conn);
        }

        if (res != null) {
            res.setRequestHeaders(getConnectionHeaders(conn));
            res.setCookies(cookies);
        }

        return conn;
    }

    /**
     * Reads the response from the URL connection.
     *
     * @param conn
     *            URL from which to read response
     * @return response content
     * @exception IOException
     *                if an I/O exception occurs
     */
    protected byte[] readResponse(HttpURLConnection conn, SampleResult res) throws IOException {
        BufferedInputStream in;

        final int contentLength = conn.getContentLength();
        if ((contentLength == 0)
            && OBEY_CONTENT_LENGTH) {
            log.info("Content-Length: 0, not reading http-body");
            res.setResponseHeaders(getResponseHeaders(conn));
            res.latencyEnd();
            return NULL_BA;
        }

        // works OK even if ContentEncoding is null
        boolean gzipped = ENCODING_GZIP.equals(conn.getContentEncoding());

        try {
            if (gzipped) {
                in = new BufferedInputStream(new GZIPInputStream(conn.getInputStream()));
            } else {
                in = new BufferedInputStream(conn.getInputStream());
            }
        } catch (IOException e) {
            if (! (e.getCause() instanceof FileNotFoundException))
            {
                log.error("readResponse: "+e.toString());
                Throwable cause = e.getCause();
                if (cause != null){
                    log.error("Cause: "+cause);
                }
            }
            // Normal InputStream is not available
            InputStream errorStream = conn.getErrorStream();
            if (errorStream == null) {
                log.info("Error Response Code: "+conn.getResponseCode()+", Server sent no Errorpage");
                res.setResponseHeaders(getResponseHeaders(conn));
                res.latencyEnd();
                return NULL_BA;
            }

            log.info("Error Response Code: "+conn.getResponseCode());

            if (gzipped) {
                in = new BufferedInputStream(new GZIPInputStream(errorStream));
            } else {
                in = new BufferedInputStream(errorStream);
            }
        } catch (Exception e) {
            log.error("readResponse: "+e.toString());
            Throwable cause = e.getCause();
            if (cause != null){
                log.error("Cause: "+cause);
            }
            in = new BufferedInputStream(conn.getErrorStream());
        }
        return readResponse(res, in, contentLength);
    }

    /**
     * Gets the ResponseHeaders from the URLConnection
     *
     * @param conn
     *            connection from which the headers are read
     * @return string containing the headers, one per line
     */
    protected String getResponseHeaders(HttpURLConnection conn) {
        StringBuilder headerBuf = new StringBuilder();
        headerBuf.append(conn.getHeaderField(0));// Leave header as is
        // headerBuf.append(conn.getHeaderField(0).substring(0, 8));
        // headerBuf.append(" ");
        // headerBuf.append(conn.getResponseCode());
        // headerBuf.append(" ");
        // headerBuf.append(conn.getResponseMessage());
        headerBuf.append("\n"); //$NON-NLS-1$

        String hfk;
        for (int i = 1; (hfk=conn.getHeaderFieldKey(i)) != null; i++) {
            headerBuf.append(hfk);
            headerBuf.append(": "); // $NON-NLS-1$
            headerBuf.append(conn.getHeaderField(i));
            headerBuf.append("\n"); // $NON-NLS-1$
        }
        return headerBuf.toString();
    }

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

    /**
     * Extracts all the required headers for that particular URL request and
     * sets them in the <code>HttpURLConnection passed in
     *
     * @param conn
     *            <code>HttpUrlConnection which represents the URL
     *            request
     * @param u
     *            <code>URL of the URL request
     * @param headerManager
     *            the <code>HeaderManager containing all the cookies
     *            for this <code>UrlConfig
     * @param cacheManager the CacheManager (may be null)
     */
    private void setConnectionHeaders(HttpURLConnection conn, URL u, HeaderManager headerManager, CacheManager cacheManager) {
        // Add all the headers from the HeaderManager
        if (headerManager != null) {
            CollectionProperty headers = headerManager.getHeaders();
            if (headers != null) {
                PropertyIterator i = headers.iterator();
                while (i.hasNext()) {
                    Header header = (Header) i.next().getObjectValue();
                    String n = header.getName();
                    String v = header.getValue();
                    conn.addRequestProperty(n, v);
                }
            }
        }
        if (cacheManager != null){
            cacheManager.setHeaders(conn, u);
        }
    }

    /**
     * Get all the headers for the <code>HttpURLConnection passed in
     *
     * @param conn
     *            <code>HttpUrlConnection which represents the URL
     *            request
     * @return the headers as a string
     */
    private String getConnectionHeaders(HttpURLConnection conn) {
        // Get all the request properties, which are the headers set on the connection
        StringBuilder hdrs = new StringBuilder(100);
        Map<String, List requestHeaders = conn.getRequestProperties();
        Set<Map.Entry> headerFields = requestHeaders.entrySet();
        for(Iterator<Map.Entry> i = headerFields.iterator(); i.hasNext();) {
            Map.Entry<String, List entry = i.next();
            String headerKey=entry.getKey();
            // Exclude the COOKIE header, since cookie is reported separately in the sample
            if(!HEADER_COOKIE.equalsIgnoreCase(headerKey)) {
                List<String> values = entry.getValue();// value is a List of Strings
                for (int j=0;j<values.size();j++){
                    hdrs.append(headerKey);
                    hdrs.append(": "); // $NON-NLS-1$
                    hdrs.append(values.get(j));
                    hdrs.append("\n"); // $NON-NLS-1$
                }
            }
        }
        return hdrs.toString();
    }

    /**
     * Extracts all the required authorization for that particular URL request
     * and sets it in the <code>HttpURLConnection passed in.
     *
     * @param conn
     *            <code>HttpUrlConnection which represents the URL
     *            request
     * @param u
     *            <code>URL of the URL request
     * @param authManager
     *            the <code>AuthManager containing all the cookies for
     *            this <code>UrlConfig
     */
    private void setConnectionAuthorization(HttpURLConnection conn, URL u, AuthManager authManager) {
        if (authManager != null) {
            Authorization auth = authManager.getAuthForURL(u);
            if (auth != null) {
                conn.setRequestProperty(HEADER_AUTHORIZATION, auth.toBasicHeader());
            }
        }
    }

    /**
     * Samples the URL passed in and stores the result in
     * <code>HTTPSampleResult, following redirects and downloading
     * page resources as appropriate.
     * <p>
     * When getting a redirect target, redirects are not followed and resources
     * are not downloaded. The caller will take care of this.
     *
     * @param url
     *            URL to sample
     * @param method
     *            HTTP method: GET, POST,...
     * @param areFollowingRedirect
     *            whether we're getting a redirect target
     * @param frameDepth
     *            Depth of this target in the frame structure. Used only to
     *            prevent infinite recursion.
     * @return results of the sampling
     */
    @Override
    protected HTTPSampleResult sample(URL url, String method, boolean areFollowingRedirect, int frameDepth) {
        HttpURLConnection conn = null;

        String urlStr = url.toString();
        log.debug("Start : sample " + urlStr);

        HTTPSampleResult res = new HTTPSampleResult();
        res.setMonitor(isMonitor());

        res.setSampleLabel(urlStr);
        res.setURL(url);
        res.setHTTPMethod(method);

        res.sampleStart(); // Count the retries as well in the time

        // Check cache for an entry with an Expires header in the future
        final CacheManager cacheManager = getCacheManager();
        if (cacheManager != null && GET.equalsIgnoreCase(method)) {
           if (cacheManager.inCache(url)) {
               res.sampleEnd();
               res.setResponseNoContent();
               res.setSuccessful(true);
               return res;
           }
        }

        try {
            // Sampling proper - establish the connection and read the response:
            // Repeatedly try to connect:
            int retry;
            // Start with 0 so tries at least once, and retries at most MAX_CONN_RETRIES times
            for (retry = 0; retry <= MAX_CONN_RETRIES; retry++) {
                try {
                    conn = setupConnection(url, method, res);
                    // Attempt the connection:
                    savedConn = conn;
                    conn.connect();
                    break;
                } catch (BindException e) {
                    if (retry >= MAX_CONN_RETRIES) {
                        log.error("Can't connect after "+retry+" retries, "+e);
                        throw e;
                    }
                    log.debug("Bind exception, try again");
                    if (conn!=null) {
                        savedConn = null; // we don't want interrupt to try disconnection again
                        conn.disconnect();
                    }
                    this.setUseKeepAlive(false);
                    continue; // try again
                } catch (IOException e) {
                    log.debug("Connection failed, giving up");
                    throw e;
                }
            }
            if (retry > MAX_CONN_RETRIES) {
                // This should never happen, but...
                throw new BindException();
            }
            // Nice, we've got a connection. Finish sending the request:
            if (method.equals(POST)) {
                String postBody = sendPostData(conn);
                res.setQueryString(postBody);
            }
            else if (method.equals(PUT)) {
                String putBody = sendPutData(conn);
                res.setQueryString(putBody);
            }
            // Request sent. Now get the response:
            byte[] responseData = readResponse(conn, res);

            res.sampleEnd();
            // Done with the sampling proper.

            // Now collect the results into the HTTPSampleResult:

            res.setResponseData(responseData);

            int errorLevel = conn.getResponseCode();
            String respMsg = conn.getResponseMessage();
            String hdr=conn.getHeaderField(0);
            if (hdr == null) {
                hdr="(null)";  // $NON-NLS-1$
            }
            if (errorLevel == -1){// Bug 38902 - sometimes -1 seems to be returned unnecessarily
                if (respMsg != null) {// Bug 41902 - NPE
                    try {
                        errorLevel = Integer.parseInt(respMsg.substring(0, 3));
                        log.warn("ResponseCode==-1; parsed "+respMsg+ " as "+errorLevel);
                      } catch (NumberFormatException e) {
                        log.warn("ResponseCode==-1; could not parse "+respMsg+" hdr: "+hdr);
                      }
                } else {
                    respMsg=hdr; // for result
                    log.warn("ResponseCode==-1 & null ResponseMessage. Header(0)= "+hdr);
                }
            }
            if (errorLevel == -1) {
                res.setResponseCode("(null)"); // $NON-NLS-1$
            } else {
                res.setResponseCode(Integer.toString(errorLevel));
            }
            res.setSuccessful(isSuccessCode(errorLevel));

            if (respMsg == null) {// has been seen in a redirect
                respMsg=hdr; // use header (if possible) if no message found
            }
            res.setResponseMessage(respMsg);

            String ct = conn.getContentType();
            if (ct != null){
                res.setContentType(ct);// e.g. text/html; charset=ISO-8859-1
                res.setEncodingAndType(ct);
            }

            res.setResponseHeaders(getResponseHeaders(conn));
            if (res.isRedirect()) {
                res.setRedirectLocation(conn.getHeaderField(HEADER_LOCATION));
            }

            // If we redirected automatically, the URL may have changed
            if (getAutoRedirects()){
                res.setURL(conn.getURL());
            }

            // Store any cookies received in the cookie manager:
            saveConnectionCookies(conn, url, getCookieManager());

            // Save cache information
            if (cacheManager != null){
                cacheManager.saveDetails(conn, res);
            }

            res = resultProcessing(areFollowingRedirect, frameDepth, res);

            log.debug("End : sample");
            return res;
        } catch (IOException e) {
            res.sampleEnd();
            // We don't want to continue using this connection, even if KeepAlive is set
            if (conn != null) { // May not exist
                savedConn = null; // we don't want interrupt to try disconnection again
                conn.disconnect();
            }
            savedConn = null; // we don't want interrupt to try disconnection again
            conn=null; // Don't process again
            return errorResult(e, res);
        } finally {
            // calling disconnect doesn't close the connection immediately,
            // but indicates we're through with it. The JVM should close
            // it when necessary.
            savedConn = null; // we don't want interrupt to try disconnection again
            disconnect(conn); // Disconnect unless using KeepAlive
        }
    }

    protected void disconnect(HttpURLConnection conn) {
        if (conn != null) {
            String connection = conn.getHeaderField(HEADER_CONNECTION);
            String protocol = conn.getHeaderField(0);
            if ((connection == null && (protocol == null || !protocol.startsWith(HTTP_1_1)))
                    || (connection != null && connection.equalsIgnoreCase(CONNECTION_CLOSE))) {
                conn.disconnect();
            } // TODO ? perhaps note connection so it can be disconnected at end of test?
        }
    }

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

    /** {@inheritDoc} */
    public boolean interrupt() {
        HttpURLConnection conn = savedConn;
        if (conn != null) {
            savedConn = null;
            conn.disconnect();
        }
        return conn != null;
    }
}

Other JMeter examples (source code examples)

Here is a short list of links related to this JMeter HTTPSampler.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.