mirror of https://github.com/apache/jmeter.git
Bug 42506 - JMeter threads all use the same SSL session
git-svn-id: https://svn.apache.org/repos/asf/jakarta/jmeter/branches/rel-2-2@543739 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
81ec3b51a6
commit
c76f9ad943
|
|
@ -16,4 +16,8 @@
|
|||
## limitations under the License.
|
||||
#
|
||||
#search_paths=../addons/addons.jar
|
||||
#log_level.jorphan.reflect=DEBUG
|
||||
#log_level.jorphan.reflect=DEBUG
|
||||
# Warning: enabling the next debug line causes javax.net.ssl.SSLException: Received fatal alert: unexpected_message
|
||||
# for certain sites when used with the default HTTP Sampler
|
||||
#log_level.jmeter.util.HttpSSLProtocolSocketFactory=DEBUG
|
||||
#log_level.jmeter.util.JsseSSLManager=DEBUG
|
||||
|
|
@ -23,8 +23,10 @@ import java.net.InetSocketAddress;
|
|||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
|
|
@ -46,37 +48,53 @@ public class HttpSSLProtocolSocketFactory
|
|||
|
||||
private static final Logger log = LoggingManager.getLoggerForClass();
|
||||
|
||||
private SSLSocketFactory sslfac;
|
||||
private JsseSSLManager sslManager;
|
||||
|
||||
private HttpSSLProtocolSocketFactory(){
|
||||
}
|
||||
|
||||
public HttpSSLProtocolSocketFactory(SSLContext context) {
|
||||
public HttpSSLProtocolSocketFactory(JsseSSLManager sslManager) {
|
||||
super();
|
||||
sslfac=context.getSocketFactory();
|
||||
this.sslManager = sslManager;
|
||||
}
|
||||
|
||||
private static final String protocolList = JMeterUtils.getPropDefault("https.socket.protocols", "");
|
||||
private static final String protocolList =
|
||||
JMeterUtils.getPropDefault("https.socket.protocols", ""); // $NON-NLS-1$ $NON-NLS-2$
|
||||
|
||||
static {
|
||||
if (protocolList.length()>0){
|
||||
log.info("Using protocol list: "+protocolList);
|
||||
}
|
||||
}
|
||||
private static final String[] protocols = protocolList.split(" ");
|
||||
|
||||
private void setSocket(Socket sock){
|
||||
if (protocolList.length() <= 0) return;
|
||||
if (sock instanceof SSLSocket){
|
||||
try {
|
||||
((SSLSocket) sock).setEnabledProtocols(protocols);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("Could not set protocol list: "+protocolList+".");
|
||||
log.warn("Valid protocols are: "+join(((SSLSocket) sock).getSupportedProtocols()));
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Expecting only SSL socket; found "+sock.getClass().getName());
|
||||
private static final String[] protocols = protocolList.split(" "); // $NON-NLS-1$
|
||||
|
||||
private void setSocket(Socket socket){
|
||||
if (!(socket instanceof SSLSocket)) {
|
||||
throw new IllegalArgumentException("Expected SSLSocket");
|
||||
}
|
||||
SSLSocket sock = (SSLSocket) socket;
|
||||
if (log.isDebugEnabled()) {
|
||||
SSLSession sslSession = sock.getSession();
|
||||
byte[] bytes = sslSession.getId();
|
||||
|
||||
StringBuffer buffer = new StringBuffer("SSL session id: ");
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
int b = bytes[i] & 0xff;
|
||||
buffer.append(Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, 16)));
|
||||
buffer.append(Character.toUpperCase(Character.forDigit(b & 0xF, 16)));
|
||||
}
|
||||
buffer.append(" for ").append(Thread.currentThread().getName());
|
||||
log.debug(buffer.toString());
|
||||
}
|
||||
if (protocolList.length() > 0) {
|
||||
try {
|
||||
sock.setEnabledProtocols(protocols);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("Could not set protocol list: " + protocolList + ".");
|
||||
log.warn("Valid protocols are: " + join(sock.getSupportedProtocols()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String join(String[] strings) {
|
||||
|
|
@ -87,6 +105,15 @@ public class HttpSSLProtocolSocketFactory
|
|||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private SSLSocketFactory getSSLSocketFactory() throws IOException {
|
||||
try {
|
||||
SSLContext sslContext = this.sslManager.getContext();
|
||||
return sslContext.getSocketFactory();
|
||||
} catch (GeneralSecurityException ex) {
|
||||
throw new IOException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get a new socket connection to the given host within the given time limit.
|
||||
|
|
@ -114,6 +141,8 @@ public class HttpSSLProtocolSocketFactory
|
|||
throw new IllegalArgumentException("Parameters may not be null");
|
||||
}
|
||||
int timeout = params.getConnectionTimeout();
|
||||
|
||||
SSLSocketFactory sslfac = getSSLSocketFactory();
|
||||
Socket socket;
|
||||
if (timeout == 0) {
|
||||
socket = sslfac.createSocket(host, port, localAddress, localPort);
|
||||
|
|
@ -133,6 +162,7 @@ public class HttpSSLProtocolSocketFactory
|
|||
*/
|
||||
public Socket createSocket(String host, int port)
|
||||
throws IOException, UnknownHostException {
|
||||
SSLSocketFactory sslfac = getSSLSocketFactory();
|
||||
Socket sock = sslfac.createSocket(
|
||||
host,
|
||||
port
|
||||
|
|
@ -150,6 +180,7 @@ public class HttpSSLProtocolSocketFactory
|
|||
int port,
|
||||
boolean autoClose)
|
||||
throws IOException, UnknownHostException {
|
||||
SSLSocketFactory sslfac = getSSLSocketFactory();
|
||||
Socket sock = sslfac.createSocket(
|
||||
socket,
|
||||
host,
|
||||
|
|
@ -170,6 +201,7 @@ public class HttpSSLProtocolSocketFactory
|
|||
int clientPort)
|
||||
throws IOException, UnknownHostException {
|
||||
|
||||
SSLSocketFactory sslfac = getSSLSocketFactory();
|
||||
Socket sock = sslfac.createSocket(
|
||||
host,
|
||||
port,
|
||||
|
|
@ -181,22 +213,34 @@ public class HttpSSLProtocolSocketFactory
|
|||
}
|
||||
|
||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
||||
SSLSocketFactory sslfac = getSSLSocketFactory();
|
||||
Socket sock=sslfac.createSocket(host,port);
|
||||
setSocket(sock);
|
||||
return sock;
|
||||
}
|
||||
|
||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
|
||||
SSLSocketFactory sslfac = getSSLSocketFactory();
|
||||
Socket sock=sslfac.createSocket(address, port, localAddress, localPort);
|
||||
setSocket(sock);
|
||||
return sock;
|
||||
}
|
||||
|
||||
public String[] getDefaultCipherSuites() {
|
||||
return sslfac.getDefaultCipherSuites();
|
||||
try {
|
||||
SSLSocketFactory sslfac = getSSLSocketFactory();
|
||||
return sslfac.getDefaultCipherSuites();
|
||||
} catch (IOException ex) {
|
||||
return new String[] {};
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getSupportedCipherSuites() {
|
||||
return sslfac.getSupportedCipherSuites();
|
||||
try {
|
||||
SSLSocketFactory sslfac = getSSLSocketFactory();
|
||||
return sslfac.getSupportedCipherSuites();
|
||||
} catch (IOException ex) {
|
||||
return new String[] {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,18 +20,13 @@ package org.apache.jmeter.util;
|
|||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.Socket;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.Principal;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Provider;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import org.apache.commons.httpclient.protocol.Protocol;
|
||||
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
|
||||
import org.apache.jmeter.util.keystore.JmeterKeyStore;
|
||||
import org.apache.jorphan.logging.LoggingManager;
|
||||
import org.apache.log.Logger;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.KeyManager;
|
||||
|
|
@ -43,6 +38,12 @@ import javax.net.ssl.TrustManagerFactory;
|
|||
import javax.net.ssl.X509KeyManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.apache.commons.httpclient.protocol.Protocol;
|
||||
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
|
||||
import org.apache.jmeter.util.keystore.JmeterKeyStore;
|
||||
import org.apache.jorphan.logging.LoggingManager;
|
||||
import org.apache.log.Logger;
|
||||
|
||||
/**
|
||||
* The SSLManager handles the KeyStore information for JMeter. Basically, it
|
||||
* handles all the logic for loading and initializing all the JSSE parameters
|
||||
|
|
@ -53,8 +54,6 @@ import javax.net.ssl.X509TrustManager;
|
|||
*
|
||||
* TODO: does not actually prompt
|
||||
*
|
||||
* @author <a href="bloritsch@apache.org">Berin Loritsch</a> Created March 21,
|
||||
* 2002
|
||||
*/
|
||||
public class JsseSSLManager extends SSLManager {
|
||||
private static final Logger log = LoggingManager.getLoggerForClass();
|
||||
|
|
@ -65,8 +64,13 @@ public class JsseSSLManager extends SSLManager {
|
|||
private static final String DEFAULT_SSL_PROTOCOL =
|
||||
JMeterUtils.getPropDefault("https.default.protocol","TLS"); // $NON-NLS-1$ // $NON-NLS-2$
|
||||
|
||||
// Allow reversion to original shared session context
|
||||
private static final boolean SHARED_SESSION_CONTEXT =
|
||||
JMeterUtils.getPropDefault("https.sessioncontext.shared",false); // $NON-NLS-1$
|
||||
|
||||
static {
|
||||
log.info("Using default SSL protocol: "+DEFAULT_SSL_PROTOCOL);
|
||||
log.info("SSL session context: "+(SHARED_SESSION_CONTEXT ? "shared" : "per-thread"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -74,13 +78,11 @@ public class JsseSSLManager extends SSLManager {
|
|||
*/
|
||||
private SecureRandom rand;
|
||||
|
||||
/**
|
||||
* Cache the Context so we can retrieve it from other places
|
||||
*/
|
||||
private SSLContext context = null;
|
||||
|
||||
private Provider pro = null;
|
||||
|
||||
private SSLContext defaultContext; // If we are using a single session
|
||||
private ThreadLocal threadlocal; // Otherwise
|
||||
|
||||
/**
|
||||
* Create the SSLContext, and wrap all the X509KeyManagers with
|
||||
* our X509KeyManager so that we can choose our alias.
|
||||
|
|
@ -91,11 +93,37 @@ public class JsseSSLManager extends SSLManager {
|
|||
public JsseSSLManager(Provider provider) {
|
||||
log.debug("ssl Provider = " + provider);
|
||||
setProvider(provider);
|
||||
if (null == this.rand) {
|
||||
if (null == this.rand) { // Surely this is always null in the constructor?
|
||||
this.rand = new SecureRandom();
|
||||
}
|
||||
|
||||
this.getContext();
|
||||
try {
|
||||
if (SHARED_SESSION_CONTEXT) {
|
||||
log.debug("Creating shared context");
|
||||
this.defaultContext = createContext();
|
||||
} else {
|
||||
this.threadlocal = new ThreadLocal();
|
||||
}
|
||||
|
||||
HttpSSLProtocolSocketFactory sockFactory = new HttpSSLProtocolSocketFactory(this);
|
||||
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(sockFactory);
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
/*
|
||||
* Also set up HttpClient defaults
|
||||
*/
|
||||
Protocol protocol = new Protocol(
|
||||
JsseSSLManager.HTTPS,
|
||||
(ProtocolSocketFactory) sockFactory,
|
||||
443);
|
||||
Protocol.registerProtocol(JsseSSLManager.HTTPS, protocol);
|
||||
log.debug("SSL stuff all set");
|
||||
} catch (GeneralSecurityException ex) {
|
||||
log.error("Could not set up SSLContext", ex);
|
||||
}
|
||||
log.debug("JsseSSLManager installed");
|
||||
}
|
||||
|
||||
|
|
@ -133,94 +161,101 @@ public class JsseSSLManager extends SSLManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the SSLContext we are using. It is useful for obtaining the
|
||||
* SSLSocketFactory so that your created sockets are authenticated.
|
||||
* Returns the SSLContext we are using.
|
||||
* This is either a context per thread,
|
||||
* or, for backwards compatibility, a single shared context.
|
||||
*
|
||||
* @return The Context value
|
||||
*/
|
||||
private SSLContext getContext() {
|
||||
if (null == this.context) {
|
||||
try {
|
||||
if (pro != null) {
|
||||
this.context = SSLContext.getInstance(DEFAULT_SSL_PROTOCOL, pro); // $NON-NLS-1$
|
||||
} else {
|
||||
this.context = SSLContext.getInstance(DEFAULT_SSL_PROTOCOL); // $NON-NLS-1$
|
||||
}
|
||||
log.debug("SSL context = " + context);
|
||||
} catch (Exception ee) {
|
||||
log.error("Could not create SSLContext", ee);
|
||||
}
|
||||
try {
|
||||
KeyManagerFactory managerFactory =
|
||||
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
JmeterKeyStore keys = this.getKeyStore();
|
||||
managerFactory.init(null, this.defaultpw.toCharArray());
|
||||
KeyManager[] managers = managerFactory.getKeyManagers();
|
||||
log.debug(keys.getClass().toString());
|
||||
|
||||
// Now wrap the default managers with our key manager
|
||||
for (int i = 0; i < managers.length; i++) {
|
||||
if (managers[i] instanceof X509KeyManager) {
|
||||
X509KeyManager manager = (X509KeyManager) managers[i];
|
||||
managers[i] = new WrappedX509KeyManager(manager, keys);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the default trust managers
|
||||
TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
|
||||
TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmfactory.init(this.getTrustStore());
|
||||
|
||||
// Wrap the defaults in our custom trust manager
|
||||
TrustManager[] trustmanagers = tmfactory.getTrustManagers();
|
||||
for (int i = 0; i < trustmanagers.length; i++) {
|
||||
if (trustmanagers[i] instanceof X509TrustManager) {
|
||||
trustmanagers[i] = new CustomX509TrustManager(
|
||||
(X509TrustManager)trustmanagers[i]);
|
||||
}
|
||||
}
|
||||
context.init(managers, trustmanagers, this.rand);
|
||||
|
||||
/*
|
||||
* The following will need to be removed if the SSL properties are to be
|
||||
* applied on a per-connection basis
|
||||
*/
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(new HttpSSLProtocolSocketFactory(context));
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
/*
|
||||
* Also set up HttpClient defaults
|
||||
*/
|
||||
Protocol protocol = new Protocol(
|
||||
JsseSSLManager.HTTPS,
|
||||
(ProtocolSocketFactory) new HttpSSLProtocolSocketFactory(context),
|
||||
443
|
||||
);
|
||||
Protocol.registerProtocol(JsseSSLManager.HTTPS, protocol);
|
||||
log.debug("SSL stuff all set");
|
||||
} catch (Exception e) {
|
||||
log.error("Could not set up SSLContext", e);
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()){
|
||||
String[] dCiphers = this.context.getSocketFactory().getDefaultCipherSuites();
|
||||
String[] sCiphers = this.context.getSocketFactory().getSupportedCipherSuites();
|
||||
int len = (dCiphers.length > sCiphers.length) ? dCiphers.length : sCiphers.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i < dCiphers.length) {
|
||||
log.debug("Default Cipher: " + dCiphers[i]);
|
||||
}
|
||||
if (i < sCiphers.length) {
|
||||
log.debug("Supported Cipher: " + sCiphers[i]);
|
||||
}
|
||||
}
|
||||
public SSLContext getContext() throws GeneralSecurityException {
|
||||
if (SHARED_SESSION_CONTEXT) {
|
||||
if (log.isDebugEnabled()){
|
||||
log.debug("Using shared SSL context for: "+Thread.currentThread().getName());
|
||||
}
|
||||
return this.defaultContext;
|
||||
}
|
||||
|
||||
SSLContext sslContext = (SSLContext) this.threadlocal.get();
|
||||
if (sslContext == null) {
|
||||
if (log.isDebugEnabled()){
|
||||
log.debug("Creating threadLocal SSL context for: "+Thread.currentThread().getName());
|
||||
}
|
||||
sslContext = createContext();
|
||||
this.threadlocal.set(sslContext);
|
||||
}
|
||||
if (log.isDebugEnabled()){
|
||||
log.debug("Using threadLocal SSL context for: "+Thread.currentThread().getName());
|
||||
}
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the SSLContext if using per-thread contexts.
|
||||
*
|
||||
*/
|
||||
public void resetContext() {
|
||||
if (!SHARED_SESSION_CONTEXT) {
|
||||
log.debug("Clearing session context for current thread");
|
||||
this.threadlocal.set(null);
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
* Creates new SSL context
|
||||
* @return SSL context
|
||||
* @throws GeneralSecurityException
|
||||
*/
|
||||
private SSLContext createContext() throws GeneralSecurityException {
|
||||
SSLContext context;
|
||||
if (pro != null) {
|
||||
context = SSLContext.getInstance(DEFAULT_SSL_PROTOCOL, pro); // $NON-NLS-1$
|
||||
} else {
|
||||
context = SSLContext.getInstance(DEFAULT_SSL_PROTOCOL); // $NON-NLS-1$
|
||||
}
|
||||
KeyManagerFactory managerFactory =
|
||||
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
JmeterKeyStore keys = this.getKeyStore();
|
||||
managerFactory.init(null, this.defaultpw.toCharArray());
|
||||
KeyManager[] managers = managerFactory.getKeyManagers();
|
||||
log.debug(keys.getClass().toString());
|
||||
|
||||
// Now wrap the default managers with our key manager
|
||||
for (int i = 0; i < managers.length; i++) {
|
||||
if (managers[i] instanceof X509KeyManager) {
|
||||
X509KeyManager manager = (X509KeyManager) managers[i];
|
||||
managers[i] = new WrappedX509KeyManager(manager, keys);
|
||||
}
|
||||
}
|
||||
return this.context;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the default trust managers
|
||||
TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
|
||||
TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmfactory.init(this.getTrustStore());
|
||||
|
||||
// Wrap the defaults in our custom trust manager
|
||||
TrustManager[] trustmanagers = tmfactory.getTrustManagers();
|
||||
for (int i = 0; i < trustmanagers.length; i++) {
|
||||
if (trustmanagers[i] instanceof X509TrustManager) {
|
||||
trustmanagers[i] = new CustomX509TrustManager(
|
||||
(X509TrustManager)trustmanagers[i]);
|
||||
}
|
||||
}
|
||||
context.init(managers, trustmanagers, this.rand);
|
||||
if (log.isDebugEnabled()){
|
||||
String[] dCiphers = context.getSocketFactory().getDefaultCipherSuites();
|
||||
String[] sCiphers = context.getSocketFactory().getSupportedCipherSuites();
|
||||
int len = (dCiphers.length > sCiphers.length) ? dCiphers.length : sCiphers.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i < dCiphers.length) {
|
||||
log.debug("Default Cipher: " + dCiphers[i]);
|
||||
}
|
||||
if (i < sCiphers.length) {
|
||||
log.debug("Supported Cipher: " + sCiphers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the X509KeyManager we have defined for the sole purpose of
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ Some of the main enhancements are:
|
|||
<li>LDAP Ext sampler optionally parses result sets and supports secure mode</li>
|
||||
<li>FTP Sampler supports Ascii/Binary mode and upload</li>
|
||||
<li>Transaction Controller now generates Sample with subresults</li>
|
||||
<li>HTTPS session contexts are now per-thread, rather than shared. This gives better emulation of multiple users</li>
|
||||
</ul>
|
||||
<p>
|
||||
The main bug fixes are:
|
||||
|
|
@ -93,6 +94,13 @@ has been removed.
|
|||
<p>
|
||||
Control-Z no longer used for Remote Start All; replaced by Control+Shift+R
|
||||
</p>
|
||||
<p>
|
||||
By default, SSL session contexts are now created per-thread, rather than being shared.
|
||||
The original behaviour can be enabled by setting the JMeter property:
|
||||
<pre>
|
||||
https.sessioncontext.shared=true
|
||||
</pre>
|
||||
</p>
|
||||
<h4>Incompatible changes (development):</h4>
|
||||
<p>
|
||||
Calulator and SamplingStatCalculator classes no longer provide any formatting of their data.
|
||||
|
|
@ -149,6 +157,7 @@ Removed deprecated method JMeterUtils.split() - use JOrphanUtils version instead
|
|||
<li>Use ISO date-time format for Tree View Listener (previously the year was not shown)</li>
|
||||
<li>Improve loading of CSV files: if possible, use header to determine format; guess timestamp format if not milliseconds</li>
|
||||
<li>Bug 41913 - TransactionController now creates samples as sub-samples of the transaction</li>
|
||||
<li>Bug 42506 - JMeter threads all use the same SSL session</li>
|
||||
</ul>
|
||||
|
||||
<h4>Non-functional improvements:</h4>
|
||||
|
|
|
|||
|
|
@ -122,6 +122,15 @@ JMeter assumes the FTP server is listening on the default port.</property>
|
|||
and the appropriate parameters from the form definition.
|
||||
If the page uses HTTP, you can use the JMeter Proxy to capture the login sequence.
|
||||
</p>
|
||||
<p>
|
||||
In versions of JMeter up to 2.2, only a single SSL context was used for all threads and samplers.
|
||||
This did not generate the proper load for multiple users.
|
||||
A separate SSL context is now used for each thread.
|
||||
To revert to the original behaviour, set the JMeter property:
|
||||
<pre>
|
||||
https.sessioncontext.shared=true
|
||||
</pre>
|
||||
</p>
|
||||
<p>If the request uses cookies, then you will also need an
|
||||
<complink name="HTTP Cookie Manager"/>. You can
|
||||
add either of these elements to the Thread Group or the HTTP Request. If you have
|
||||
|
|
|
|||
Loading…
Reference in New Issue