ASF Bugzilla – Attachment 33610 Details for
Bug 56141
Application does not behave correctly when using HTTP Recorder
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
With my changes
HTTPHC4Impl.java (text/x-csrc), 62.36 KB, created by
Dan
on 2016-02-29 01:42:31 UTC
(
hide
)
Description:
With my changes
Filename:
MIME Type:
Creator:
Dan
Created:
2016-02-29 01:42:31 UTC
Size:
62.36 KB
patch
obsolete
>/* > * 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.ByteArrayOutputStream; >import java.io.File; >import java.io.IOException; >import java.io.OutputStream; >import java.io.UnsupportedEncodingException; >import java.net.InetAddress; >import java.net.URI; >import java.net.URL; >import java.net.URLDecoder; >import java.nio.charset.Charset; >import java.security.PrivilegedActionException; >import java.security.PrivilegedExceptionAction; >import java.util.ArrayList; >import java.util.HashMap; >import java.util.List; >import java.util.Map; >import java.util.concurrent.TimeUnit; > >import javax.security.auth.Subject; > >import org.apache.commons.lang3.StringUtils; >import org.apache.http.Header; >import org.apache.http.HttpConnection; >import org.apache.http.HttpConnectionMetrics; >import org.apache.http.HttpEntity; >import org.apache.http.HttpException; >import org.apache.http.HttpHost; >import org.apache.http.HttpRequest; >import org.apache.http.HttpRequestInterceptor; >import org.apache.http.HttpResponse; >import org.apache.http.HttpResponseInterceptor; >import org.apache.http.NameValuePair; >import org.apache.http.StatusLine; >import org.apache.http.auth.AuthScope; >import org.apache.http.auth.Credentials; >import org.apache.http.auth.NTCredentials; >import org.apache.http.client.ClientProtocolException; >import org.apache.http.client.CredentialsProvider; >import org.apache.http.client.HttpClient; >import org.apache.http.client.HttpRequestRetryHandler; >import org.apache.http.client.config.CookieSpecs; >import org.apache.http.client.entity.UrlEncodedFormEntity; >import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; >import org.apache.http.client.methods.HttpGet; >import org.apache.http.client.methods.HttpHead; >import org.apache.http.client.methods.HttpOptions; >import org.apache.http.client.methods.HttpPatch; >import org.apache.http.client.methods.HttpPost; >import org.apache.http.client.methods.HttpPut; >import org.apache.http.client.methods.HttpRequestBase; >import org.apache.http.client.methods.HttpTrace; >import org.apache.http.client.methods.HttpUriRequest; >import org.apache.http.client.params.ClientPNames; >import org.apache.http.client.protocol.HttpClientContext; >import org.apache.http.client.protocol.ResponseContentEncoding; >import org.apache.http.conn.ConnectionKeepAliveStrategy; >import org.apache.http.conn.DnsResolver; >import org.apache.http.conn.params.ConnRoutePNames; >import org.apache.http.conn.scheme.PlainSocketFactory; >import org.apache.http.conn.scheme.Scheme; >import org.apache.http.conn.scheme.SchemeRegistry; >import org.apache.http.entity.ContentType; >import org.apache.http.entity.FileEntity; >import org.apache.http.entity.StringEntity; >import org.apache.http.entity.mime.FormBodyPart; >import org.apache.http.entity.mime.HttpMultipartMode; >import org.apache.http.entity.mime.MultipartEntity; >//DJ Added >import org.apache.http.entity.mime.MultipartEntityBuilder; > >import org.apache.http.entity.mime.content.FileBody; >import org.apache.http.entity.mime.content.StringBody; >import org.apache.http.impl.client.AbstractHttpClient; >import org.apache.http.impl.client.DefaultClientConnectionReuseStrategy; >import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy; >import org.apache.http.impl.client.DefaultHttpClient; >import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; >import org.apache.http.impl.conn.SystemDefaultDnsResolver; >import org.apache.http.message.BasicNameValuePair; >import org.apache.http.params.BasicHttpParams; >import org.apache.http.params.CoreConnectionPNames; >import org.apache.http.params.CoreProtocolPNames; >import org.apache.http.params.DefaultedHttpParams; >import org.apache.http.params.HttpParams; >import org.apache.http.params.SyncBasicHttpParams; >import org.apache.http.protocol.BasicHttpContext; >import org.apache.http.protocol.HTTP; >import org.apache.http.protocol.HttpContext; >import org.apache.http.protocol.HttpCoreContext; >import org.apache.jmeter.protocol.http.control.AuthManager; >import org.apache.jmeter.protocol.http.control.CacheManager; >import org.apache.jmeter.protocol.http.control.CookieManager; >import org.apache.jmeter.protocol.http.control.HeaderManager; >import org.apache.jmeter.protocol.http.util.EncoderCache; >import org.apache.jmeter.protocol.http.util.HTTPArgument; >import org.apache.jmeter.protocol.http.util.HTTPConstants; >import org.apache.jmeter.protocol.http.util.HTTPFileArg; >import org.apache.jmeter.protocol.http.util.SlowHC4SocketFactory; >import org.apache.jmeter.samplers.SampleResult; >import org.apache.jmeter.services.FileServer; >import org.apache.jmeter.testelement.property.CollectionProperty; >import org.apache.jmeter.testelement.property.JMeterProperty; >import org.apache.jmeter.testelement.property.PropertyIterator; >import org.apache.jmeter.threads.JMeterContextService; >import org.apache.jmeter.threads.JMeterVariables; >import org.apache.jmeter.util.JMeterUtils; >import org.apache.jmeter.util.JsseSSLManager; >import org.apache.jmeter.util.SSLManager; >import org.apache.jorphan.logging.LoggingManager; >import org.apache.log.Logger; > >/** > * HTTP Sampler using Apache HttpClient 4.x. > * > */ >public class HTTPHC4Impl extends HTTPHCAbstractImpl { > > private static final Logger log = LoggingManager.getLoggerForClass(); > > /** retry count to be used (default 0); 0 = disable retries */ > private static final int RETRY_COUNT = JMeterUtils.getPropDefault("httpclient4.retrycount", 0); > > /** Idle timeout to be applied to connections if no Keep-Alive header is sent by the server (default 0 = disable) */ > private static final int IDLE_TIMEOUT = JMeterUtils.getPropDefault("httpclient4.idletimeout", 0); > > private static final String CONTEXT_METRICS = "jmeter_metrics"; // TODO hack for metrics related to HTTPCLIENT-1081, to be removed later > > private static final ConnectionKeepAliveStrategy IDLE_STRATEGY = new DefaultConnectionKeepAliveStrategy(){ > @Override > public long getKeepAliveDuration(HttpResponse response, HttpContext context) { > long duration = super.getKeepAliveDuration(response, context); > if (duration <= 0 && IDLE_TIMEOUT > 0) {// none found by the superclass > if(log.isDebugEnabled()) { > log.debug("Setting keepalive to " + IDLE_TIMEOUT); > } > return IDLE_TIMEOUT; > } > return duration; // return the super-class value > } > > }; > > /** > * Special interceptor made to keep metrics when connection is released for some method like HEAD > * Otherwise calling directly ((HttpConnection) localContext.getAttribute(HttpCoreContext.HTTP_CONNECTION)).getMetrics(); > * would throw org.apache.http.impl.conn.ConnectionShutdownException > * See https://bz.apache.org/jira/browse/HTTPCLIENT-1081 > */ > private static final HttpResponseInterceptor METRICS_SAVER = new HttpResponseInterceptor(){ > @Override > public void process(HttpResponse response, HttpContext context) > throws HttpException, IOException { > HttpConnectionMetrics metrics = ((HttpConnection) context.getAttribute(HttpCoreContext.HTTP_CONNECTION)).getMetrics(); > context.setAttribute(CONTEXT_METRICS, metrics); > } > }; > private static final HttpRequestInterceptor METRICS_RESETTER = new HttpRequestInterceptor() { > @Override > public void process(HttpRequest request, HttpContext context) > throws HttpException, IOException { > HttpConnectionMetrics metrics = ((HttpConnection) context.getAttribute(HttpCoreContext.HTTP_CONNECTION)).getMetrics(); > metrics.reset(); > } > }; > > /** > * 1 HttpClient instance per combination of (HttpClient,HttpClientKey) > */ > private static final ThreadLocal<Map<HttpClientKey, HttpClient>> HTTPCLIENTS_CACHE_PER_THREAD_AND_HTTPCLIENTKEY = > new InheritableThreadLocal<Map<HttpClientKey, HttpClient>>(){ > @Override > protected Map<HttpClientKey, HttpClient> initialValue() { > return new HashMap<>(); > } > }; > > // Scheme used for slow HTTP sockets. Cannot be set as a default, because must be set on an HttpClient instance. > private static final Scheme SLOW_HTTP; > > /* > * Create a set of default parameters from the ones initially created. > * This allows the defaults to be overridden if necessary from the properties file. > */ > private static final HttpParams DEFAULT_HTTP_PARAMS; > > private static final String USER_TOKEN = "__jmeter.USER_TOKEN__"; //$NON-NLS-1$ > > static { > log.info("HTTP request retry count = "+RETRY_COUNT); > > DEFAULT_HTTP_PARAMS = new SyncBasicHttpParams(); // Could we drop the Sync here? > DEFAULT_HTTP_PARAMS.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false); > DefaultHttpClient.setDefaultHttpParams(DEFAULT_HTTP_PARAMS); > > // Process Apache HttpClient parameters file > String file=JMeterUtils.getProperty("hc.parameters.file"); // $NON-NLS-1$ > if (file != null) { > HttpClientDefaultParameters.load(file, DEFAULT_HTTP_PARAMS); > } > > // Set up HTTP scheme override if necessary > if (CPS_HTTP > 0) { > log.info("Setting up HTTP SlowProtocol, cps="+CPS_HTTP); > SLOW_HTTP = new Scheme(HTTPConstants.PROTOCOL_HTTP, HTTPConstants.DEFAULT_HTTP_PORT, new SlowHC4SocketFactory(CPS_HTTP)); > } else { > SLOW_HTTP = null; > } > > if (localAddress != null){ > DEFAULT_HTTP_PARAMS.setParameter(ConnRoutePNames.LOCAL_ADDRESS, localAddress); > } > > } > > private volatile HttpUriRequest currentRequest; // Accessed from multiple threads > > private volatile boolean resetSSLContext; > > protected HTTPHC4Impl(HTTPSamplerBase testElement) { > super(testElement); > } > > public static final class HttpDelete extends HttpEntityEnclosingRequestBase { > > public HttpDelete(final URI uri) { > super(); > setURI(uri); > } > > @Override > public String getMethod() { > return HTTPConstants.DELETE; > } > } > > @Override > protected HTTPSampleResult sample(URL url, String method, > boolean areFollowingRedirect, int frameDepth) { > > if (log.isDebugEnabled()) { > log.debug("Start : sample " + url.toString()); > log.debug("method " + method+ " followingRedirect " + areFollowingRedirect + " depth " + frameDepth); > } > > HTTPSampleResult res = createSampleResult(url, method); > > HttpClient httpClient = setupClient(url, res); > > HttpRequestBase httpRequest = null; > try { > URI uri = url.toURI(); > if (method.equals(HTTPConstants.POST)) { > httpRequest = new HttpPost(uri); > } else if (method.equals(HTTPConstants.GET)) { > httpRequest = new HttpGet(uri); > } else if (method.equals(HTTPConstants.PUT)) { > httpRequest = new HttpPut(uri); > } else if (method.equals(HTTPConstants.HEAD)) { > httpRequest = new HttpHead(uri); > } else if (method.equals(HTTPConstants.TRACE)) { > httpRequest = new HttpTrace(uri); > } else if (method.equals(HTTPConstants.OPTIONS)) { > httpRequest = new HttpOptions(uri); > } else if (method.equals(HTTPConstants.DELETE)) { > httpRequest = new HttpDelete(uri); > } else if (method.equals(HTTPConstants.PATCH)) { > httpRequest = new HttpPatch(uri); > } else if (HttpWebdav.isWebdavMethod(method)) { > httpRequest = new HttpWebdav(method, uri); > } else { > throw new IllegalArgumentException("Unexpected method: '"+method+"'"); > } > setupRequest(url, httpRequest, res); // can throw IOException > } catch (Exception e) { > res.sampleStart(); > res.sampleEnd(); > errorResult(e, res); > return res; > } > > HttpContext localContext = new BasicHttpContext(); > setupClientContextBeforeSample(localContext); > > res.sampleStart(); > > final CacheManager cacheManager = getCacheManager(); > if (cacheManager != null && HTTPConstants.GET.equalsIgnoreCase(method)) { > if (cacheManager.inCache(url)) { > return updateSampleResultForResourceInCache(res); > } > } > > try { > currentRequest = httpRequest; > handleMethod(method, res, httpRequest, localContext); > // perform the sample > HttpResponse httpResponse = > executeRequest(httpClient, httpRequest, localContext, url); > > // Needs to be done after execute to pick up all the headers > final HttpRequest request = (HttpRequest) localContext.getAttribute(HttpCoreContext.HTTP_REQUEST); > extractClientContextAfterSample(localContext); > // We've finished with the request, so we can add the LocalAddress to it for display > final InetAddress localAddr = (InetAddress) httpRequest.getParams().getParameter(ConnRoutePNames.LOCAL_ADDRESS); > if (localAddr != null) { > request.addHeader(HEADER_LOCAL_ADDRESS, localAddr.toString()); > } > res.setRequestHeaders(getConnectionHeaders(request)); > > Header contentType = httpResponse.getLastHeader(HTTPConstants.HEADER_CONTENT_TYPE); > if (contentType != null){ > String ct = contentType.getValue(); > res.setContentType(ct); > res.setEncodingAndType(ct); > } > HttpEntity entity = httpResponse.getEntity(); > if (entity != null) { > res.setResponseData(readResponse(res, entity.getContent(), (int) entity.getContentLength())); > } > > res.sampleEnd(); // Done with the sampling proper. > currentRequest = null; > > // Now collect the results into the HTTPSampleResult: > StatusLine statusLine = httpResponse.getStatusLine(); > int statusCode = statusLine.getStatusCode(); > res.setResponseCode(Integer.toString(statusCode)); > res.setResponseMessage(statusLine.getReasonPhrase()); > res.setSuccessful(isSuccessCode(statusCode)); > > res.setResponseHeaders(getResponseHeaders(httpResponse)); > if (res.isRedirect()) { > final Header headerLocation = httpResponse.getLastHeader(HTTPConstants.HEADER_LOCATION); > if (headerLocation == null) { // HTTP protocol violation, but avoids NPE > throw new IllegalArgumentException("Missing location header in redirect for " + httpRequest.getRequestLine()); > } > String redirectLocation = headerLocation.getValue(); > res.setRedirectLocation(redirectLocation); > } > > // record some sizes to allow HTTPSampleResult.getBytes() with different options > HttpConnectionMetrics metrics = (HttpConnectionMetrics) localContext.getAttribute(CONTEXT_METRICS); > long headerBytes = > res.getResponseHeaders().length() // condensed length (without \r) > + httpResponse.getAllHeaders().length // Add \r for each header > + 1 // Add \r for initial header > + 2; // final \r\n before data > long totalBytes = metrics.getReceivedBytesCount(); > res.setHeadersSize((int) headerBytes); > res.setBodySize((int)(totalBytes - headerBytes)); > if (log.isDebugEnabled()) { > log.debug("ResponseHeadersSize=" + res.getHeadersSize() + " Content-Length=" + res.getBodySize() > + " Total=" + (res.getHeadersSize() + res.getBodySize())); > } > > // If we redirected automatically, the URL may have changed > if (getAutoRedirects()){ > HttpUriRequest req = (HttpUriRequest) localContext.getAttribute(HttpCoreContext.HTTP_REQUEST); > HttpHost target = (HttpHost) localContext.getAttribute(HttpCoreContext.HTTP_TARGET_HOST); > URI redirectURI = req.getURI(); > if (redirectURI.isAbsolute()){ > res.setURL(redirectURI.toURL()); > } else { > res.setURL(new URL(new URL(target.toURI()),redirectURI.toString())); > } > } > > // Store any cookies received in the cookie manager: > saveConnectionCookies(httpResponse, res.getURL(), getCookieManager()); > > // Save cache information > if (cacheManager != null){ > cacheManager.saveDetails(httpResponse, res); > } > > // Follow redirects and download page resources if appropriate: > res = resultProcessing(areFollowingRedirect, frameDepth, res); > > } catch (IOException e) { > log.debug("IOException", e); > if (res.getEndTime() == 0) { > res.sampleEnd(); > } > // pick up headers if failed to execute the request > if (res.getRequestHeaders() != null) { > log.debug("Overwriting request old headers: " + res.getRequestHeaders()); > } > res.setRequestHeaders(getConnectionHeaders((HttpRequest) localContext.getAttribute(HttpCoreContext.HTTP_REQUEST))); > errorResult(e, res); > return res; > } catch (RuntimeException e) { > log.debug("RuntimeException", e); > if (res.getEndTime() == 0) { > res.sampleEnd(); > } > errorResult(e, res); > return res; > } finally { > currentRequest = null; > } > return res; > } > > /** > * Store in JMeter Variables the UserToken so that the SSL context is reused > * See https://bz.apache.org/bugzilla/show_bug.cgi?id=57804 > * @param localContext {@link HttpContext} > */ > private void extractClientContextAfterSample(HttpContext localContext) { > Object userToken = localContext.getAttribute(HttpClientContext.USER_TOKEN); > if(userToken != null) { > if(log.isDebugEnabled()) { > log.debug("Extracted from HttpContext user token:"+userToken+", storing it as JMeter variable:"+USER_TOKEN); > } > // During recording JMeterContextService.getContext().getVariables() is null > JMeterVariables jMeterVariables = JMeterContextService.getContext().getVariables(); > if (jMeterVariables != null) { > jMeterVariables.putObject(USER_TOKEN, userToken); > } > } > } > > /** > * Configure the UserToken so that the SSL context is reused > * See https://bz.apache.org/bugzilla/show_bug.cgi?id=57804 > * @param localContext {@link HttpContext} > */ > private void setupClientContextBeforeSample(HttpContext localContext) { > Object userToken = null; > // During recording JMeterContextService.getContext().getVariables() is null > JMeterVariables jMeterVariables = JMeterContextService.getContext().getVariables(); > if(jMeterVariables != null) { > userToken = jMeterVariables.getObject(USER_TOKEN); > } > if(userToken != null) { > if(log.isDebugEnabled()) { > log.debug("Found user token:"+userToken+" as JMeter variable:"+USER_TOKEN+", storing it in HttpContext"); > } > localContext.setAttribute(HttpClientContext.USER_TOKEN, userToken); > } else { > // It would be better to create a ClientSessionManager that would compute this value > // for now it can be Thread.currentThread().getName() but must be changed when we would change > // the Thread per User model > String userId = Thread.currentThread().getName(); > if(log.isDebugEnabled()) { > log.debug("Storing in HttpContext the user token:"+userId); > } > localContext.setAttribute(HttpClientContext.USER_TOKEN, userId); > } > } > > /** > * Calls {@link #sendPostData(HttpPost)} if method is <code>POST</code> and > * {@link #sendEntityData(HttpEntityEnclosingRequestBase)} if method is > * <code>PUT</code> or <code>PATCH</code> > * <p> > * Field HTTPSampleResult#queryString of result is modified in the 2 cases > * > * @param method > * String HTTP method > * @param result > * {@link HTTPSampleResult} > * @param httpRequest > * {@link HttpRequestBase} > * @param localContext > * {@link HttpContext} > * @throws IOException > * when posting data fails due to I/O > */ > protected void handleMethod(String method, HTTPSampleResult result, > HttpRequestBase httpRequest, HttpContext localContext) throws IOException { > // Handle the various methods > if (method.equals(HTTPConstants.POST)) { > String postBody = sendPostData((HttpPost)httpRequest); > result.setQueryString(postBody); > } else if (method.equals(HTTPConstants.PUT) || method.equals(HTTPConstants.PATCH) > || HttpWebdav.isWebdavMethod(method) > || method.equals(HTTPConstants.DELETE)) { > String entityBody = sendEntityData(( HttpEntityEnclosingRequestBase)httpRequest); > result.setQueryString(entityBody); > } > } > > /** > * Create HTTPSampleResult filling url, method and SampleLabel. > * Monitor field is computed calling isMonitor() > * @param url URL > * @param method HTTP Method > * @return {@link HTTPSampleResult} > */ > protected HTTPSampleResult createSampleResult(URL url, String method) { > HTTPSampleResult res = new HTTPSampleResult(); > res.setMonitor(isMonitor()); > > res.setSampleLabel(url.toString()); // May be replaced later > res.setHTTPMethod(method); > res.setURL(url); > > return res; > } > > /** > * Execute request either as is or under PrivilegedAction > * if a Subject is available for url > * @param httpClient the {@link HttpClient} to be used to execute the httpRequest > * @param httpRequest the {@link HttpRequest} to be executed > * @param localContext th {@link HttpContext} to be used for execution > * @param url the target url (will be used to look up a possible subject for the execution) > * @return the result of the execution of the httpRequest > * @throws IOException > * @throws ClientProtocolException > */ > private HttpResponse executeRequest(final HttpClient httpClient, > final HttpRequestBase httpRequest, final HttpContext localContext, final URL url) > throws IOException, ClientProtocolException { > AuthManager authManager = getAuthManager(); > if (authManager != null) { > Subject subject = authManager.getSubjectForUrl(url); > if(subject != null) { > try { > return Subject.doAs(subject, > new PrivilegedExceptionAction<HttpResponse>() { > > @Override > public HttpResponse run() throws Exception { > return httpClient.execute(httpRequest, > localContext); > } > }); > } catch (PrivilegedActionException e) { > log.error( > "Can't execute httpRequest with subject:"+subject, > e); > throw new RuntimeException("Can't execute httpRequest with subject:"+subject, e); > } > } > } > return httpClient.execute(httpRequest, localContext); > } > > /** > * Holder class for all fields that define an HttpClient instance; > * used as the key to the ThreadLocal map of HttpClient instances. > */ > private static final class HttpClientKey { > > private final String target; // protocol://[user:pass@]host:[port] > private final boolean hasProxy; > private final String proxyHost; > private final int proxyPort; > private final String proxyUser; > private final String proxyPass; > > private final int hashCode; // Always create hash because we will always need it > > /** > * @param url URL Only protocol and url authority are used (protocol://[user:pass@]host:[port]) > * @param hasProxy has proxy > * @param proxyHost proxy host > * @param proxyPort proxy port > * @param proxyUser proxy user > * @param proxyPass proxy password > */ > public HttpClientKey(URL url, boolean hasProxy, String proxyHost, > int proxyPort, String proxyUser, String proxyPass) { > // N.B. need to separate protocol from authority otherwise http://server would match https://erver (<= sic, not typo error) > // could use separate fields, but simpler to combine them > this.target = url.getProtocol()+"://"+url.getAuthority(); > this.hasProxy = hasProxy; > this.proxyHost = proxyHost; > this.proxyPort = proxyPort; > this.proxyUser = proxyUser; > this.proxyPass = proxyPass; > this.hashCode = getHash(); > } > > private int getHash() { > int hash = 17; > hash = hash*31 + (hasProxy ? 1 : 0); > if (hasProxy) { > hash = hash*31 + getHash(proxyHost); > hash = hash*31 + proxyPort; > hash = hash*31 + getHash(proxyUser); > hash = hash*31 + getHash(proxyPass); > } > hash = hash*31 + target.hashCode(); > return hash; > } > > // Allow for null strings > private int getHash(String s) { > return s == null ? 0 : s.hashCode(); > } > > @Override > public boolean equals (Object obj){ > if (this == obj) { > return true; > } > if (!(obj instanceof HttpClientKey)) { > return false; > } > HttpClientKey other = (HttpClientKey) obj; > if (this.hasProxy) { // otherwise proxy String fields may be null > return > this.hasProxy == other.hasProxy && > this.proxyPort == other.proxyPort && > this.proxyHost.equals(other.proxyHost) && > this.proxyUser.equals(other.proxyUser) && > this.proxyPass.equals(other.proxyPass) && > this.target.equals(other.target); > } > // No proxy, so don't check proxy fields > return > this.hasProxy == other.hasProxy && > this.target.equals(other.target); > } > > @Override > public int hashCode(){ > return hashCode; > } > > // For debugging > @Override > public String toString() { > StringBuilder sb = new StringBuilder(); > sb.append(target); > if (hasProxy) { > sb.append(" via "); > sb.append(proxyUser); > sb.append("@"); > sb.append(proxyHost); > sb.append(":"); > sb.append(proxyPort); > } > return sb.toString(); > } > } > > private HttpClient setupClient(URL url, SampleResult res) { > > Map<HttpClientKey, HttpClient> mapHttpClientPerHttpClientKey = HTTPCLIENTS_CACHE_PER_THREAD_AND_HTTPCLIENTKEY.get(); > > final String host = url.getHost(); > String proxyHost = getProxyHost(); > int proxyPort = getProxyPortInt(); > String proxyPass = getProxyPass(); > String proxyUser = getProxyUser(); > > // static proxy is the globally define proxy eg command line or properties > boolean useStaticProxy = isStaticProxy(host); > // dynamic proxy is the proxy defined for this sampler > boolean useDynamicProxy = isDynamicProxy(proxyHost, proxyPort); > boolean useProxy = useStaticProxy || useDynamicProxy; > > // if both dynamic and static are used, the dynamic proxy has priority over static > if(!useDynamicProxy) { > proxyHost = PROXY_HOST; > proxyPort = PROXY_PORT; > proxyUser = PROXY_USER; > proxyPass = PROXY_PASS; > } > > // Lookup key - must agree with all the values used to create the HttpClient. > HttpClientKey key = new HttpClientKey(url, useProxy, proxyHost, proxyPort, proxyUser, proxyPass); > > HttpClient httpClient = mapHttpClientPerHttpClientKey.get(key); > > if (httpClient != null && resetSSLContext && HTTPConstants.PROTOCOL_HTTPS.equalsIgnoreCase(url.getProtocol())) { > ((AbstractHttpClient) httpClient).clearRequestInterceptors(); > ((AbstractHttpClient) httpClient).clearResponseInterceptors(); > httpClient.getConnectionManager().closeIdleConnections(1L, TimeUnit.MICROSECONDS); > httpClient = null; > JsseSSLManager sslMgr = (JsseSSLManager) SSLManager.getInstance(); > sslMgr.resetContext(); > resetSSLContext = false; > } > > if (httpClient == null) { // One-time init for this client > > HttpParams clientParams = new DefaultedHttpParams(new BasicHttpParams(), DEFAULT_HTTP_PARAMS); > > DnsResolver resolver = this.testElement.getDNSResolver(); > if (resolver == null) { > resolver = SystemDefaultDnsResolver.INSTANCE; > } > MeasuringConnectionManager connManager = new MeasuringConnectionManager(createSchemeRegistry(), resolver); > > // Modern browsers use more connections per host than the current httpclient default (2) > // when using parallel download the httpclient and connection manager are shared by the downloads threads > // to be realistic JMeter must set an higher value to DefaultMaxPerRoute > if(this.testElement.isConcurrentDwn()) { > try { > int maxConcurrentDownloads = Integer.parseInt(this.testElement.getConcurrentPool()); > connManager.setDefaultMaxPerRoute(Math.max(maxConcurrentDownloads, connManager.getDefaultMaxPerRoute())); > } catch (NumberFormatException nfe) { > // no need to log -> will be done by the sampler > } > } > > httpClient = new DefaultHttpClient(connManager, clientParams) { > @Override > protected HttpRequestRetryHandler createHttpRequestRetryHandler() { > return new DefaultHttpRequestRetryHandler(RETRY_COUNT, false); // set retry count > } > }; > > if (IDLE_TIMEOUT > 0) { > ((AbstractHttpClient) httpClient).setKeepAliveStrategy(IDLE_STRATEGY ); > } > // see https://issues.apache.org/jira/browse/HTTPCORE-397 > ((AbstractHttpClient) httpClient).setReuseStrategy(DefaultClientConnectionReuseStrategy.INSTANCE); > ((AbstractHttpClient) httpClient).addResponseInterceptor(new ResponseContentEncoding()); > ((AbstractHttpClient) httpClient).addResponseInterceptor(METRICS_SAVER); // HACK > ((AbstractHttpClient) httpClient).addRequestInterceptor(METRICS_RESETTER); > > // Override the default schemes as necessary > SchemeRegistry schemeRegistry = httpClient.getConnectionManager().getSchemeRegistry(); > > if (SLOW_HTTP != null){ > schemeRegistry.register(SLOW_HTTP); > } > > // Set up proxy details > if(useProxy) { > > HttpHost proxy = new HttpHost(proxyHost, proxyPort); > clientParams.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); > > if (proxyUser.length() > 0) { > ((AbstractHttpClient) httpClient).getCredentialsProvider().setCredentials( > new AuthScope(proxyHost, proxyPort), > new NTCredentials(proxyUser, proxyPass, localHost, PROXY_DOMAIN)); > } > } > > // Bug 52126 - we do our own cookie handling > clientParams.setParameter(ClientPNames.COOKIE_POLICY, CookieSpecs.IGNORE_COOKIES); > > if (log.isDebugEnabled()) { > log.debug("Created new HttpClient: @"+System.identityHashCode(httpClient) + " " + key.toString()); > } > > mapHttpClientPerHttpClientKey.put(key, httpClient); // save the agent for next time round > } else { > if (log.isDebugEnabled()) { > log.debug("Reusing the HttpClient: @"+System.identityHashCode(httpClient) + " " + key.toString()); > } > } > > MeasuringConnectionManager connectionManager = (MeasuringConnectionManager) httpClient.getConnectionManager(); > connectionManager.setSample(res); > > // TODO - should this be done when the client is created? > // If so, then the details need to be added as part of HttpClientKey > setConnectionAuthorization(httpClient, url, getAuthManager(), key); > > return httpClient; > } > > /** > * Setup LazySchemeSocketFactory > * @see https://bz.apache.org/bugzilla/show_bug.cgi?id=58099 > */ > private static SchemeRegistry createSchemeRegistry() { > final SchemeRegistry registry = new SchemeRegistry(); > registry.register( > new Scheme("http", 80, PlainSocketFactory.getSocketFactory())); //$NON-NLS-1$ > registry.register( > new Scheme("https", 443, new LazySchemeSocketFactory())); //$NON-NLS-1$ > return registry; > } > > /** > * Setup following elements on httpRequest: > * <ul> > * <li>ConnRoutePNames.LOCAL_ADDRESS enabling IP-SPOOFING</li> > * <li>Socket and connection timeout</li> > * <li>Redirect handling</li> > * <li>Keep Alive header or Connection Close</li> > * <li>Calls setConnectionHeaders to setup headers</li> > * <li>Calls setConnectionCookie to setup Cookie</li> > * </ul> > * > * @param url > * {@link URL} of the request > * @param httpRequest > * http request for the request > * @param res > * sample result to set cookies on > * @throws IOException > * if hostname/ip to use could not be figured out > */ > protected void setupRequest(URL url, HttpRequestBase httpRequest, HTTPSampleResult res) > throws IOException { > > HttpParams requestParams = httpRequest.getParams(); > > // Set up the local address if one exists > final InetAddress inetAddr = getIpSourceAddress(); > if (inetAddr != null) {// Use special field ip source address (for pseudo 'ip spoofing') > requestParams.setParameter(ConnRoutePNames.LOCAL_ADDRESS, inetAddr); > } else if (localAddress != null){ > requestParams.setParameter(ConnRoutePNames.LOCAL_ADDRESS, localAddress); > } else { // reset in case was set previously > requestParams.removeParameter(ConnRoutePNames.LOCAL_ADDRESS); > } > > int rto = getResponseTimeout(); > if (rto > 0){ > requestParams.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, rto); > } > > int cto = getConnectTimeout(); > if (cto > 0){ > requestParams.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, cto); > } > > requestParams.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, getAutoRedirects()); > > // a well-behaved 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()) { > httpRequest.setHeader(HTTPConstants.HEADER_CONNECTION, HTTPConstants.KEEP_ALIVE); > } else { > httpRequest.setHeader(HTTPConstants.HEADER_CONNECTION, HTTPConstants.CONNECTION_CLOSE); > } > > setConnectionHeaders(httpRequest, url, getHeaderManager(), getCacheManager()); > > String cookies = setConnectionCookie(httpRequest, url, getCookieManager()); > > if (res != null) { > res.setCookies(cookies); > } > >} > > > /** > * Set any default request headers to include > * > * @param request the HttpRequest to be used > */ > protected void setDefaultRequestHeaders(HttpRequest request) { > // Method left empty here, but allows subclasses to override > } > > /** > * Gets the ResponseHeaders > * > * @param response > * containing the headers > * @return string containing the headers, one per line > */ > private String getResponseHeaders(HttpResponse response) { > StringBuilder headerBuf = new StringBuilder(); > Header[] rh = response.getAllHeaders(); > headerBuf.append(response.getStatusLine());// header[0] is not the status line... > headerBuf.append("\n"); // $NON-NLS-1$ > > for (Header responseHeader : rh) { > headerBuf.append(responseHeader.getName()); > headerBuf.append(": "); // $NON-NLS-1$ > headerBuf.append(responseHeader.getValue()); > 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>HttpMethod</code> passed in. > * > * @param request <code>HttpRequest</code> for the request > * @param url <code>URL</code> of the request > * @param cookieManager the <code>CookieManager</code> containing all the cookies > * @return a String containing the cookie details (for the response) > * May be null > */ > protected String setConnectionCookie(HttpRequest request, URL url, CookieManager cookieManager) { > String cookieHeader = null; > if (cookieManager != null) { > cookieHeader = cookieManager.getCookieHeaderForURL(url); > if (cookieHeader != null) { > request.setHeader(HTTPConstants.HEADER_COOKIE, cookieHeader); > } > } > return cookieHeader; > } > > /** > * Extracts all the required non-cookie headers for that particular URL request and > * sets them in the <code>HttpMethod</code> passed in > * > * @param request > * <code>HttpRequest</code> which represents the request > * @param url > * <code>URL</code> of the URL request > * @param headerManager > * the <code>HeaderManager</code> containing all the cookies > * for this <code>UrlConfig</code> > * @param cacheManager the CacheManager (may be null) > */ > protected void setConnectionHeaders(HttpRequestBase request, URL url, HeaderManager headerManager, CacheManager cacheManager) { > if (headerManager != null) { > CollectionProperty headers = headerManager.getHeaders(); > if (headers != null) { > for (JMeterProperty jMeterProperty : headers) { > org.apache.jmeter.protocol.http.control.Header header > = (org.apache.jmeter.protocol.http.control.Header) > jMeterProperty.getObjectValue(); > String n = header.getName(); > // Don't allow override of Content-Length > // TODO - what other headers are not allowed? > if (! HTTPConstants.HEADER_CONTENT_LENGTH.equalsIgnoreCase(n)){ > String v = header.getValue(); > if (HTTPConstants.HEADER_HOST.equalsIgnoreCase(n)) { > int port = getPortFromHostHeader(v, url.getPort()); > v = v.replaceFirst(":\\d+$",""); // remove any port specification // $NON-NLS-1$ $NON-NLS-2$ > if (port != -1) { > if (port == url.getDefaultPort()) { > port = -1; // no need to specify the port if it is the default > } > } > request.getParams().setParameter(ClientPNames.VIRTUAL_HOST, new HttpHost(v, port)); > } else { > request.addHeader(n, v); > } > } > } > } > } > if (cacheManager != null){ > cacheManager.setHeaders(url, request); > } > } > > /** > * Get port from the value of the Host header, or return the given > * defaultValue > * > * @param hostHeaderValue > * value of the http Host header > * @param defaultValue > * value to be used, when no port could be extracted from > * hostHeaderValue > * @return integer representing the port for the host header > */ > private int getPortFromHostHeader(String hostHeaderValue, int defaultValue) { > String[] hostParts = hostHeaderValue.split(":"); > if (hostParts.length > 1) { > String portString = hostParts[hostParts.length - 1]; > if (portString.matches("^\\d+$")) { > return Integer.parseInt(portString); > } > } > return defaultValue; > } > > /** > * Get all the request headers for the <code>HttpMethod</code> > * > * @param method > * <code>HttpMethod</code> which represents the request > * @return the headers as a string > */ > private String getConnectionHeaders(HttpRequest method) { > if(method != null) { > // Get all the request headers > StringBuilder hdrs = new StringBuilder(100); > Header[] requestHeaders = method.getAllHeaders(); > for (Header requestHeader : requestHeaders) { > // Exclude the COOKIE header, since cookie is reported separately in the sample > if (!HTTPConstants.HEADER_COOKIE.equalsIgnoreCase(requestHeader.getName())) { > hdrs.append(requestHeader.getName()); > hdrs.append(": "); // $NON-NLS-1$ > hdrs.append(requestHeader.getValue()); > hdrs.append("\n"); // $NON-NLS-1$ > } > } > > return hdrs.toString(); > } > return ""; ////$NON-NLS-1$ > } > > /** > * Setup credentials for url AuthScope but keeps Proxy AuthScope credentials > * @param client HttpClient > * @param url URL > * @param authManager {@link AuthManager} > * @param key key > */ > private void setConnectionAuthorization(HttpClient client, URL url, AuthManager authManager, HttpClientKey key) { > CredentialsProvider credentialsProvider = > ((AbstractHttpClient) client).getCredentialsProvider(); > if (authManager != null) { > if(authManager.hasAuthForURL(url)) { > authManager.setupCredentials(client, url, credentialsProvider, localHost); > } else { > credentialsProvider.clear(); > } > } else { > Credentials credentials = null; > AuthScope authScope = null; > if(key.hasProxy && !StringUtils.isEmpty(key.proxyUser)) { > authScope = new AuthScope(key.proxyHost, key.proxyPort); > credentials = credentialsProvider.getCredentials(authScope); > } > credentialsProvider.clear(); > if(credentials != null) { > credentialsProvider.setCredentials(authScope, credentials); > } > } > } > > // Helper class so we can generate request data without dumping entire file contents > private static class ViewableFileBody extends FileBody { > private boolean hideFileData; > > public ViewableFileBody(File file, String mimeType) { > super(file, mimeType); > hideFileData = false; > } > > @Override > public void writeTo(final OutputStream out) throws IOException { > if (hideFileData) { > out.write("<actual file content, not shown here>".getBytes());// encoding does not really matter here > } else { > super.writeTo(out); > } > } > } > > // TODO needs cleaning up > /** > * > * @param post {@link HttpPost} > * @return String posted body if computable > * @throws IOException if sending the data fails due to I/O > */ > protected String sendPostData(HttpPost post) throws IOException { > // Buffer to hold the post body, except file content > StringBuilder postedBody = new StringBuilder(1000); > HTTPFileArg[] files = getHTTPFiles(); > > final String contentEncoding = getContentEncodingOrNull(); > final boolean haveContentEncoding = contentEncoding != null; > > // Check if we should do a multipart/form-data or an > // application/x-www-form-urlencoded post request > if(getUseMultipartForPost()) { > // If a content encoding is specified, we use that as the > // encoding of any parameter values > Charset charset = null; > if(haveContentEncoding) { > charset = Charset.forName(contentEncoding); > } > > // Write the request to our own stream >// DJ removed MultipartEntity multiPart = new MultipartEntity( >// getDoBrowserCompatibleMultipart() ? HttpMultipartMode.BROWSER_COMPATIBLE : HttpMultipartMode.STRICT, >// null, charset); >//DJ added > MultipartEntityBuilder mep = MultipartEntityBuilder.create(); > // Create the parts > // Add any parameters > for (JMeterProperty jMeterProperty : getArguments()) { > HTTPArgument arg = (HTTPArgument) jMeterProperty.getObjectValue(); > String parameterName = arg.getName(); > if (arg.isSkippable(parameterName)) { > continue; > } >// DJ removed StringBody stringBody = new StringBody(arg.getValue(), charset); >// DJ removed FormBodyPart formPart = new FormBodyPart(arg.getName(), stringBody); >// DJ removed multiPart.addPart(formPart); >//DJ added > mep.addBinaryBody(arg.getName(), arg.getValue().getBytes(contentEncoding)); > mep.setLaxMode(); > } > > // Add any files > // Cannot retrieve parts once added to the MultiPartEntity, so have to save them here. > ViewableFileBody[] fileBodies = new ViewableFileBody[files.length]; > for (int i=0; i < files.length; i++) { > HTTPFileArg file = files[i]; > > File reservedFile = FileServer.getFileServer().getResolvedFile(file.getPath()); > fileBodies[i] = new ViewableFileBody(reservedFile, file.getMimeType()); >// DJ removed multiPart.addPart(file.getParamName(),fileBodies[i]); > mep.addPart(file.getParamName(), fileBodies[i] ); > } >//DJ added >HttpEntity pst = mep.build(); > post.setEntity(pst); >//DJ Changed from multipart to pst > if (pst.isRepeatable()){ > ByteArrayOutputStream bos = new ByteArrayOutputStream(); > for(ViewableFileBody fileBody : fileBodies){ > fileBody.hideFileData = true; > } > >//DJ Changed from multipart to pst > pst.writeTo(bos); > for(ViewableFileBody fileBody : fileBodies){ > fileBody.hideFileData = false; > } > bos.flush(); > // We get the posted bytes using the encoding used to create it > postedBody.append(new String(bos.toByteArray(), > contentEncoding == null ? "US-ASCII" // $NON-NLS-1$ this is the default used by HttpClient > : contentEncoding)); > bos.close(); > } else { > postedBody.append("<Multipart was not repeatable, cannot view what was sent>"); // $NON-NLS-1$ > } > >// // Set the content type TODO - needed? >// String multiPartContentType = multiPart.getContentType().getValue(); >// post.setHeader(HEADER_CONTENT_TYPE, multiPartContentType); > > } else { // not multipart > // Check if the header manager had a content type header > // This allows the user to specify his own content-type for a POST request > Header contentTypeHeader = post.getFirstHeader(HTTPConstants.HEADER_CONTENT_TYPE); > boolean hasContentTypeHeader = contentTypeHeader != null && contentTypeHeader.getValue() != null && contentTypeHeader.getValue().length() > 0; > // If there are no arguments, we can send a file as the body of the request > // TODO: needs a multiple file upload scenerio > if(!hasArguments() && getSendFileAsPostBody()) { > // If getSendFileAsPostBody returned true, it's sure that file is not null > HTTPFileArg file = files[0]; > if(!hasContentTypeHeader) { > // Allow the mimetype of the file to control the content type > if(file.getMimeType() != null && file.getMimeType().length() > 0) { > post.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, file.getMimeType()); > } > else { > post.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED); > } > } > > FileEntity fileRequestEntity = new FileEntity(new File(file.getPath()),(ContentType) null);// TODO is null correct? > post.setEntity(fileRequestEntity); > > // We just add placeholder text for file content > postedBody.append("<actual file content, not shown here>"); > } else { > // In a post request which is not multipart, we only support > // parameters, no file upload is allowed > > // If a content encoding is specified, we set it as http parameter, so that > // the post body will be encoded in the specified content encoding > if(haveContentEncoding) { > post.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, contentEncoding); > } > > // If none of the arguments have a name specified, we > // just send all the values as the post body > if(getSendParameterValuesAsPostBody()) { > // Allow the mimetype of the file to control the content type > // This is not obvious in GUI if you are not uploading any files, > // but just sending the content of nameless parameters > // TODO: needs a multiple file upload scenerio > if(!hasContentTypeHeader) { > HTTPFileArg file = files.length > 0? files[0] : null; > if(file != null && file.getMimeType() != null && file.getMimeType().length() > 0) { > post.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, file.getMimeType()); > } > else { > // TODO - is this the correct default? > post.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED); > } > } > > // Just append all the parameter values, and use that as the post body > StringBuilder postBody = new StringBuilder(); > for (JMeterProperty jMeterProperty : getArguments()) { > HTTPArgument arg = (HTTPArgument) jMeterProperty.getObjectValue(); > // Note: if "Encoded?" is not selected, arg.getEncodedValue is equivalent to arg.getValue > if (haveContentEncoding) { > postBody.append(arg.getEncodedValue(contentEncoding)); > } else { > postBody.append(arg.getEncodedValue()); > } > } > // Let StringEntity perform the encoding > StringEntity requestEntity = new StringEntity(postBody.toString(), contentEncoding); > post.setEntity(requestEntity); > postedBody.append(postBody.toString()); > } else { > // It is a normal post request, with parameter names and values > > // Set the content type > if(!hasContentTypeHeader) { > post.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED); > } > // Add the parameters > PropertyIterator args = getArguments().iterator(); > List <NameValuePair> nvps = new ArrayList<>(); > String urlContentEncoding = contentEncoding; > if(urlContentEncoding == null || urlContentEncoding.length() == 0) { > // Use the default encoding for urls > urlContentEncoding = EncoderCache.URL_ARGUMENT_ENCODING; > } > while (args.hasNext()) { > HTTPArgument arg = (HTTPArgument) args.next().getObjectValue(); > // The HTTPClient always urlencodes both name and value, > // so if the argument is already encoded, we have to decode > // it before adding it to the post request > String parameterName = arg.getName(); > if (arg.isSkippable(parameterName)){ > continue; > } > String parameterValue = arg.getValue(); > if(!arg.isAlwaysEncoded()) { > // The value is already encoded by the user > // Must decode the value now, so that when the > // httpclient encodes it, we end up with the same value > // as the user had entered. > parameterName = URLDecoder.decode(parameterName, urlContentEncoding); > parameterValue = URLDecoder.decode(parameterValue, urlContentEncoding); > } > // Add the parameter, httpclient will urlencode it > nvps.add(new BasicNameValuePair(parameterName, parameterValue)); > } > UrlEncodedFormEntity entity = new UrlEncodedFormEntity(nvps, urlContentEncoding); > post.setEntity(entity); > if (entity.isRepeatable()){ > ByteArrayOutputStream bos = new ByteArrayOutputStream(); > post.getEntity().writeTo(bos); > bos.flush(); > // We get the posted bytes using the encoding used to create it > if (contentEncoding != null) { > postedBody.append(new String(bos.toByteArray(), contentEncoding)); > } else { > postedBody.append(new String(bos.toByteArray(), SampleResult.DEFAULT_HTTP_ENCODING)); > } > bos.close(); > } else { > postedBody.append("<RequestEntity was not repeatable, cannot view what was sent>"); > } > } > } > } > return postedBody.toString(); > } > > // TODO merge put and post methods as far as possible. > // e.g. post checks for multipart form/files, and if not, invokes sendData(HttpEntityEnclosingRequestBase) > > > /** > * Creates the entity data to be sent. > * <p> > * If there is a file entry with a non-empty MIME type we use that to > * set the request Content-Type header, otherwise we default to whatever > * header is present from a Header Manager. > * <p> > * If the content charset {@link #getContentEncoding()} is null or empty > * we use the HC4 default provided by {@link HTTP#DEF_CONTENT_CHARSET} which is > * ISO-8859-1. > * > * @param entity to be processed, e.g. PUT or PATCH > * @return the entity content, may be empty > * @throws UnsupportedEncodingException for invalid charset name > * @throws IOException cannot really occur for ByteArrayOutputStream methods > */ > protected String sendEntityData( HttpEntityEnclosingRequestBase entity) throws IOException { > // Buffer to hold the entity body > StringBuilder entityBody = new StringBuilder(1000); > boolean hasEntityBody = false; > > final HTTPFileArg[] files = getHTTPFiles(); > // Allow the mimetype of the file to control the content type > // This is not obvious in GUI if you are not uploading any files, > // but just sending the content of nameless parameters > final HTTPFileArg file = files.length > 0? files[0] : null; > String contentTypeValue = null; > if(file != null && file.getMimeType() != null && file.getMimeType().length() > 0) { > contentTypeValue = file.getMimeType(); > entity.setHeader(HEADER_CONTENT_TYPE, contentTypeValue); // we provide the MIME type here > } > > // Check for local contentEncoding (charset) override; fall back to default for content body > // we do this here rather so we can use the same charset to retrieve the data > final String charset = getContentEncoding(HTTP.DEF_CONTENT_CHARSET.name()); > > // Only create this if we are overriding whatever default there may be > // If there are no arguments, we can send a file as the body of the request > > if(!hasArguments() && getSendFileAsPostBody()) { > hasEntityBody = true; > > // If getSendFileAsPostBody returned true, it's sure that file is not null > File reservedFile = FileServer.getFileServer().getResolvedFile(files[0].getPath()); > FileEntity fileRequestEntity = new FileEntity(reservedFile); // no need for content-type here > entity.setEntity(fileRequestEntity); > } > // If none of the arguments have a name specified, we > // just send all the values as the entity body > else if(getSendParameterValuesAsPostBody()) { > hasEntityBody = true; > > // Just append all the parameter values, and use that as the entity body > StringBuilder entityBodyContent = new StringBuilder(); > for (JMeterProperty jMeterProperty : getArguments()) { > HTTPArgument arg = (HTTPArgument) jMeterProperty.getObjectValue(); > // Note: if "Encoded?" is not selected, arg.getEncodedValue is equivalent to arg.getValue > if (charset != null) { > entityBodyContent.append(arg.getEncodedValue(charset)); > } else { > entityBodyContent.append(arg.getEncodedValue()); > } > } > StringEntity requestEntity = new StringEntity(entityBodyContent.toString(), charset); > entity.setEntity(requestEntity); > } > // Check if we have any content to send for body > if(hasEntityBody) { > // If the request entity is repeatable, we can send it first to > // our own stream, so we can return it > final HttpEntity entityEntry = entity.getEntity(); > if(entityEntry.isRepeatable()) { > entityBody.append("<actual file content, not shown here>"); > } > else { // this probably cannot happen > entityBody.append("<RequestEntity was not repeatable, cannot view what was sent>"); > } > } > return entityBody.toString(); // may be the empty string > } > > /** > * > * @return the value of {@link #getContentEncoding()}; forced to null if empty > */ > private String getContentEncodingOrNull() { > return getContentEncoding(null); > } > > /** > * @param dflt the default to be used > * @return the value of {@link #getContentEncoding()}; default if null or empty > */ > private String getContentEncoding(String dflt) { > String ce = getContentEncoding(); > if (isNullOrEmptyTrimmed(ce)) { > return dflt; > } else { > return ce; > } > } > > private void saveConnectionCookies(HttpResponse method, URL u, CookieManager cookieManager) { > if (cookieManager != null) { > Header[] hdrs = method.getHeaders(HTTPConstants.HEADER_SET_COOKIE); > for (Header hdr : hdrs) { > cookieManager.addCookieFromHeader(hdr.getValue(),u); > } > } > } > > @Override > protected void notifyFirstSampleAfterLoopRestart() { > log.debug("notifyFirstSampleAfterLoopRestart"); > resetSSLContext = !USE_CACHED_SSL_CONTEXT; > } > > @Override > protected void threadFinished() { > log.debug("Thread Finished"); > closeThreadLocalConnections(); > } > > /** > * > */ > private void closeThreadLocalConnections() { > // Does not need to be synchronised, as all access is from same thread > Map<HttpClientKey, HttpClient> mapHttpClientPerHttpClientKey = HTTPCLIENTS_CACHE_PER_THREAD_AND_HTTPCLIENTKEY.get(); > if ( mapHttpClientPerHttpClientKey != null ) { > for ( HttpClient cl : mapHttpClientPerHttpClientKey.values() ) { > ((AbstractHttpClient) cl).clearRequestInterceptors(); > ((AbstractHttpClient) cl).clearResponseInterceptors(); > ((AbstractHttpClient) cl).close(); > cl.getConnectionManager().shutdown(); > } > mapHttpClientPerHttpClientKey.clear(); > } > } > > @Override > public boolean interrupt() { > HttpUriRequest request = currentRequest; > if (request != null) { > currentRequest = null; // don't try twice > try { > request.abort(); > } catch (UnsupportedOperationException e) { > log.warn("Could not abort pending request", e); > } > } > return request != null; > } > >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 56141
:
32251
|
32255
|
33607
|
33608
| 33610 |
33642