You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jmeter-dev@jakarta.apache.org by se...@apache.org on 2006/05/21 18:51:57 UTC
svn commit: r408188 - in
/jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http:
control/gui/AjpSamplerGui.java sampler/AjpSampler.java
Author: sebb
Date: Sun May 21 09:51:56 2006
New Revision: 408188
URL: http://svn.apache.org/viewvc?rev=408188&view=rev
Log:
Add AjpSampler (bug 37652)
Added:
jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/AjpSamplerGui.java (with props)
jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/sampler/AjpSampler.java (with props)
Added: jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/AjpSamplerGui.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/AjpSamplerGui.java?rev=408188&view=auto
==============================================================================
--- jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/AjpSamplerGui.java (added)
+++ jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/AjpSamplerGui.java Sun May 21 09:51:56 2006
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.control.gui;
+
+import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
+import org.apache.jmeter.protocol.http.sampler.AjpSampler;
+import org.apache.jmeter.testelement.TestElement;
+
+public class AjpSamplerGui extends HttpTestSampleGui {
+
+ public AjpSamplerGui() {
+ super();
+ }
+
+ public TestElement createTestElement() {
+ AjpSampler sampler = new AjpSampler();
+ modifyTestElement(sampler);
+ return sampler;
+ }
+
+ public String getStaticLabel() {
+ return "AJP/1.3 Sampler"; //$NON-NLS-1$
+ }
+
+ public String getDocAnchor() {// reuse documentation
+ return super.getStaticLabel().replace(' ', '_'); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+}
Propchange: jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/AjpSamplerGui.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/AjpSamplerGui.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision
Propchange: jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/AjpSamplerGui.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/sampler/AjpSampler.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/sampler/AjpSampler.java?rev=408188&view=auto
==============================================================================
--- jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/sampler/AjpSampler.java (added)
+++ jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/sampler/AjpSampler.java Sun May 21 09:51:56 2006
@@ -0,0 +1,492 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.URL;
+
+import org.apache.jmeter.protocol.http.control.AuthManager;
+import org.apache.jmeter.protocol.http.control.CookieManager;
+import org.apache.jmeter.protocol.http.control.Header;
+import org.apache.jmeter.protocol.http.control.HeaderManager;
+import org.apache.jmeter.testelement.property.CollectionProperty;
+import org.apache.jmeter.testelement.property.JMeterProperty;
+import org.apache.jmeter.testelement.property.PropertyIterator;
+import org.apache.jmeter.util.JMeterUtils;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+/**
+ * Selector for the AJP/1.3 protocol
+ * (i.e. what Tomcat uses with mod_jk)
+ * It allows you to test Tomcat in AJP mode without
+ * actually having Apache installed and configured
+ *
+ */
+public class AjpSampler extends HTTPSamplerBase {
+
+ private static final Logger log= LoggingManager.getLoggerForClass();
+
+ private static final char NEWLINE = '\n';
+ private static final String COLON_SPACE = ": ";//$NON-NLS-1$
+ private static final String APPLICATION_X_WWW_FORM_URLENCODED =
+ "application/x-www-form-urlencoded";//$NON-NLS-1$
+
+ /**
+ * Translates integer codes to request header names
+ */
+ public static final String []headerTransArray = {
+ "accept", //$NON-NLS-1$
+ "accept-charset", //$NON-NLS-1$
+ "accept-encoding", //$NON-NLS-1$
+ "accept-language", //$NON-NLS-1$
+ "authorization", //$NON-NLS-1$
+ "connection", //$NON-NLS-1$
+ "content-type", //$NON-NLS-1$
+ "content-length", //$NON-NLS-1$
+ "cookie", //$NON-NLS-1$
+ "cookie2", //$NON-NLS-1$
+ "host", //$NON-NLS-1$
+ "pragma", //$NON-NLS-1$
+ "referer", //$NON-NLS-1$
+ "user-agent" //$NON-NLS-1$
+ };
+
+ /**
+ * Base value for translated headers
+ */
+ static final int AJP_HEADER_BASE = 0xA000;
+
+ static final int MAX_SEND_SIZE = 8*1024 - 4 - 4;
+
+ private Socket channel = null;
+ private int lastPort = -1;
+ private String lastHost = null;
+ private String localName = null;
+ private String localAddress = null;
+ private byte [] inbuf = new byte[8*1024];
+ private byte [] outbuf = new byte[8*1024];
+ private transient ByteArrayOutputStream responseData = new ByteArrayOutputStream();
+ private int inpos = 0;
+ private int outpos = 0;
+ private InputStream body = null;
+
+ public AjpSampler() {
+ }
+
+ protected HTTPSampleResult sample(URL url,
+ String method,
+ boolean frd,
+ int fd) {
+ HTTPSampleResult res = new HTTPSampleResult();
+ res.setMonitor(false);
+ res.setSampleLabel(url.toExternalForm());
+ res.sampleStart();
+ try {
+ setupConnection(url, method, res);
+ execute(method, res);
+ res.sampleEnd();
+ res.setResponseData(responseData.toByteArray());
+ return res;
+ } catch(IOException iex) {
+ res.sampleEnd();
+ HTTPSampleResult err = errorResult(iex, res);
+ lastPort = -1; // force reopen on next sample
+ channel = null;
+ return err;
+ }
+ }
+
+ public void threadFinished() {
+ if(channel != null) {
+ try {
+ channel.close();
+ } catch(IOException iex) {
+ log.debug("Error closing channel",iex);
+ }
+ }
+ channel = null;
+ body = null;
+ }
+
+ private void setupConnection(URL url,
+ String method,
+ HTTPSampleResult res) throws IOException {
+
+ String host = url.getHost();
+ int port = url.getPort();
+ if(port <= 0 || port == url.getDefaultPort()) {
+ port = 8009;
+ }
+ String scheme = url.getProtocol();
+ if(channel == null || !host.equals(lastHost) || port != lastPort) {
+ if(channel != null) {
+ channel.close();
+ }
+ channel = new Socket(host, port);
+ int timeout = JMeterUtils.getPropDefault("httpclient.timeout",0);//$NON-NLS-1$
+ if(timeout > 0) {
+ channel.setSoTimeout(timeout);
+ }
+ localAddress = channel.getLocalAddress().getHostAddress();
+ localName = channel.getLocalAddress().getHostName();
+ lastHost = host;
+ lastPort = port;
+ }
+ res.setURL(url);
+ res.setHTTPMethod(method);
+ outpos = 4;
+ setByte((byte)2);
+ if(method.equals(POST))
+ setByte((byte)4);
+ else
+ setByte((byte)2);
+ if(JMeterUtils.getPropDefault("httpclient.version","1.1").equals("1.0")) {//$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+ setString("HTTP/1.0");//$NON-NLS-1$
+ } else {
+ setString(HTTP_1_1);
+ }
+ setString(url.getFile());
+ setString(localAddress);
+ setString(localName);
+ setString(host);
+ setInt(url.getDefaultPort());
+ setByte(PROTOCOL_HTTPS.equalsIgnoreCase(scheme) ? (byte)1 : (byte)0);
+ setInt(getHeaderSize(method, url));
+ String hdr = setConnectionHeaders(url, host, method);
+ res.setRequestHeaders(hdr);
+ setConnectionCookies(url, getCookieManager());
+ setByte((byte)0xff); // Attributes not supported
+ }
+
+ private int getHeaderSize(String method, URL url) {
+ HeaderManager headers = getHeaderManager();
+ CookieManager cookies = getCookieManager();
+ AuthManager auth = getAuthManager();
+ int hsz = 1; // Host always
+ if(method.equals(POST)) {
+ String fn = getFilename();
+ if(fn != null && fn.trim().length() > 0) {
+ hsz += 3;
+ } else {
+ hsz += 2;
+ }
+ }
+ if(headers != null) {
+ hsz += headers.size();
+ }
+ if(cookies != null) {
+ hsz += cookies.getCookieCount();
+ }
+ if(auth != null) {
+ String authHeader = auth.getAuthHeaderForURL(url);
+ if(authHeader != null) {
+ ++hsz;
+ }
+ }
+ return hsz;
+ }
+
+
+ private String setConnectionHeaders(URL url, String host, String method)
+ throws IOException {
+ HeaderManager headers = getHeaderManager();
+ AuthManager auth = getAuthManager();
+ StringBuffer hbuf = new StringBuffer();
+ // Allow Headers to override Host setting
+ hbuf.append("Host").append(COLON_SPACE).append(host).append(NEWLINE);//$NON-NLS-1$
+ setInt(0xA00b); //Host
+ setString(host);
+ if(headers != null) {
+ CollectionProperty coll = headers.getHeaders();
+ PropertyIterator i = coll.iterator();
+ while(i.hasNext()) {
+ Header header = (Header)i.next().getObjectValue();
+ String n = header.getName();
+ String v = header.getValue();
+ hbuf.append(n).append(COLON_SPACE).append(v).append(NEWLINE);
+ int hc = translateHeader(n);
+ if(hc > 0) {
+ setInt(hc+AJP_HEADER_BASE);
+ } else {
+ setString(n);
+ }
+ setString(v);
+ }
+ }
+ if(method.equals(POST)) {
+ int cl = -1;
+ String fn = getFilename();
+ if(fn != null && fn.trim().length() > 0) {
+ File input = new File(fn);
+ cl = (int)input.length();
+ body = new FileInputStream(input);
+ setString(HEADER_CONTENT_DISPOSITION);
+ setString("form-data; name=\""+encode(getFileField())+
+ "\"; filename=\"" + encode(fn) +"\""); //$NON-NLS-1$ //$NON-NLS-2$
+ String mt = getMimetype();
+ hbuf.append(HEADER_CONTENT_TYPE).append(COLON_SPACE).append(mt).append(NEWLINE);
+ setInt(0xA007); // content-type
+ setString(mt);
+ } else {
+ hbuf.append(HEADER_CONTENT_TYPE).append(COLON_SPACE).append(APPLICATION_X_WWW_FORM_URLENCODED).append(NEWLINE);
+ setInt(0xA007); // content-type
+ setString(APPLICATION_X_WWW_FORM_URLENCODED);
+ StringBuffer sb = new StringBuffer();
+ boolean first = true;
+ PropertyIterator args = getArguments().iterator();
+ while(args.hasNext()) {
+ JMeterProperty arg = args.next();
+ if(first) {
+ first = false;
+ } else {
+ sb.append('&');
+ }
+ sb.append(arg.getName()).append('=').append(arg.getStringValue());
+ }
+ byte [] sbody = sb.toString().getBytes(); //FIXME - encoding
+ cl = sbody.length;
+ body = new ByteArrayInputStream(sbody);
+ }
+ hbuf.append(HEADER_CONTENT_LENGTH).append(COLON_SPACE).append(String.valueOf(cl)).append(NEWLINE);
+ setInt(0xA008); // Content-length
+ setString(String.valueOf(cl));
+ }
+ if(auth != null) {
+ String authHeader = auth.getAuthHeaderForURL(url);
+ if(authHeader != null) {
+ setInt(0xA005); // Authorization
+ setString(authHeader);
+ hbuf.append(HEADER_AUTHORIZATION).append(COLON_SPACE).append(authHeader).append(NEWLINE);
+ }
+ }
+ return hbuf.toString();
+ }
+
+ private String encode(String value) {
+ StringBuffer newValue = new StringBuffer();
+ char[] chars = value.toCharArray();
+ for (int i = 0; i < chars.length; i++)
+ {
+ if (chars[i] == '\\')//$NON-NLS-1$
+ {
+ newValue.append("\\\\");//$NON-NLS-1$
+ }
+ else
+ {
+ newValue.append(chars[i]);
+ }
+ }
+ return newValue.toString();
+ }
+
+ private void setConnectionCookies(URL url, CookieManager cookies) {
+ if(cookies != null) {
+ CollectionProperty coll = cookies.getCookies();
+ PropertyIterator i = coll.iterator();
+ while(i.hasNext()) {
+ JMeterProperty header = i.next();
+ setInt(0xA009); // Cookie
+ setString(header.getName()+"="+header.getStringValue());//$NON-NLS-1$
+ }
+ }
+ }
+
+ private int translateHeader(String n) {
+ for(int i=0; i < headerTransArray.length; i++) {
+ if(headerTransArray[i].equalsIgnoreCase(n)) {
+ return i+1;
+ }
+ }
+ return -1;
+ }
+
+ private void setByte(byte b) {
+ outbuf[outpos++] = b;
+ }
+
+ private void setInt(int n) {
+ outbuf[outpos++] = (byte)((n >> 8)&0xff);
+ outbuf[outpos++] = (byte) (n&0xff);
+ }
+
+ private void setString(String s) {
+ if( s == null ) {
+ setInt(0xFFFF);
+ } else {
+ int len = s.length();
+ setInt(len);
+ for(int i=0; i < len; i++) {
+ setByte((byte)s.charAt(i));
+ }
+ setByte((byte)0);
+ }
+ }
+
+ private void send() throws IOException {
+ OutputStream os = channel.getOutputStream();
+ int len = outpos;
+ outpos = 0;
+ setInt(0x1234);
+ setInt(len-4);
+ os.write(outbuf, 0, len);
+ }
+
+ private void execute(String method, HTTPSampleResult res)
+ throws IOException {
+ send();
+ if(method.equals(POST)) {
+ sendPostBody();
+ }
+ handshake(res);
+ }
+
+ private void handshake(HTTPSampleResult res) throws IOException {
+ responseData.reset();
+ int msg = getMessage();
+ while(msg != 5) {
+ if(msg == 3) {
+ int len = getInt();
+ responseData.write(inbuf, inpos, len);
+ } else if(msg == 4) {
+ parseHeaders(res);
+ } else if(msg == 6) {
+ setNextBodyChunk();
+ send();
+ }
+ msg = getMessage();
+ }
+ }
+
+
+ private void sendPostBody() throws IOException {
+ setNextBodyChunk();
+ send();
+ }
+
+ private void setNextBodyChunk() throws IOException {
+ int len = body.available();
+ if(len < 0) {
+ len = 0;
+ } else if(len > MAX_SEND_SIZE) {
+ len = MAX_SEND_SIZE;
+ }
+ outpos = 4;
+ int nr = 0;
+ if(len > 0) {
+ nr = body.read(outbuf, outpos+2, len);
+ }
+ setInt(nr);
+ outpos += nr;
+ }
+
+
+ private void parseHeaders(HTTPSampleResult res)
+ throws IOException {
+ int status = getInt();
+ res.setResponseCode(Integer.toString(status));
+ res.setSuccessful(200 <= status && status <= 399);
+ String msg = getString();
+ res.setResponseMessage(msg);
+ int nh = getInt();
+ StringBuffer sb = new StringBuffer();
+ sb.append(HTTP_1_1 ).append(status).append(" ").append(msg).append(NEWLINE);//$NON-NLS-1$//$NON-NLS-2$
+ for(int i=0; i < nh; i++) {
+ // Currently, no Tomcat version sends translated headers
+ String name;
+ int thn = peekInt();
+ if((thn & 0xff00) == AJP_HEADER_BASE) {
+ name = headerTransArray[(thn&0xff)-1];
+ } else {
+ name = getString();
+ }
+ String value = getString();
+ if(HEADER_CONTENT_TYPE.equalsIgnoreCase(name)) {
+ res.setContentType(value);
+ String de = value.toLowerCase();
+ int cset = de.indexOf("charset=");//$NON-NLS-1$
+ if(cset >= 0) {
+ res.setDataEncoding(de.substring(cset+8));
+ }
+ if(de.startsWith("text/")) {//$NON-NLS-1$
+ res.setDataType(HTTPSampleResult.TEXT);
+ } else {
+ res.setDataType(HTTPSampleResult.BINARY);
+ }
+ } else if(HEADER_SET_COOKIE.equalsIgnoreCase(name)) {
+ CookieManager cookies = getCookieManager();
+ if(cookies != null) {
+ cookies.addCookieFromHeader(value, res.getURL());
+ }
+ }
+ sb.append(name).append(COLON_SPACE).append(value).append(NEWLINE);
+ }
+ res.setResponseHeaders(sb.toString());
+ }
+
+
+ private int getMessage() throws IOException {
+ InputStream is = channel.getInputStream();
+ inpos = 0;
+ int nr = is.read(inbuf, inpos, 4);
+ if(nr != 4) {
+ channel.close();
+ channel = null;
+ throw new IOException("Connection Closed: "+nr);
+ }
+ //int mark =
+ getInt();
+ int len = getInt();
+ int toRead = len;
+ int cpos = inpos;
+ while(toRead > 0) {
+ nr = is.read(inbuf, cpos, toRead);
+ cpos += nr;
+ toRead -= nr;
+ }
+ return getByte();
+ }
+
+ private byte getByte() {
+ return inbuf[inpos++];
+ }
+
+ private int getInt() {
+ int res = (inbuf[inpos++]<<8)&0xff00;
+ res += inbuf[inpos++]&0xff;
+ return res;
+ }
+
+ private int peekInt() {
+ int res = (inbuf[inpos]<<8)&0xff00;
+ res += inbuf[inpos+1]&0xff;
+ return res;
+ }
+
+ private String getString() throws IOException {
+ int len = getInt();
+ String s = new String(inbuf, inpos, len, "iso-8859-1");//$NON-NLS-1$
+ inpos+= len+1;
+ return s;
+ }
+}
\ No newline at end of file
Propchange: jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/sampler/AjpSampler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/sampler/AjpSampler.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision
Propchange: jakarta/jmeter/branches/rel-2-1/src/protocol/http/org/apache/jmeter/protocol/http/sampler/AjpSampler.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
---------------------------------------------------------------------
To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org