1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package org.apache.jmeter.protocol.http.control; 20 21 import java.io.BufferedReader; 22 import java.io.File; 23 import java.io.FileReader; 24 import java.io.FileWriter; 25 import java.io.IOException; 26 import java.io.PrintWriter; 27 import java.io.Serializable; 28 import java.util.ArrayList; 29 import java.util.Enumeration; 30 import java.util.Vector; 31 32 import org.apache.commons.io.IOUtils; 33 import org.apache.jmeter.config.ConfigTestElement; 34 import org.apache.jmeter.testelement.TestElement; 35 import org.apache.jmeter.testelement.property.CollectionProperty; 36 import org.apache.jmeter.testelement.property.JMeterProperty; 37 import org.apache.jorphan.util.JOrphanUtils; 38 39 /** 40 * This class provides an interface to headers file to pass HTTP headers along 41 * with a request. 42 * 43 * @version $Revision: 773376 $ 44 */ 45 public class HeaderManager extends ConfigTestElement implements Serializable { 46 47 public static final String HEADERS = "HeaderManager.headers";// $NON-NLS-1$ 48 49 private final static String[] COLUMN_RESOURCE_NAMES = { 50 "name", // $NON-NLS-1$ 51 "value" // $NON-NLS-1$ 52 }; 53 54 private final static int COLUMN_COUNT = COLUMN_RESOURCE_NAMES.length; 55 56 57 /** 58 * Apache SOAP driver does not provide an easy way to get and set the cookie 59 * or HTTP header. Therefore it is necessary to store the SOAPHTTPConnection 60 * object and reuse it. 61 */ 62 private Object SOAPHeader = null; 63 64 public HeaderManager() { 65 setProperty(new CollectionProperty(HEADERS, new ArrayList())); 66 } 67 68 public void clear() { 69 super.clear(); 70 setProperty(new CollectionProperty(HEADERS, new ArrayList())); 71 } 72 73 /** 74 * Get the collection of JMeterProperty entries representing the headers. 75 * 76 * @return the header collection property 77 */ 78 public CollectionProperty getHeaders() { 79 return (CollectionProperty) getProperty(HEADERS); 80 } 81 82 public int getColumnCount() { 83 return COLUMN_COUNT; 84 } 85 86 public String getColumnName(int column) { 87 return COLUMN_RESOURCE_NAMES[column]; 88 } 89 90 public Class getColumnClass(int column) { 91 return COLUMN_RESOURCE_NAMES[column].getClass(); 92 } 93 94 public Header getHeader(int row) { 95 return (Header) getHeaders().get(row).getObjectValue(); 96 } 97 98 /** 99 * Save the header data to a file. 100 */ 101 public void save(String headFile) throws IOException { 102 File file = new File(headFile); 103 if (!file.isAbsolute()) { 104 file = new File(System.getProperty("user.dir")// $NON-NLS-1$ 105 + File.separator + headFile); 106 } 107 PrintWriter writer = new PrintWriter(new FileWriter(file)); 108 writer.println("# JMeter generated Header file");// $NON-NLS-1$ 109 final CollectionProperty hdrs = getHeaders(); 110 for (int i = 0; i < hdrs.size(); i++) { 111 final JMeterProperty hdr = hdrs.get(i); 112 Header head = (Header) hdr.getObjectValue(); 113 writer.println(head.toString()); 114 } 115 writer.flush(); 116 writer.close(); 117 } 118 119 /** 120 * Add header data from a file. 121 */ 122 public void addFile(String headerFile) throws IOException { 123 File file = new File(headerFile); 124 if (!file.isAbsolute()) { 125 file = new File(System.getProperty("user.dir")// $NON-NLS-1$ 126 + File.separator + headerFile); 127 } 128 if (!file.canRead()) { 129 throw new IOException("The file you specified cannot be read."); 130 } 131 132 BufferedReader reader = null; 133 try { 134 reader = new BufferedReader(new FileReader(file)); 135 String line; 136 while ((line = reader.readLine()) != null) { 137 try { 138 if (line.startsWith("#") || line.trim().length() == 0) {// $NON-NLS-1$ 139 continue; 140 } 141 String[] st = JOrphanUtils.split(line, "\t", " ");// $NON-NLS-1$ $NON-NLS-2$ 142 int name = 0; 143 int value = 1; 144 Header header = new Header(st[name], st[value]); 145 getHeaders().addItem(header); 146 } catch (Exception e) { 147 throw new IOException("Error parsing header line\n\t'" + line + "'\n\t" + e); 148 } 149 } 150 } finally { 151 IOUtils.closeQuietly(reader); 152 } 153 } 154 155 /** 156 * Add a header. 157 */ 158 public void add(Header h) { 159 getHeaders().addItem(h); 160 } 161 162 /** 163 * Add an empty header. 164 */ 165 public void add() { 166 getHeaders().addItem(new Header()); 167 } 168 169 /** 170 * Remove a header. 171 */ 172 public void remove(int index) { 173 getHeaders().remove(index); 174 } 175 176 /** 177 * Return the number of headers. 178 */ 179 public int size() { 180 return getHeaders().size(); 181 } 182 183 /** 184 * Return the header at index i. 185 */ 186 public Header get(int i) { 187 return (Header) getHeaders().get(i).getObjectValue(); 188 } 189 190 /* 191 * public String getHeaderHeaderForURL(URL url) { if 192 * (!url.getProtocol().toUpperCase().trim().equals("HTTP") && 193 * !url.getProtocol().toUpperCase().trim().equals("HTTPS")) { return null; } 194 * 195 * StringBuffer sbHeader = new StringBuffer(); for (Iterator enum = 196 * headers.iterator(); enum.hasNext();) { Header header = (Header) 197 * enum.next(); if (url.getHost().endsWith(header.getDomain()) && 198 * url.getFile().startsWith(header.getPath()) && (System.currentTimeMillis() / 199 * 1000) <= header.getExpires()) { if (sbHeader.length() > 0) { 200 * sbHeader.append("; "); } 201 * sbHeader.append(header.getName()).append("=").append( header.getValue()); } } 202 * 203 * if (sbHeader.length() != 0) { return sbHeader.toString(); } else { return 204 * null; } } 205 */ 206 207 /* 208 * public void addHeaderFromHeader(String headerHeader, URL url) { 209 * StringTokenizer st = new StringTokenizer(headerHeader, ";"); String nvp; 210 * // first n=v is name=value nvp = st.nextToken(); int index = 211 * nvp.indexOf("="); String name = nvp.substring(0, index); String value = 212 * nvp.substring(index + 1); String domain = url.getHost(); 213 * 214 * Header newHeader = new Header(name, value); // check the rest of the 215 * headers while (st.hasMoreTokens()) { nvp = st.nextToken(); nvp = 216 * nvp.trim(); index = nvp.indexOf("="); if (index == -1) { index = 217 * nvp.length(); } String key = nvp.substring(0, index); 218 * 219 * Vector removeIndices = new Vector(); for (int i = headers.size() - 1; i >= 220 * 0; i--) { Header header = (Header) headers.get(i); if (header == null) { 221 * continue; } if (header.getName().equals(newHeader.getName())) { 222 * removeIndices.addElement(new Integer(i)); } } 223 * 224 * for (Enumeration e = removeIndices.elements(); e.hasMoreElements(); ) { 225 * index = ((Integer) e.nextElement()).intValue(); headers.remove(index); } 226 * } 227 */ 228 public void removeHeaderNamed(String name) { 229 Vector removeIndices = new Vector(); 230 for (int i = getHeaders().size() - 1; i >= 0; i--) { 231 Header header = (Header) getHeaders().get(i).getObjectValue(); 232 if (header == null) { 233 continue; 234 } 235 if (header.getName().equalsIgnoreCase(name)) { 236 removeIndices.addElement(new Integer(i)); 237 } 238 } 239 240 for (Enumeration e = removeIndices.elements(); e.hasMoreElements();) { 241 getHeaders().remove(((Integer) e.nextElement()).intValue()); 242 } 243 } 244 245 /** 246 * Added support for SOAP related header stuff. 1-29-04 Peter Lin 247 * 248 * @return the SOAP header Object 249 */ 250 public Object getSOAPHeader() { 251 return this.SOAPHeader; 252 } 253 254 /** 255 * Set the SOAPHeader with the SOAPHTTPConnection object. We may or may not 256 * want to rename this to setHeaderObject(Object). Concievably, other 257 * samplers may need this kind of functionality. 1-29-04 Peter Lin 258 * 259 * @param header 260 */ 261 public void setSOAPHeader(Object header) { 262 this.SOAPHeader = header; 263 } 264 265 /** 266 * Merge the attributes with a another HeaderManager's attributes. 267 * @param element The object to be merged with 268 * @param preferLocalValues When both objects have a value for the 269 * same attribute, this flag determines which value is preferresd. 270 */ 271 public HeaderManager merge(TestElement element, boolean preferLocalValues) { 272 if (!(element instanceof HeaderManager)) { 273 throw new IllegalArgumentException("Cannot merge type:" + this.getClass().getName() + " with type:" + element.getClass().getName()); 274 } 275 276 // start off with a merged object as a copy of the local object 277 HeaderManager merged = (HeaderManager)this.clone(); 278 279 HeaderManager other = (HeaderManager)element; 280 // iterate thru each of the other headers 281 for (int i = 0; i < other.getHeaders().size(); i++) { 282 Header otherHeader = other.get(i); 283 boolean found = false; 284 // find the same property in the local headers 285 for (int j = 0; j < merged.getHeaders().size(); j++) { 286 Header mergedHeader = merged.get(j); 287 if (mergedHeader.getName().equalsIgnoreCase(otherHeader.getName())) { 288 // we have a match 289 found = true; 290 if (!preferLocalValues) { 291 // prefer values from the other object 292 if ( (otherHeader.getValue() == null) || (otherHeader.getValue().length() == 0) ) { 293 // the other object has an empty value, so remove this value from the merged object 294 merged.remove(j); 295 } else { 296 // use the other object's value 297 mergedHeader.setValue(otherHeader.getValue()); 298 } 299 } 300 // break out of the inner loop 301 break; 302 } 303 } 304 if (!found) { 305 // the other object has a new value to be added to the merged 306 merged.add(otherHeader); 307 } 308 } 309 310 // finally, merge the names so it's clear they've been merged 311 merged.setName(merged.getName() + ":" + other.getName()); 312 313 return merged; 314 } 315 }