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, String encoding, 054 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 tp.getListener().setProgress(WAITING_FOR_A_REQUEST, currentAction.size() + 1, 1, false); 073 074 tp.startCommandInformation(currentAction); 075 try (Socket socket = theServerSocket.accept()) { 076 077 if (tp.isStoppedTest()) { 078 break; 079 } 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 if (StringUtils.isNotBlank(key)) { 138 String value = StringUtils.substringAfter(readLine, ": "); 139 header.setProperty(key.toLowerCase(), value); 140 } 141 142 } while (readLine.length() != 0); 143 144 String contentLengthStr = header.getProperty(CONTENT_LENGTH); 145 int contentLength = Integer.parseInt(StringUtils.defaultIfBlank(contentLengthStr, "-1").trim()); 146 147 ByteArrayOutputStream bodyStream = new ByteArrayOutputStream(); 148 if (contentLength > -1) { 149 for (int j = 0; j < contentLength - 1; j++) { 150 int b = inputStream.read(); 151 bodyStream.write(b); 152 } 153 } else if (StringUtils.equalsIgnoreCase(header.getProperty("transfer-encoding"), "chunked")) { 154 int data = -1; 155 int[] pdata = new int[4]; 156 while ((data = inputStream.read()) > 0) { 157 pdata[0] = pdata[1]; 158 pdata[1] = pdata[2]; 159 pdata[2] = pdata[3]; 160 pdata[3] = data; 161 162 if (pdata[0] == 13 && pdata[1] == 10 && pdata[2] == 13 && pdata[3] == 10) { 163 break; 164 } 165 166 bodyStream.write(data); 167 } 168 } else { 169 while (inputStream.ready()) { 170 readLine = inputStream.readLine(); 171 if (readLine.length() > 0) { 172 bodyStream.write(readLine.getBytes()); 173 } else { 174 break; 175 } 176 } 177 } 178 179 String byteArray = null; 180 if (StringUtils.indexOf(header.getProperty("Content-Type"), "text/xml") >= 0) { 181 String xml = new String(bodyStream.toByteArray()); 182 byteArray = "<" + StringUtils.substringBeforeLast(StringUtils.substringAfter(xml, "<"), ">") 183 + ">"; 184 } else { 185 byteArray = new String(bodyStream.toByteArray()); 186 } 187 188 requestMap.put("method", method); 189 requestMap.put("params", query); 190 requestMap.put("header", header); 191 requestMap.put(BODY, byteArray); 192 requestMap.put("query", uri); 193 194 tp.setVariableValue(request, requestMap); 195 tp.taskNode(currentAction); 196 197 final OutputStream theOutputStream = socket.getOutputStream(); 198 Object responseObject = tp.getVariableValue(response); 199 ByteArrayOutputStream output = new ByteArrayOutputStream(); 200 if (responseObject instanceof Map) { 201 Map<String, Object> responseMap = new HashMap<String, Object>((Map<String, ?>) responseObject); 202 responseObject = responseMap.get(BODY); 203 responseMap.remove(BODY); 204 205 output.write( 206 ("HTTP/1.1 " + StringUtils.defaultIfEmpty((String) responseMap.get(STATUS), "200 OK") 207 + '\n').getBytes()); 208 responseMap.remove(STATUS); 209 210 String ip = (String) responseMap.get(HOST); 211 if (ip == null) { 212 ip = socket.getLocalAddress().getHostName(); 213 } 214 output.write(("Host: " + ip).getBytes()); 215 responseMap.remove(HOST); 216 217 output.write(("User-Agent: " 218 + StringUtils.defaultIfEmpty((String) responseMap.get(AGENT), "Anteater") + '\n') 219 .getBytes()); 220 responseMap.remove(AGENT); 221 222 Set<Entry<String, Object>> entrySet = responseMap.entrySet(); 223 for (Entry<String, Object> entry : entrySet) { 224 output.write((entry.getKey() + ": " + entry.getValue() + '\n').getBytes()); 225 } 226 227 if (responseObject instanceof String) { 228 responseObject = ((String) responseObject).getBytes(encoding); 229 } 230 231 if (!responseMap.containsKey(CONTENT_LENGTH)) { 232 long length = ((byte[]) responseObject).length; 233 output.write((CONTENT_LENGTH + ": " + length + '\n').getBytes()); 234 } 235 236 output.write('\n'); 237 } 238 239 if (responseObject instanceof String) { 240 responseObject = ((String) responseObject).getBytes(encoding); 241 } 242 243 if (responseObject != null) { 244 output.write((byte[]) responseObject); 245 } 246 theOutputStream.write(output.toByteArray()); 247 248 IOUtils.closeQuietly(theOutputStream); 249 IOUtils.closeQuietly(theInputStream); 250 251 } catch (final SocketTimeoutException e) { 252 continue; 253 } catch (final SocketException e) { 254 continue; 255 } 256 tp.getListener().setProgress("", 1, 1, false); 257 258 } 259 } finally { 260 theServerSocket.close(); 261 } 262 } 263}