001package com.ganteater.ae.processor; 002 003import java.io.BufferedReader; 004import java.io.ByteArrayOutputStream; 005import java.io.IOException; 006import java.io.InputStream; 007import java.io.InputStreamReader; 008import java.io.OutputStream; 009import java.net.ServerSocket; 010import java.net.Socket; 011import java.net.SocketException; 012import java.net.SocketTimeoutException; 013import java.net.URI; 014import java.util.ArrayList; 015import java.util.HashMap; 016import java.util.List; 017import java.util.Map; 018import java.util.Map.Entry; 019import java.util.Properties; 020import java.util.Set; 021 022import org.apache.commons.io.IOUtils; 023import org.apache.commons.lang.StringUtils; 024import org.apache.http.NameValuePair; 025import org.apache.http.client.utils.URLEncodedUtils; 026 027import com.ganteater.ae.util.xml.easyparser.Node; 028 029public class ServerAction { 030 private static final String WAITING_FOR_A_REQUEST = "Waiting for a request ..."; 031 032 private static final String CONTENT_LENGTH = "content-length"; 033 034 private static final String AGENT = "agent"; 035 036 private static final String HOST = "host"; 037 038 private static final String STATUS = "status"; 039 040 private static final String BODY = "body"; 041 042 ServerSocket theServerSocket = null; 043 044 private String request; 045 private String response; 046 private String encoding; 047 private int maxNumber; 048 049 private Node currentAction; 050 051 private Processor tp; 052 053 public ServerAction(Processor tp, Node aCurrentAction, int port, String request, String response, 054 String encoding, int maxNumber) throws IOException { 055 056 this.tp = tp; 057 this.request = request; 058 this.response = response; 059 this.encoding = encoding; 060 this.maxNumber = maxNumber; 061 this.currentAction = aCurrentAction; 062 063 theServerSocket = tp.getListener().createPort(port, aCurrentAction.getAttribute("description")); 064 theServerSocket.setSoTimeout(100); 065 } 066 067 @SuppressWarnings("unchecked") 068 public void perform() throws Exception { 069 try { 070 Map<String, Object> requestMap = new HashMap<String, Object>(); 071 for (int i = 0; (maxNumber == 0 || i < maxNumber) && tp.isStoppedTest() == false; i++) { 072 if (tp.isStoppedTest()) { 073 break; 074 } 075 076 tp.startCommandInformation(currentAction); 077 try { 078 tp.getListener().setProgress(WAITING_FOR_A_REQUEST, 1, 1, false); 079 Socket socket = theServerSocket.accept(); 080 081 final InputStream theInputStream = socket.getInputStream(); 082 BufferedReader inputStream = new BufferedReader(new InputStreamReader(theInputStream)); 083 String readLine = inputStream.readLine(); 084 085 if (StringUtils.isEmpty(readLine)) { 086 socket.close(); 087 continue; 088 } 089 090 requestMap.put("head", readLine); 091 String method = StringUtils.substringBefore(readLine, " "); 092 readLine = StringUtils.substringBetween(readLine, " ", " "); 093 String uri = readLine; 094 if (StringUtils.isEmpty(readLine)) { 095 socket.close(); 096 continue; 097 } 098 099 List<NameValuePair> parse = new ArrayList<NameValuePair>(); 100 101 try { 102 parse = URLEncodedUtils.parse(new URI(readLine), "UTF-8"); 103 } catch (Exception e) { 104 socket.close(); 105 continue; 106 } 107 108 Properties query = new Properties(); 109 for (NameValuePair nameValuePair : parse) { 110 String name = nameValuePair.getName(); 111 if (StringUtils.isNotBlank(name)) { 112 Object property = query.get(name); 113 List<String> values = null; 114 String newValue = StringUtils.defaultIfEmpty(nameValuePair.getValue(), StringUtils.EMPTY); 115 if (property == null) { 116 query.put(name, newValue); 117 } else { 118 if (property instanceof String) { 119 String value = (String) property; 120 values = new ArrayList<String>(); 121 values.add(value); 122 123 } else if (property instanceof List) { 124 values = (List<String>) property; 125 126 } 127 values.add(newValue); 128 query.put(name, values); 129 } 130 } 131 } 132 133 Properties header = new Properties(); 134 do { 135 readLine = inputStream.readLine(); 136 String key = StringUtils.substringBefore(readLine, ":"); 137 String value = StringUtils.substringAfter(readLine, ": "); 138 header.setProperty(key.toLowerCase(), value); 139 140 } while (readLine.length() != 0); 141 142 String contentLengthStr = header.getProperty(CONTENT_LENGTH); 143 int contentLength = Integer.parseInt(StringUtils.defaultIfBlank(contentLengthStr, "-1").trim()); 144 145 ByteArrayOutputStream bodyStream = new ByteArrayOutputStream(); 146 if (contentLength > -1) { 147 for (int j = 0; j < contentLength; j++) { 148 bodyStream.write(inputStream.read()); 149 } 150 } else if (StringUtils.equalsIgnoreCase(header.getProperty("transfer-encoding"), "chunked")) { 151 int data = -1; 152 int[] pdata = new int[4]; 153 while ((data = inputStream.read()) > 0) { 154 pdata[0] = pdata[1]; 155 pdata[1] = pdata[2]; 156 pdata[2] = pdata[3]; 157 pdata[3] = data; 158 159 if (pdata[0] == 13 && pdata[1] == 10 && pdata[2] == 13 && pdata[3] == 10) { 160 break; 161 } 162 163 bodyStream.write(data); 164 } 165 } else { 166 while (inputStream.ready()) { 167 readLine = inputStream.readLine(); 168 if (readLine.length() > 0) { 169 bodyStream.write(readLine.getBytes()); 170 } else { 171 break; 172 } 173 } 174 } 175 176 String byteArray = null; 177 if (StringUtils.indexOf(header.getProperty("Content-Type"), "text/xml") >= 0) { 178 String xml = new String(bodyStream.toByteArray()); 179 byteArray = "<" + StringUtils.substringBeforeLast(StringUtils.substringAfter(xml, "<"), ">") 180 + ">"; 181 } else { 182 byteArray = new String(bodyStream.toByteArray()); 183 } 184 185 requestMap.put("method", method); 186 requestMap.put("params", query); 187 requestMap.put("header", header); 188 requestMap.put(BODY, byteArray); 189 requestMap.put("query", uri); 190 191 tp.setVariableValue(request, requestMap); 192 tp.taskNode(currentAction); 193 194 final OutputStream theOutputStream = socket.getOutputStream(); 195 Object responseObject = tp.getVariableValue(response); 196 ByteArrayOutputStream output = new ByteArrayOutputStream(); 197 if (responseObject instanceof Map) { 198 Map<String, Object> responseMap = new HashMap<String, Object>((Map<String, ?>) responseObject); 199 responseObject = responseMap.get(BODY); 200 responseMap.remove(BODY); 201 202 output.write( 203 ("HTTP/1.1 " + StringUtils.defaultIfEmpty((String) responseMap.get(STATUS), "200 OK") 204 + '\n').getBytes()); 205 responseMap.remove(STATUS); 206 207 String ip = (String) responseMap.get(HOST); 208 if (ip == null) { 209 ip = socket.getLocalAddress().getHostName(); 210 } 211 output.write(("Host: " + ip).getBytes()); 212 responseMap.remove(HOST); 213 214 output.write(("User-Agent: " 215 + StringUtils.defaultIfEmpty((String) responseMap.get(AGENT), "Anteater") + '\n') 216 .getBytes()); 217 responseMap.remove(AGENT); 218 219 Set<Entry<String, Object>> entrySet = responseMap.entrySet(); 220 for (Entry<String, Object> entry : entrySet) { 221 output.write((entry.getKey() + ": " + entry.getValue() + '\n').getBytes()); 222 } 223 224 if (responseObject instanceof String) { 225 responseObject = ((String) responseObject).getBytes(encoding); 226 } 227 228 if (!responseMap.containsKey(CONTENT_LENGTH)) { 229 long length = ((byte[]) responseObject).length; 230 output.write((CONTENT_LENGTH + ": " + length + '\n').getBytes()); 231 } 232 233 output.write('\n'); 234 } 235 236 if (responseObject instanceof String) { 237 responseObject = ((String) responseObject).getBytes(encoding); 238 } 239 240 if (responseObject != null) { 241 output.write((byte[]) responseObject); 242 } 243 theOutputStream.write(output.toByteArray()); 244 245 IOUtils.closeQuietly(theOutputStream); 246 IOUtils.closeQuietly(theInputStream); 247 248 } catch (final SocketTimeoutException e) { 249 continue; 250 } catch (final SocketException e) { 251 continue; 252 } 253 tp.getListener().setProgress("", 1, 1, false); 254 255 } 256 } finally { 257 theServerSocket.close(); 258 } 259 } 260}