/*
* 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.modifier;
import java.io.Serializable;
import org.apache.jmeter.processor.PreProcessor;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
import org.apache.jmeter.protocol.http.util.HTTPArgument;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.Sampler;
import org.apache.jmeter.testelement.AbstractTestElement;
import org.apache.jmeter.testelement.property.BooleanProperty;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.oro.text.regex.MatchResult;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Perl5Matcher;
//For unit tests, @see TestURLRewritingModifier
public class URLRewritingModifier extends AbstractTestElement implements Serializable, PreProcessor {
private static final long serialVersionUID = 233L;
private static final String SEMI_COLON = ";"; // $NON-NLS-1$
private transient Pattern pathExtensionEqualsQuestionmarkRegexp;
private transient Pattern pathExtensionEqualsNoQuestionmarkRegexp;
private transient Pattern parameterRegexp;
private transient Pattern pathExtensionNoEqualsQuestionmarkRegexp;
private transient Pattern pathExtensionNoEqualsNoQuestionmarkRegexp;
// transient Perl5Compiler compiler = new Perl5Compiler();
private final static String ARGUMENT_NAME = "argument_name"; // $NON-NLS-1$
private final static String PATH_EXTENSION = "path_extension"; // $NON-NLS-1$
private final static String PATH_EXTENSION_NO_EQUALS = "path_extension_no_equals"; // $NON-NLS-1$
private final static String PATH_EXTENSION_NO_QUESTIONMARK = "path_extension_no_questionmark"; // $NON-NLS-1$
private final static String SHOULD_CACHE = "cache_value"; // $NON-NLS-1$
// PreProcessors are cloned per-thread, so this will be saved per-thread
private transient String savedValue = ""; // $NON-NLS-1$
public void process() {
JMeterContext ctx = getThreadContext();
Sampler sampler = ctx.getCurrentSampler();
if (!(sampler instanceof HTTPSamplerBase)) {// Ignore non-HTTP samplers
return;
}
SampleResult responseText = ctx.getPreviousResult();
if (responseText == null) {
return;
}
initRegex(getArgumentName());
String text = new String(responseText.getResponseData());
Perl5Matcher matcher = JMeterUtils.getMatcher();
String value = "";
if (isPathExtension() && isPathExtensionNoEquals() && isPathExtensionNoQuestionmark()) {
if (matcher.contains(text, pathExtensionNoEqualsNoQuestionmarkRegexp)) {
MatchResult result = matcher.getMatch();
value = result.group(1);
}
} else if (isPathExtension() && isPathExtensionNoEquals()) // && !
// isPathExtensionNoQuestionmark
{
if (matcher.contains(text, pathExtensionNoEqualsQuestionmarkRegexp)) {
MatchResult result = matcher.getMatch();
value = result.group(1);
}
} else if (isPathExtension() && isPathExtensionNoQuestionmark()) // && !
// isPathExtensionNoEquals
{
if (matcher.contains(text, pathExtensionEqualsNoQuestionmarkRegexp)) {
MatchResult result = matcher.getMatch();
value = result.group(1);
}
} else if (isPathExtension()) // && ! isPathExtensionNoEquals && !
// isPathExtensionNoQuestionmark
{
if (matcher.contains(text, pathExtensionEqualsQuestionmarkRegexp)) {
MatchResult result = matcher.getMatch();
value = result.group(1);
}
} else // if ! isPathExtension()
{
if (matcher.contains(text, parameterRegexp)) {
MatchResult result = matcher.getMatch();
for (int i = 1; i < result.groups(); i++) {
value = result.group(i);
if (value != null) {
break;
}
}
}
}
// Bug 15025 - save session value across samplers
if (shouldCache()){
if (value == null || value.length() == 0) {
value = savedValue;
} else {
savedValue = value;
}
}
modify((HTTPSamplerBase) sampler, value);
}
private void modify(HTTPSamplerBase sampler, String value) {
if (isPathExtension()) {
if (isPathExtensionNoEquals()) {
sampler.setPath(sampler.getPath() + SEMI_COLON + getArgumentName() + value); // $NON-NLS-1$
} else {
sampler.setPath(sampler.getPath() + SEMI_COLON + getArgumentName() + "=" + value); // $NON-NLS-1$ // $NON-NLS-2$
}
} else {
sampler.getArguments().removeArgument(getArgumentName());
sampler.getArguments().addArgument(new HTTPArgument(getArgumentName(), value, true));
}
}
public void setArgumentName(String argName) {
setProperty(ARGUMENT_NAME, argName);
}
private void initRegex(String argName) {
String quotedArg = Perl5Compiler.quotemeta(argName);// Don't get tripped up by RE chars in the arg name
pathExtensionEqualsQuestionmarkRegexp = JMeterUtils.getPatternCache().getPattern(
SEMI_COLON + quotedArg + "=([^\"'>&\\s;]*)[&\\s\"'>;]?$?", // $NON-NLS-1$
Perl5Compiler.MULTILINE_MASK | Perl5Compiler.READ_ONLY_MASK);
pathExtensionEqualsNoQuestionmarkRegexp = JMeterUtils.getPatternCache().getPattern(
SEMI_COLON + quotedArg + "=([^\"'>&\\s;?]*)[&\\s\"'>;?]?$?", // $NON-NLS-1$
Perl5Compiler.MULTILINE_MASK | Perl5Compiler.READ_ONLY_MASK);
pathExtensionNoEqualsQuestionmarkRegexp = JMeterUtils.getPatternCache().getPattern(
SEMI_COLON + quotedArg + "([^\"'>&\\s;]*)[&\\s\"'>;]?$?", // $NON-NLS-1$
Perl5Compiler.MULTILINE_MASK | Perl5Compiler.READ_ONLY_MASK);
pathExtensionNoEqualsNoQuestionmarkRegexp = JMeterUtils.getPatternCache().getPattern(
SEMI_COLON + quotedArg + "([^\"'>&\\s;?]*)[&\\s\"'>;?]?$?", // $NON-NLS-1$
Perl5Compiler.MULTILINE_MASK | Perl5Compiler.READ_ONLY_MASK);
parameterRegexp = JMeterUtils.getPatternCache().getPattern(
// ;sessionid=value
"[;\\?&]" + quotedArg + "=([^\"'>&\\s;\\\\]*)[&\\s\"'>;]?$?" + // $NON-NLS-1$
// name="sessionid" value="value"
"|\\s[Nn][Aa][Mm][Ee]\\s*=\\s*[\"']" + quotedArg
+ "[\"']" + "[^>]*" // $NON-NLS-1$
+ "\\s[vV][Aa][Ll][Uu][Ee]\\s*=\\s*[\"']" // $NON-NLS-1$
+ "([^\"']*)" + "[\"']" // $NON-NLS-1$
// value="value" name="sessionid"
+ "|\\s[vV][Aa][Ll][Uu][Ee]\\s*=\\s*[\"']" // $NON-NLS-1$
+ "([^\"']*)" + "[\"']" + "[^>]*" // $NON-NLS-1$ // $NON-NLS-2$ // $NON-NLS-3$
+ "\\s[Nn][Aa][Mm][Ee]\\s*=\\s*[\"']" // $NON-NLS-1$
+ quotedArg + "[\"']", // $NON-NLS-1$
Perl5Compiler.MULTILINE_MASK | Perl5Compiler.READ_ONLY_MASK);
// NOTE: the handling of simple- vs. double-quotes could be formally
// more accurate, but I can't imagine a session id containing
// either, so we should be OK. The whole set of expressions is a
// quick hack anyway, so who cares.
}
public String getArgumentName() {
return getPropertyAsString(ARGUMENT_NAME);
}
public void setPathExtension(boolean pathExt) {
setProperty(new BooleanProperty(PATH_EXTENSION, pathExt));
}
public void setPathExtensionNoEquals(boolean pathExtNoEquals) {
setProperty(new BooleanProperty(PATH_EXTENSION_NO_EQUALS, pathExtNoEquals));
}
public void setPathExtensionNoQuestionmark(boolean pathExtNoQuestionmark) {
setProperty(new BooleanProperty(PATH_EXTENSION_NO_QUESTIONMARK, pathExtNoQuestionmark));
}
public void setShouldCache(boolean b) {
setProperty(new BooleanProperty(SHOULD_CACHE, b));
}
public boolean isPathExtension() {
return getPropertyAsBoolean(PATH_EXTENSION);
}
public boolean isPathExtensionNoEquals() {
return getPropertyAsBoolean(PATH_EXTENSION_NO_EQUALS);
}
public boolean isPathExtensionNoQuestionmark() {
return getPropertyAsBoolean(PATH_EXTENSION_NO_QUESTIONMARK);
}
public boolean shouldCache() {
return getPropertyAsBoolean(SHOULD_CACHE,true);
}
}