001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.jmeter.protocol.http.sampler;
020:
021: import org.apache.commons.httpclient.HttpClient;
022: import org.apache.commons.httpclient.methods.PostMethod;
023: import org.apache.commons.httpclient.methods.RequestEntity;
024: import org.apache.jmeter.protocol.http.control.Header;
025: import org.apache.jmeter.protocol.http.control.HeaderManager;
026: import org.apache.jorphan.logging.LoggingManager;
027: import org.apache.jorphan.util.JOrphanUtils;
028: import org.apache.log.Logger;
029:
030: import java.io.ByteArrayOutputStream;
031: import java.io.File;
032: import java.io.FileInputStream;
033: import java.io.IOException;
034: import java.io.InputStream;
035: import java.io.OutputStream;
036: import java.io.PrintWriter;
037: import java.net.MalformedURLException;
038: import java.net.URL;
039: import java.util.zip.GZIPInputStream;
040:
041: /**
042: * Commons HTTPClient based soap sampler
043: */
044: public class SoapSampler extends HTTPSampler2 {
045: private static final Logger log = LoggingManager
046: .getLoggerForClass();
047:
048: public static final String XML_DATA = "HTTPSamper.xml_data"; //$NON-NLS-1$
049:
050: public static final String URL_DATA = "SoapSampler.URL_DATA"; //$NON-NLS-1$
051:
052: public static final String SOAP_ACTION = "SoapSampler.SOAP_ACTION"; //$NON-NLS-1$
053:
054: public static final String SEND_SOAP_ACTION = "SoapSampler.SEND_SOAP_ACTION"; //$NON-NLS-1$
055:
056: public static final String XML_DATA_FILE = "SoapSampler.xml_data_file"; //$NON-NLS-1$
057:
058: private static final String DOUBLE_QUOTE = "\""; //$NON-NLS-1$
059:
060: private static final String SOAPACTION = "SOAPAction"; //$NON-NLS-1$
061:
062: public void setXmlData(String data) {
063: setProperty(XML_DATA, data);
064: }
065:
066: public String getXmlData() {
067: return getPropertyAsString(XML_DATA);
068: }
069:
070: /**
071: * it's kinda obvious, but we state it anyways. Set the xml file with a
072: * string path.
073: *
074: * @param filename
075: */
076: public void setXmlFile(String filename) {
077: setProperty(XML_DATA_FILE, filename);
078: }
079:
080: /**
081: * Get the file location of the xml file.
082: *
083: * @return String file path.
084: */
085: public String getXmlFile() {
086: return getPropertyAsString(XML_DATA_FILE);
087: }
088:
089: public String getURLData() {
090: return getPropertyAsString(URL_DATA);
091: }
092:
093: public void setURLData(String url) {
094: setProperty(URL_DATA, url);
095: }
096:
097: public String getSOAPAction() {
098: return getPropertyAsString(SOAP_ACTION);
099: }
100:
101: public String getSOAPActionQuoted() {
102: String action = getSOAPAction();
103: StringBuffer sb = new StringBuffer(action.length() + 2);
104: sb.append(DOUBLE_QUOTE);
105: sb.append(action);
106: sb.append(DOUBLE_QUOTE);
107: return sb.toString();
108: }
109:
110: public void setSOAPAction(String action) {
111: setProperty(SOAP_ACTION, action);
112: }
113:
114: public boolean getSendSOAPAction() {
115: return getPropertyAsBoolean(SEND_SOAP_ACTION);
116: }
117:
118: public void setSendSOAPAction(boolean action) {
119: setProperty(SEND_SOAP_ACTION, String.valueOf(action));
120: }
121:
122: protected int setPostHeaders(PostMethod post) {
123: int length = 0;// Take length from file
124: if (getHeaderManager() != null) {
125: // headerManager was set, so let's set the connection
126: // to use it.
127: HeaderManager mngr = getHeaderManager();
128: int headerSize = mngr.size();
129: for (int idx = 0; idx < headerSize; idx++) {
130: Header hd = mngr.getHeader(idx);
131: if (HEADER_CONTENT_LENGTH
132: .equalsIgnoreCase(hd.getName())) {// Use this to override file length
133: length = Integer.parseInt(hd.getValue());
134: }
135: // All the other headers are set up by HTTPSampler2.setupConnection()
136: }
137: } else {
138: // otherwise we use "text/xml" as the default
139: post.addParameter(HEADER_CONTENT_TYPE, "text/xml"); //$NON-NLS-1$
140: }
141: if (getSendSOAPAction()) {
142: post.setRequestHeader(SOAPACTION, getSOAPActionQuoted());
143: }
144: return length;
145: }
146:
147: /**
148: * Send POST data from <code>Entry</code> to the open connection.
149: *
150: * @param post
151: * @throws IOException if an I/O exception occurs
152: */
153: protected void sendPostData(PostMethod post, final int length) {
154: final String xmlFile = getXmlFile();
155: if (xmlFile != null && getXmlFile().length() > 0) {
156: post.setRequestEntity(new RequestEntity() {
157: public boolean isRepeatable() {
158: return true;
159: }
160:
161: public void writeRequest(OutputStream out)
162: throws IOException {
163: byte[] buf = new byte[1024];
164: // 1k - the previous 100k made no sense (there's tons of buffers
165: // elsewhere in the chain) and it caused OOM when many concurrent
166: // uploads were being done. Could be fixed by increasing the evacuation
167: // ratio in bin/jmeter[.bat], but this is better.
168: int read;
169: InputStream in = new FileInputStream(xmlFile);
170: while ((read = in.read(buf)) > 0) {
171: out.write(buf, 0, read);
172: }
173: in.close();
174: out.flush();
175: }
176:
177: public long getContentLength() {
178: switch (length) {
179: case -1:
180: return -1;
181: case 0: // No header provided
182: return (new File(xmlFile)).length();
183: default:
184: return length;
185: }
186: }
187:
188: public String getContentType() {
189: return "text/xml";
190: }
191: });
192: } else {
193: post.setRequestEntity(new RequestEntity() {
194: public boolean isRepeatable() {
195: return true;
196: }
197:
198: public void writeRequest(OutputStream out)
199: throws IOException {
200: PrintWriter printer = new PrintWriter(out);
201: printer.print(getXmlData());
202: printer.flush();
203: }
204:
205: public long getContentLength() {
206: return getXmlData().getBytes().length;// so we don't generate chunked encoding
207: }
208:
209: public String getContentType() {
210: return "text/xml";
211: }
212: });
213: }
214: }
215:
216: protected HTTPSampleResult sample(URL url, String method,
217: boolean areFollowingRedirect, int frameDepth) {
218:
219: String urlStr = url.toString();
220:
221: log.debug("Start : sample" + urlStr);
222: log.debug("method" + method);
223:
224: PostMethod httpMethod;
225: httpMethod = new PostMethod(urlStr);
226:
227: HTTPSampleResult res = new HTTPSampleResult();
228: res.setMonitor(isMonitor());
229:
230: res.setSampleLabel(urlStr); // May be replaced later
231: res.setHTTPMethod(method);
232: res.sampleStart(); // Count the retries as well in the time
233: HttpClient client = null;
234: InputStream instream = null;
235: try {
236: int content_len = setPostHeaders(httpMethod);
237: client = setupConnection(url, httpMethod, res);
238:
239: res.setQueryString(getQueryString());
240: sendPostData(httpMethod, content_len);
241:
242: int statusCode = client.executeMethod(httpMethod);
243:
244: // Request sent. Now get the response:
245: instream = httpMethod.getResponseBodyAsStream();
246:
247: if (instream != null) {// will be null for HEAD
248:
249: org.apache.commons.httpclient.Header responseHeader = httpMethod
250: .getResponseHeader(TRANSFER_ENCODING);
251: if (responseHeader != null
252: && ENCODING_GZIP.equals(responseHeader
253: .getValue())) {
254: instream = new GZIPInputStream(instream);
255: }
256:
257: //int contentLength = httpMethod.getResponseContentLength();Not visible ...
258: //TODO size ouststream according to actual content length
259: ByteArrayOutputStream outstream = new ByteArrayOutputStream(
260: 4 * 1024);
261: //contentLength > 0 ? contentLength : DEFAULT_INITIAL_BUFFER_SIZE);
262: byte[] buffer = new byte[4096];
263: int len;
264: boolean first = true;// first response
265: while ((len = instream.read(buffer)) > 0) {
266: if (first) { // save the latency
267: res.latencyEnd();
268: first = false;
269: }
270: outstream.write(buffer, 0, len);
271: }
272:
273: res.setResponseData(outstream.toByteArray());
274: outstream.close();
275:
276: }
277:
278: res.sampleEnd();
279: // Done with the sampling proper.
280:
281: // Now collect the results into the HTTPSampleResult:
282:
283: res.setSampleLabel(httpMethod.getURI().toString());
284: // Pick up Actual path (after redirects)
285:
286: res.setResponseCode(Integer.toString(statusCode));
287: res.setSuccessful(isSuccessCode(statusCode));
288:
289: res.setResponseMessage(httpMethod.getStatusText());
290:
291: String ct = null;
292: org.apache.commons.httpclient.Header h = httpMethod
293: .getResponseHeader(HEADER_CONTENT_TYPE);
294: if (h != null)// Can be missing, e.g. on redirect
295: {
296: ct = h.getValue();
297: res.setContentType(ct);// e.g. text/html; charset=ISO-8859-1
298: res.setEncodingAndType(ct);
299: }
300:
301: res.setResponseHeaders(getResponseHeaders(httpMethod));
302: if (res.isRedirect()) {
303: res.setRedirectLocation(httpMethod.getResponseHeader(
304: HEADER_LOCATION).getValue());
305: }
306:
307: // If we redirected automatically, the URL may have changed
308: if (getAutoRedirects()) {
309: res.setURL(new URL(httpMethod.getURI().toString()));
310: }
311:
312: // Store any cookies received in the cookie manager:
313: saveConnectionCookies(httpMethod, res.getURL(),
314: getCookieManager());
315:
316: // Follow redirects and download page resources if appropriate:
317: res = resultProcessing(areFollowingRedirect, frameDepth,
318: res);
319:
320: log.debug("End : sample");
321: if (httpMethod != null)
322: httpMethod.releaseConnection();
323: return res;
324: } catch (IllegalArgumentException e)// e.g. some kinds of invalid URL
325: {
326: res.sampleEnd();
327: HTTPSampleResult err = errorResult(e, res);
328: err.setSampleLabel("Error: " + url.toString());
329: return err;
330: } catch (IOException e) {
331: res.sampleEnd();
332: HTTPSampleResult err = errorResult(e, res);
333: err.setSampleLabel("Error: " + url.toString());
334: return err;
335: } finally {
336: JOrphanUtils.closeQuietly(instream);
337: if (httpMethod != null)
338: httpMethod.releaseConnection();
339: }
340: }
341:
342: public URL getUrl() throws MalformedURLException {
343: return new URL(getURLData());
344: }
345: }
|