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}