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}