Author: pmouawad
Date: Fri Mar 2 23:37:26 2012
New Revision: 1296512
URL: http://svn.apache.org/viewvc?rev=1296512&view=rev
Log:
Bug 52674 - Proxy : Add a Sampler Creator to allow plugging HTTP based samplers
using potentially non textual POST Body (AMF, Silverlight...) and customizing
them for others
Added:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/AbstractSamplerCreator.java
(with props)
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/DefaultSamplerCreator.java
(with props)
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreator.java
(with props)
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreatorFactory.java
(with props)
Modified:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/HttpRequestHdr.java
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/Proxy.java
jmeter/trunk/xdocs/changes.xml
Added:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/AbstractSamplerCreator.java
URL:
http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/AbstractSamplerCreator.java?rev=1296512&view=auto
==============================================================================
---
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/AbstractSamplerCreator.java
(added)
+++
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/AbstractSamplerCreator.java
Fri Mar 2 23:37:26 2012
@@ -0,0 +1,123 @@
+/*
+ * 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.proxy;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.apache.jmeter.util.JMeterUtils;
+
+/**
+ * Base class for SamplerCreator
+ */
+public abstract class AbstractSamplerCreator implements SamplerCreator {
+
+ protected static final String HTTP = "http"; // $NON-NLS-1$
+ protected static final String HTTPS = "https"; // $NON-NLS-1$
+
+ /** Filetype to be used for the temporary binary files*/
+ private static final String binaryFileSuffix =
+ JMeterUtils.getPropDefault("proxy.binary.filesuffix",// $NON-NLS-1$
+ ".binary"); // $NON-NLS-1$
+
+ /** Which content-types will be treated as binary (exact match) */
+ private static final Set<String> binaryContentTypes = new
HashSet<String>();
+
+ /** Where to store the temporary binary files */
+ private static final String binaryDirectory =
+ JMeterUtils.getPropDefault("proxy.binary.directory",// $NON-NLS-1$
+ System.getProperty("user.dir")); // $NON-NLS-1$
proxy.binary.filetype=binary
+
+ static {
+ String binaries = JMeterUtils.getPropDefault("proxy.binary.types", //
$NON-NLS-1$
+ "application/x-amf,application/x-java-serialized-object"); //
$NON-NLS-1$
+ if (binaries.length() > 0){
+ StringTokenizer s = new StringTokenizer(binaries,"|, ");//
$NON-NLS-1$
+ while (s.hasMoreTokens()){
+ binaryContentTypes.add(s.nextToken());
+ }
+ }
+ }
+
+ /*
+ * Optionally number the requests
+ */
+ private static final boolean numberRequests =
+ JMeterUtils.getPropDefault("proxy.number.requests", false); //
$NON-NLS-1$
+
+ private static volatile int requestNumber = 0;// running number
+
+
+ /**
+ *
+ */
+ /**
+ *
+ */
+ public AbstractSamplerCreator() {
+ super();
+ }
+
+ /**
+ * @return int request number
+ */
+ protected static int getRequestNumber() {
+ return requestNumber;
+ }
+
+ /**
+ * Increment request number
+ */
+ protected static void incrementRequestNumber() {
+ requestNumber++;
+ }
+
+ /**
+ * @return boolean is numbering requests is required
+ */
+ protected static boolean isNumberRequests() {
+ return numberRequests;
+ }
+
+ /**
+ * @param contentType String content type
+ * @return true if contentType is part of binary declared types
+ */
+ protected boolean isBinaryContent(String contentType) {
+ if (contentType == null) {
+ return false;
+ }
+ return binaryContentTypes.contains(contentType);
+ }
+
+ /**
+ * @return String binary file suffix
+ */
+ protected String getBinaryFileSuffix() {
+ return binaryFileSuffix;
+ }
+
+ /**
+ * @return String binary directory
+ */
+ protected String getBinaryDirectory() {
+ return binaryDirectory;
+ }
+}
\ No newline at end of file
Propchange:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/AbstractSamplerCreator.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/DefaultSamplerCreator.java
URL:
http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/DefaultSamplerCreator.java?rev=1296512&view=auto
==============================================================================
---
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/DefaultSamplerCreator.java
(added)
+++
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/DefaultSamplerCreator.java
Fri Mar 2 23:37:26 2012
@@ -0,0 +1,349 @@
+/*
+ * 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.proxy;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.jmeter.protocol.http.config.MultipartUrlConfig;
+import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
+import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
+import org.apache.jmeter.protocol.http.sampler.HTTPSamplerFactory;
+import org.apache.jmeter.protocol.http.sampler.PostWriter;
+import org.apache.jmeter.protocol.http.util.ConversionUtils;
+import org.apache.jmeter.protocol.http.util.HTTPConstants;
+import org.apache.jmeter.protocol.http.util.HTTPFileArg;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+/**
+ * Default implementation that handles classical HTTP textual + Multipart
requests
+ */
+public class DefaultSamplerCreator extends AbstractSamplerCreator {
+ private static final Logger log = LoggingManager.getLoggerForClass();
+
+ /**
+ *
+ */
+ public DefaultSamplerCreator() {
+ }
+
+ /**
+ * @see
org.apache.jmeter.protocol.http.proxy.SamplerCreator#getManagedContentTypes()
+ */
+ public String[] getManagedContentTypes() {
+ return new String[0];
+ }
+
+ /**
+ *
+ * @see
org.apache.jmeter.protocol.http.proxy.SamplerCreator#createSampler(org.apache.jmeter.protocol.http.proxy.HttpRequestHdr,
java.util.Map, java.util.Map)
+ */
+ public HTTPSamplerBase createSampler(HttpRequestHdr request,
+ Map<String, String> pageEncodings, Map<String, String>
formEncodings) {
+ // Instantiate the sampler
+ HTTPSamplerBase sampler =
HTTPSamplerFactory.newInstance(request.getHttpSamplerName());
+
+ sampler.setProperty(TestElement.GUI_CLASS,
HttpTestSampleGui.class.getName());
+
+ // Defaults
+ sampler.setFollowRedirects(false);
+ sampler.setUseKeepAlive(true);
+
+ if (log.isDebugEnabled()) {
+ log.debug("getSampler: sampler path = " + sampler.getPath());
+ }
+ return sampler;
+ }
+
+ /**
+ * @see
org.apache.jmeter.protocol.http.proxy.SamplerCreator#populateSampler(org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase,
org.apache.jmeter.protocol.http.proxy.HttpRequestHdr, java.util.Map,
java.util.Map)
+ */
+ public final void populateSampler(HTTPSamplerBase sampler,
+ HttpRequestHdr request, Map<String, String> pageEncodings,
+ Map<String, String> formEncodings) throws Exception{
+ computeFromHeader(sampler, request, pageEncodings, formEncodings);
+
+ computeFromPostBody(sampler, request);
+ if (log.isDebugEnabled()) {
+ log.debug("sampler path = " + sampler.getPath());
+ }
+ }
+
+ /**
+ * Compute sampler informations from Request Header
+ * @param sampler {@link HTTPSamplerBase}
+ * @param request {@link HttpRequestHdr}
+ * @param pageEncodings Map<String, String>
+ * @param formEncodings Map<String, String>
+ * @throws Exception
+ */
+ protected void computeFromHeader(HTTPSamplerBase sampler,
+ HttpRequestHdr request, Map<String, String> pageEncodings,
+ Map<String, String> formEncodings) throws Exception {
+ computeDomain(sampler, request);
+
+ computeMethod(sampler, request);
+
+ computePort(sampler, request);
+
+ computeProtocol(sampler, request);
+
+ computeContentEncoding(sampler, request,
+ pageEncodings, formEncodings);
+
+ computePath(sampler, request);
+
+ computeSamplerName(sampler, request);
+ }
+
+ /**
+ * Compute sampler informations from Request Header
+ * @param sampler {@link HTTPSamplerBase}
+ * @param request {@link HttpRequestHdr}
+ * @throws Exception
+ */
+ protected void computeFromPostBody(HTTPSamplerBase sampler,
+ HttpRequestHdr request) throws Exception {
+ // If it was a HTTP GET request, then all parameters in the URL
+ // has been handled by the sampler.setPath above, so we just need
+ // to do parse the rest of the request if it is not a GET request
+ if((!HTTPConstants.CONNECT.equals(request.getMethod())) &&
(!HTTPConstants.GET.equals(request.getMethod()))) {
+ // Check if it was a multipart http post request
+ final String contentType = request.getContentType();
+ MultipartUrlConfig urlConfig =
request.getMultipartConfig(contentType);
+ String contentEncoding = sampler.getContentEncoding();
+ // Get the post data using the content encoding of the request
+ String postData = null;
+ if (log.isDebugEnabled()) {
+ if(!StringUtils.isEmpty(contentEncoding)) {
+ log.debug("Using encoding " + contentEncoding + " for
request body");
+ }
+ else {
+ log.debug("No encoding found, using JRE default encoding
for request body");
+ }
+ }
+
+
+ if (!StringUtils.isEmpty(contentEncoding)) {
+ postData = new String(request.getRawPostData(),
contentEncoding);
+ } else {
+ // Use default encoding
+ postData = new String(request.getRawPostData(),
PostWriter.ENCODING);
+ }
+
+ if (urlConfig != null) {
+ urlConfig.parseArguments(postData);
+ // Tell the sampler to do a multipart post
+ sampler.setDoMultipartPost(true);
+ // Remove the header for content-type and content-length, since
+ // those values will most likely be incorrect when the sampler
+ // performs the multipart request, because the boundary string
+ // will change
+
request.getHeaderManager().removeHeaderNamed(HttpRequestHdr.CONTENT_TYPE);
+
request.getHeaderManager().removeHeaderNamed(HttpRequestHdr.CONTENT_LENGTH);
+
+ // Set the form data
+ sampler.setArguments(urlConfig.getArguments());
+ // Set the file uploads
+ sampler.setHTTPFiles(urlConfig.getHTTPFileArgs().asArray());
+ // used when postData is pure xml (eg. an xml-rpc call) or for PUT
+ } else if (postData.trim().startsWith("<?") ||
"PUT".equals(sampler.getMethod())) {
+ sampler.addNonEncodedArgument("", postData, "");
+ } else if (contentType == null ||
contentType.startsWith(HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED) ){
+ // It is the most common post request, with parameter name and
values
+ // We also assume this if no content type is present, to be
most backwards compatible,
+ // but maybe we should only parse arguments if the content
type is as expected
+ sampler.parseArguments(postData.trim(), contentEncoding);
//standard name=value postData
+ } else if (postData.length() > 0) {
+ if (isBinaryContent(contentType)) {
+ try {
+ File tempDir = new File(getBinaryDirectory());
+ File out = File.createTempFile(request.getMethod(),
getBinaryFileSuffix(), tempDir);
+
FileUtils.writeByteArrayToFile(out,request.getRawPostData());
+ HTTPFileArg [] files = {new
HTTPFileArg(out.getPath(),"",contentType)};
+ sampler.setHTTPFiles(files);
+ } catch (IOException e) {
+ log.warn("Could not create binary file: "+e);
+ }
+ } else {
+ // Just put the whole postbody as the value of a parameter
+ sampler.addNonEncodedArgument("", postData, ""); //used
when postData is pure xml (ex. an xml-rpc call)
+ }
+ }
+ }
+ }
+
+ /**
+ * Compute sampler name
+ * @param sampler {@link HTTPSamplerBase}
+ * @param request {@link HttpRequestHdr}
+ */
+ protected void computeSamplerName(HTTPSamplerBase sampler,
+ HttpRequestHdr request) {
+ if (!HTTPConstants.CONNECT.equals(request.getMethod()) &&
isNumberRequests()) {
+ incrementRequestNumber();
+ sampler.setName(getRequestNumber() + " " + sampler.getPath());
+ } else {
+ sampler.setName(sampler.getPath());
+ }
+ }
+
+ /**
+ * Set path on sampler
+ * @param sampler {@link HTTPSamplerBase}
+ * @param request {@link HttpRequestHdr}
+ */
+ protected void computePath(HTTPSamplerBase sampler, HttpRequestHdr
request) {
+ if(sampler.getContentEncoding() != null) {
+ sampler.setPath(request.getPath(), sampler.getContentEncoding());
+ }
+ else {
+ // Although the spec says UTF-8 should be used for encoding URL
parameters,
+ // most browser use ISO-8859-1 for default if encoding is not
known.
+ // We use null for contentEncoding, then the url parameters will
be added
+ // with the value in the URL, and the "encode?" flag set to false
+ sampler.setPath(request.getPath(), null);
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("Proxy: setting path: " + sampler.getPath());
+ }
+ }
+
+ /**
+ * Compute content encoding
+ * @param sampler {@link HTTPSamplerBase}
+ * @param request {@link HttpRequestHdr}
+ * @param pageEncodings Map<String, String>
+ * @param formEncodings Map<String, String>
+ * @throws MalformedURLException
+ */
+ protected void computeContentEncoding(HTTPSamplerBase sampler,
+ HttpRequestHdr request, Map<String, String> pageEncodings,
+ Map<String, String> formEncodings) throws MalformedURLException {
+ URL pageUrl = null;
+ if(sampler.isProtocolDefaultPort()) {
+ pageUrl = new URL(sampler.getProtocol(), sampler.getDomain(),
request.getPath());
+ }
+ else {
+ pageUrl = new URL(sampler.getProtocol(), sampler.getDomain(),
+ sampler.getPort(), request.getPath());
+ }
+ String urlWithoutQuery = request.getUrlWithoutQuery(pageUrl);
+
+
+ String contentEncoding = computeContentEncoding(request, pageEncodings,
+ formEncodings, urlWithoutQuery);
+
+ // Set the content encoding
+ if(!StringUtils.isEmpty(contentEncoding)) {
+ sampler.setContentEncoding(contentEncoding);
+ }
+ }
+
+ /**
+ * Computes content encoding from request and if not found uses
pageEncoding
+ * and formEncoding to see if URL was previously computed with a content
type
+ * @param sampler {@link HTTPSamplerBase}
+ * @param request {@link HttpRequestHdr}
+ * @param pageEncodings Map<String, String>
+ * @param formEncodings Map<String, String>
+ * @return String content encoding
+ */
+ protected String computeContentEncoding(HttpRequestHdr request,
+ Map<String, String> pageEncodings,
+ Map<String, String> formEncodings, String urlWithoutQuery) {
+ // Check if the request itself tells us what the encoding is
+ String contentEncoding = null;
+ String requestContentEncoding =
ConversionUtils.getEncodingFromContentType(
+ request.getContentType());
+ if(requestContentEncoding != null) {
+ contentEncoding = requestContentEncoding;
+ }
+ else {
+ // Check if we know the encoding of the page
+ if (pageEncodings != null) {
+ synchronized (pageEncodings) {
+ contentEncoding = pageEncodings.get(urlWithoutQuery);
+ }
+ }
+ // Check if we know the encoding of the form
+ if (formEncodings != null) {
+ synchronized (formEncodings) {
+ String formEncoding = formEncodings.get(urlWithoutQuery);
+ // Form encoding has priority over page encoding
+ if (formEncoding != null) {
+ contentEncoding = formEncoding;
+ }
+ }
+ }
+ }
+ return contentEncoding;
+ }
+
+ /**
+ * Set protocol on sampler
+ * @param sampler {@link HTTPSamplerBase}
+ * @param request {@link HttpRequestHdr}
+ */
+ protected void computeProtocol(HTTPSamplerBase sampler,
+ HttpRequestHdr request) {
+ sampler.setProtocol(request.getProtocol(sampler));
+ }
+
+ /**
+ * Set Port on sampler
+ * @param sampler {@link HTTPSamplerBase}
+ * @param request {@link HttpRequestHdr}
+ */
+ protected void computePort(HTTPSamplerBase sampler, HttpRequestHdr
request) {
+ sampler.setPort(request.serverPort());
+ if (log.isDebugEnabled()) {
+ log.debug("Proxy: setting port: " + sampler.getPort());
+ }
+ }
+
+ /**
+ * Set method on sampler
+ * @param sampler {@link HTTPSamplerBase}
+ * @param request {@link HttpRequestHdr}
+ */
+ protected void computeMethod(HTTPSamplerBase sampler, HttpRequestHdr
request) {
+ sampler.setMethod(request.getMethod());
+ log.debug("Proxy: setting method: " + sampler.getMethod());
+ }
+
+ /**
+ * Set domain on sampler
+ * @param sampler {@link HTTPSamplerBase}
+ * @param request {@link HttpRequestHdr}
+ */
+ protected void computeDomain(HTTPSamplerBase sampler, HttpRequestHdr
request) {
+ sampler.setDomain(request.serverName());
+ if (log.isDebugEnabled()) {
+ log.debug("Proxy: setting server: " + sampler.getDomain());
+ }
+ }
+}
\ No newline at end of file
Propchange:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/DefaultSamplerCreator.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/HttpRequestHdr.java
URL:
http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/HttpRequestHdr.java?rev=1296512&r1=1296511&r2=1296512&view=diff
==============================================================================
---
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/HttpRequestHdr.java
(original)
+++
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/HttpRequestHdr.java
Fri Mar 2 23:37:26 2012
@@ -19,30 +19,20 @@
package org.apache.jmeter.protocol.http.proxy;
import java.io.ByteArrayOutputStream;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
import java.util.StringTokenizer;
-import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.CharUtils;
import org.apache.jmeter.protocol.http.config.MultipartUrlConfig;
import org.apache.jmeter.protocol.http.control.Header;
import org.apache.jmeter.protocol.http.control.HeaderManager;
-import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
import org.apache.jmeter.protocol.http.gui.HeaderPanel;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
-import org.apache.jmeter.protocol.http.sampler.HTTPSamplerFactory;
-import org.apache.jmeter.protocol.http.util.ConversionUtils;
import org.apache.jmeter.protocol.http.util.HTTPConstants;
-import org.apache.jmeter.protocol.http.util.HTTPFileArg;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.logging.LoggingManager;
@@ -60,32 +50,9 @@ public class HttpRequestHdr {
private static final String HTTP = "http"; // $NON-NLS-1$
private static final String HTTPS = "https"; // $NON-NLS-1$
private static final String PROXY_CONNECTION = "proxy-connection"; //
$NON-NLS-1$
- private static final String CONTENT_TYPE = "content-type"; // $NON-NLS-1$
- private static final String CONTENT_LENGTH = "content-length"; //
$NON-NLS-1$
+ public static final String CONTENT_TYPE = "content-type"; // $NON-NLS-1$
+ public static final String CONTENT_LENGTH = "content-length"; //
$NON-NLS-1$
- /** Filetype to be used for the temporary binary files*/
- private static final String binaryFileSuffix =
- JMeterUtils.getPropDefault("proxy.binary.filesuffix",// $NON-NLS-1$
- ".binary"); // $NON-NLS-1$
-
- /** Which content-types will be treated as binary (exact match) */
- private static final Set<String> binaryContentTypes = new
HashSet<String>();
-
- /** Where to store the temporary binary files */
- private static final String binaryDirectory =
- JMeterUtils.getPropDefault("proxy.binary.directory",// $NON-NLS-1$
- System.getProperty("user.dir")); // $NON-NLS-1$
proxy.binary.filetype=binary
-
- static {
- String binaries = JMeterUtils.getPropDefault("proxy.binary.types", //
$NON-NLS-1$
- "application/x-amf,application/x-java-serialized-object"); //
$NON-NLS-1$
- if (binaries.length() > 0){
- StringTokenizer s = new StringTokenizer(binaries,"|, ");//
$NON-NLS-1$
- while (s.hasMoreTokens()){
- binaryContentTypes.add(s.nextToken());
- }
- }
- }
/**
* Http Request method, uppercased, e.g. GET or POST.
@@ -114,14 +81,6 @@ public class HttpRequestHdr {
private HeaderManager headerManager;
- /*
- * Optionally number the requests
- */
- private static final boolean numberRequests =
- JMeterUtils.getPropDefault("proxy.number.requests", false); //
$NON-NLS-1$
-
- private static volatile int requestNumber = 0;// running number
-
public HttpRequestHdr() {
this.httpSamplerName = ""; // $NON-NLS-1$
}
@@ -251,26 +210,7 @@ public class HttpRequestHdr {
return headerManager;
}
- public HTTPSamplerBase getSampler(Map<String, String> pageEncodings,
Map<String, String> formEncodings)
- throws MalformedURLException, IOException {
- // Instantiate the sampler
- HTTPSamplerBase sampler =
HTTPSamplerFactory.newInstance(httpSamplerName);
- sampler.setProperty(TestElement.GUI_CLASS,
HttpTestSampleGui.class.getName());
-
- // Populate the sampler
- populateSampler(sampler, pageEncodings, formEncodings);
-
- // Defaults
- sampler.setFollowRedirects(false);
- sampler.setUseKeepAlive(true);
-
- if (log.isDebugEnabled()) {
- log.debug("getSampler: sampler path = " + sampler.getPath());
- }
- return sampler;
- }
-
- private String getContentType() {
+ public String getContentType() {
Header contentTypeHeader = headers.get(CONTENT_TYPE);
if (contentTypeHeader != null) {
return contentTypeHeader.getValue();
@@ -285,7 +225,7 @@ public class HttpRequestHdr {
return false;
}
- private MultipartUrlConfig getMultipartConfig(String contentType) {
+ public MultipartUrlConfig getMultipartConfig(String contentType) {
if(isMultipart(contentType)) {
// Get the boundary string for the multiparts from the content type
String boundaryString =
contentType.substring(contentType.toLowerCase(java.util.Locale.ENGLISH).indexOf("boundary=")
+ "boundary=".length());
@@ -294,172 +234,6 @@ public class HttpRequestHdr {
return null;
}
- private void populateSampler(
- HTTPSamplerBase sampler,
- Map<String, String> pageEncodings, Map<String, String>
formEncodings)
- throws MalformedURLException, UnsupportedEncodingException {
- sampler.setDomain(serverName());
- if (log.isDebugEnabled()) {
- log.debug("Proxy: setting server: " + sampler.getDomain());
- }
- sampler.setMethod(method);
- log.debug("Proxy: setting method: " + sampler.getMethod());
- sampler.setPort(serverPort());
- if (log.isDebugEnabled()) {
- log.debug("Proxy: setting port: " + sampler.getPort());
- }
- if (url.indexOf("//") > -1) {
- String protocol = url.substring(0, url.indexOf(":"));
- if (log.isDebugEnabled()) {
- log.debug("Proxy: setting protocol to : " + protocol);
- }
- sampler.setProtocol(protocol);
- } else if (sampler.getPort() == HTTPConstants.DEFAULT_HTTPS_PORT) {
- sampler.setProtocol(HTTPS);
- if (log.isDebugEnabled()) {
- log.debug("Proxy: setting protocol to https");
- }
- } else {
- if (log.isDebugEnabled()) {
- log.debug("Proxy setting default protocol to: http");
- }
- sampler.setProtocol(HTTP);
- }
-
- URL pageUrl = null;
- if(sampler.isProtocolDefaultPort()) {
- pageUrl = new URL(sampler.getProtocol(), sampler.getDomain(),
getPath());
- }
- else {
- pageUrl = new URL(sampler.getProtocol(), sampler.getDomain(),
sampler.getPort(), getPath());
- }
- String urlWithoutQuery = getUrlWithoutQuery(pageUrl);
-
-
- // Check if the request itself tells us what the encoding is
- String contentEncoding = null;
- String requestContentEncoding =
ConversionUtils.getEncodingFromContentType(getContentType());
- if(requestContentEncoding != null) {
- contentEncoding = requestContentEncoding;
- }
- else {
- // Check if we know the encoding of the page
- if (pageEncodings != null) {
- synchronized (pageEncodings) {
- contentEncoding = pageEncodings.get(urlWithoutQuery);
- }
- }
- // Check if we know the encoding of the form
- if (formEncodings != null) {
- synchronized (formEncodings) {
- String formEncoding = formEncodings.get(urlWithoutQuery);
- // Form encoding has priority over page encoding
- if (formEncoding != null) {
- contentEncoding = formEncoding;
- }
- }
- }
- }
-
- // Get the post data using the content encoding of the request
- String postData = null;
- if (log.isDebugEnabled()) {
- if(contentEncoding != null) {
- log.debug("Using encoding " + contentEncoding + " for request
body");
- }
- else {
- log.debug("No encoding found, using JRE default encoding for
request body");
- }
- }
- if (contentEncoding != null) {
- postData = new String(rawPostData, contentEncoding);
- } else {
- // Use default encoding
- postData = new String(rawPostData);
- }
-
- if(contentEncoding != null) {
- sampler.setPath(getPath(), contentEncoding);
- }
- else {
- // Although the spec says UTF-8 should be used for encoding URL
parameters,
- // most browser use ISO-8859-1 for default if encoding is not
known.
- // We use null for contentEncoding, then the url parameters will
be added
- // with the value in the URL, and the "encode?" flag set to false
- sampler.setPath(getPath(), null);
- }
- if (log.isDebugEnabled()) {
- log.debug("Proxy: setting path: " + sampler.getPath());
- }
- if (!HTTPConstants.CONNECT.equals(getMethod()) && numberRequests) {
- requestNumber++;
- sampler.setName(requestNumber + " " + sampler.getPath());
- } else {
- sampler.setName(sampler.getPath());
- }
-
- // Set the content encoding
- if(contentEncoding != null) {
- sampler.setContentEncoding(contentEncoding);
- }
-
- // If it was a HTTP GET request, then all parameters in the URL
- // has been handled by the sampler.setPath above, so we just need
- // to do parse the rest of the request if it is not a GET request
- if((!HTTPConstants.CONNECT.equals(getMethod())) &&
(!HTTPConstants.GET.equals(method))) {
- // Check if it was a multipart http post request
- final String contentType = getContentType();
- MultipartUrlConfig urlConfig = getMultipartConfig(contentType);
- if (urlConfig != null) {
- urlConfig.parseArguments(postData);
- // Tell the sampler to do a multipart post
- sampler.setDoMultipartPost(true);
- // Remove the header for content-type and content-length, since
- // those values will most likely be incorrect when the sampler
- // performs the multipart request, because the boundary string
- // will change
- getHeaderManager().removeHeaderNamed(CONTENT_TYPE);
- getHeaderManager().removeHeaderNamed(CONTENT_LENGTH);
-
- // Set the form data
- sampler.setArguments(urlConfig.getArguments());
- // Set the file uploads
- sampler.setHTTPFiles(urlConfig.getHTTPFileArgs().asArray());
- // used when postData is pure xml (eg. an xml-rpc call) or for PUT
- } else if (postData.trim().startsWith("<?") ||
"PUT".equals(sampler.getMethod())) {
- sampler.addNonEncodedArgument("", postData, "");
- } else if (contentType == null ||
contentType.startsWith(HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED) ){
- // It is the most common post request, with parameter name and
values
- // We also assume this if no content type is present, to be
most backwards compatible,
- // but maybe we should only parse arguments if the content
type is as expected
- sampler.parseArguments(postData.trim(), contentEncoding);
//standard name=value postData
- } else if (postData.length() > 0) {
- if (isBinaryContent(contentType)) {
- try {
- File tempDir = new File(binaryDirectory);
- File out = File.createTempFile(method,
binaryFileSuffix, tempDir);
- FileUtils.writeByteArrayToFile(out,rawPostData);
- HTTPFileArg [] files = {new
HTTPFileArg(out.getPath(),"",contentType)};
- sampler.setHTTPFiles(files);
- } catch (IOException e) {
- log.warn("Could not create binary file: "+e);
- }
- } else {
- // Just put the whole postbody as the value of a parameter
- sampler.addNonEncodedArgument("", postData, ""); //used
when postData is pure xml (ex. an xml-rpc call)
- }
- }
- }
- if (log.isDebugEnabled()) {
- log.debug("sampler path = " + sampler.getPath());
- }
- }
-
- private boolean isBinaryContent(String contentType) {
- if (contentType == null) return false;
- return binaryContentTypes.contains(contentType);
- }
-
//
// Parsing Methods
//
@@ -469,7 +243,7 @@ public class HttpRequestHdr {
*
* @return server's internet name
*/
- private String serverName() {
+ public String serverName() {
// chop to "server.name:x/thing"
String str = url;
int i = str.indexOf("//"); // $NON-NLS-1$
@@ -500,7 +274,7 @@ public class HttpRequestHdr {
*
* @return server's port (or UNSPECIFIED if not found)
*/
- private int serverPort() {
+ public int serverPort() {
String str = url;
// chop to "server.name:x/thing"
int i = str.indexOf("//");
@@ -525,7 +299,7 @@ public class HttpRequestHdr {
*
* @return the path
*/
- private String getPath() {
+ public String getPath() {
String str = url;
int i = str.indexOf("//");
if (i > 0) {
@@ -589,7 +363,7 @@ public class HttpRequestHdr {
// return strBuff.toString();
// }
- private String getUrlWithoutQuery(URL _url) {
+ public String getUrlWithoutQuery(URL _url) {
String fullUrl = _url.toString();
String urlWithoutQuery = fullUrl;
String query = _url.getQuery();
@@ -599,4 +373,42 @@ public class HttpRequestHdr {
}
return urlWithoutQuery;
}
+
+ /**
+ * @return the httpSamplerName
+ */
+ public String getHttpSamplerName() {
+ return httpSamplerName;
+ }
+
+ /**
+ * @return byte[] Raw post data
+ */
+ public byte[] getRawPostData() {
+ return rawPostData;
+ }
+
+ /**
+ * @param sampler {@link HTTPSamplerBase}
+ * @return String Protocol (http or https)
+ */
+ public String getProtocol(HTTPSamplerBase sampler) {
+ if (url.indexOf("//") > -1) {
+ String protocol = url.substring(0, url.indexOf(":"));
+ if (log.isDebugEnabled()) {
+ log.debug("Proxy: setting protocol to : " + protocol);
+ }
+ return protocol;
+ } else if (sampler.getPort() == HTTPConstants.DEFAULT_HTTPS_PORT) {
+ if (log.isDebugEnabled()) {
+ log.debug("Proxy: setting protocol to https");
+ }
+ return HTTPS;
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Proxy setting default protocol to: http");
+ }
+ return HTTP;
+ }
+ }
}
Modified:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/Proxy.java
URL:
http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/Proxy.java?rev=1296512&r1=1296511&r2=1296512&view=diff
==============================================================================
---
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/Proxy.java
(original)
+++
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/Proxy.java
Fri Mar 2 23:37:26 2012
@@ -109,6 +109,8 @@ public class Proxy extends Thread {
private static final char[] KEY_PASSWORD =
JMeterUtils.getPropDefault("proxy.cert.keypassword","password").toCharArray();
// $NON-NLS-1$ $NON-NLS-2$
+ private static final SamplerCreatorFactory factory = new
SamplerCreatorFactory();
+
// Use with SSL connection
private OutputStream outStreamClient = null;
@@ -202,10 +204,10 @@ public class Proxy extends Thread {
request.parse(new
BufferedInputStream(clientSocket.getInputStream()));
}
- // Populate the sampler. It is the same sampler as we sent into
- // the constructor of the HttpRequestHdr instance above
- sampler = request.getSampler(pageEncodings, formEncodings);
-
+ SamplerCreator samplerCreator = factory.getSamplerCreator(request,
pageEncodings, formEncodings);
+ sampler = samplerCreator.createSampler(request, pageEncodings,
formEncodings);
+ samplerCreator.populateSampler(sampler, request, pageEncodings,
formEncodings);
+
/*
* Create a Header Manager to ensure that the browsers headers are
* captured and sent to the server
Added:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreator.java
URL:
http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreator.java?rev=1296512&view=auto
==============================================================================
---
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreator.java
(added)
+++
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreator.java
Fri Mar 2 23:37:26 2012
@@ -0,0 +1,57 @@
+/*
+ * 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.proxy;
+
+import java.util.Map;
+
+import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
+
+/**
+ * Factory of sampler
+ */
+public interface SamplerCreator {
+
+ /**
+ * @return String[] array of Content types managed by Factory
+ */
+ public String[] getManagedContentTypes();
+
+ /**
+ * Create HTTPSamplerBase
+ * @param request {@link HttpRequestHdr}
+ * @param pageEncodings Map<String, String>
+ * @param formEncodings Map<String, String>
+ * @return {@link HTTPSamplerBase}
+ */
+ public HTTPSamplerBase createSampler(HttpRequestHdr request,
+ Map<String, String> pageEncodings, Map<String, String>
formEncodings);
+
+ /**
+ * Populate sampler from request
+ * @param sampler {@link HTTPSamplerBase}
+ * @param request {@link HttpRequestHdr}
+ * @param pageEncodings Map<String, String>
+ * @param formEncodings Map<String, String>
+ * @throws Exception
+ */
+ public void populateSampler(HTTPSamplerBase sampler,
+ HttpRequestHdr request, Map<String, String> pageEncodings,
+ Map<String, String> formEncodings)
+ throws Exception;
+}
Propchange:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreator.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreatorFactory.java
URL:
http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreatorFactory.java?rev=1296512&view=auto
==============================================================================
---
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreatorFactory.java
(added)
+++
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreatorFactory.java
Fri Mar 2 23:37:26 2012
@@ -0,0 +1,95 @@
+/*
+ * 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.proxy;
+
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.jmeter.util.JMeterUtils;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.jorphan.reflect.ClassFinder;
+import org.apache.log.Logger;
+
+/**
+ * {@link SamplerCreator} factory
+ */
+public class SamplerCreatorFactory {
+ private static final Logger log = LoggingManager.getLoggerForClass();
+
+ private static final SamplerCreator DEFAULT_SAMPLER_CREATOR = new
DefaultSamplerCreator();
+
+ private Map<String, SamplerCreator> samplerCreatorMap = new
HashMap<String, SamplerCreator>();
+
+ /**
+ *
+ */
+ public SamplerCreatorFactory() {
+ init();
+ }
+
+ /**
+ * Initialize factory from classpath
+ */
+ private void init() {
+ try {
+ List<String> listClasses = ClassFinder.findClassesThatExtend(
+ JMeterUtils.getSearchPaths(),
+ new Class[] {SamplerCreator.class });
+ for (String strClassName : listClasses) {
+ try {
+ log.info("Loading class:"+ strClassName);
+ Class<?> commandClass = Class.forName(strClassName);
+ if (!Modifier.isAbstract(commandClass.getModifiers())) {
+ log.info("Instantiating :"+
commandClass.getName());
+ SamplerCreator creator = (SamplerCreator)
commandClass.newInstance();
+ String[] contentTypes =
creator.getManagedContentTypes();
+ for (String contentType : contentTypes) {
+ if(log.isInfoEnabled()) {
+ log.info("Registering samplerCreator
"+commandClass.getName()+" for content type:"+contentType);
+ }
+ samplerCreatorMap.put(contentType, creator);
+ }
+ }
+ } catch (Exception e) {
+ log.error("Exception registering
"+SamplerCreator.class.getName() + " with implementation:"+strClassName, e);
+ }
+ }
+ } catch (Exception e) {
+ log.error("Exception finding implementations of
"+SamplerCreator.class, e);
+ }
+ }
+
+ /**
+ * Gets {@link SamplerCreator} for content type, if none is found returns
{@link DefaultSamplerCreator}
+ * @param request {@link HttpRequestHdr}
+ * @param pageEncodings Map<String, String> pageEncodings
+ * @param formEncodings Map<String, String> formEncodings
+ * @return SamplerCreator
+ */
+ public SamplerCreator getSamplerCreator(HttpRequestHdr request,
+ Map<String, String> pageEncodings, Map<String, String>
formEncodings) {
+ SamplerCreator creator =
samplerCreatorMap.get(request.getContentType());
+ if(creator == null) {
+ return DEFAULT_SAMPLER_CREATOR;
+ }
+ return creator;
+ }
+}
\ No newline at end of file
Propchange:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreatorFactory.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: jmeter/trunk/xdocs/changes.xml
URL:
http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1296512&r1=1296511&r2=1296512&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml (original)
+++ jmeter/trunk/xdocs/changes.xml Fri Mar 2 23:37:26 2012
@@ -156,6 +156,7 @@ When doing replacement of User Defined V
<li>Bug 45839 - Test Action : Allow premature exit from a loop</li>
<li>Bug 52614 - MailerModel.sendMail has strange way to calculate debug
setting</li>
<li>Bug 52782 - Add a detail button on parameters table to show detail of a
Row</li>
+<li>Bug 52674 - Proxy : Add a Sampler Creator to allow plugging HTTP based
samplers using potentially non textual POST Body (AMF, Silverlight...) and
customizing them for others</li>
</ul>
<h2>Non-functional changes</h2>