/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.jmeterplugins.protocol.http.control; import org.apache.jmeter.gui.Stoppable; import org.apache.jmeter.util.JMeterUtils; import org.apache.jorphan.logging.LoggingManager; import org.apache.log.Logger; import java.io.*; import java.text.SimpleDateFormat; import java.util.*; public class HttpSimpleTableServer extends NanoHTTPD implements Stoppable, KeyWaiter { private static final Logger log = LoggingManager.getLoggerForClass(); public static final String STS_VERSION = "1.3"; public static final String ROOT = "/sts/"; public static final String ROOT2 = "/sts"; public static final String URI_INITFILE = "INITFILE"; public static final String URI_READ = "READ"; public static final String URI_ADD = "ADD"; public static final String URI_SAVE = "SAVE"; public static final String URI_LENGTH = "LENGTH"; public static final String URI_STATUS = "STATUS"; public static final String URI_RESET = "RESET"; public static final String URI_STOP = "STOP"; public static final String PARM_FILENAME = "FILENAME"; public static final String PARM_LINE = "LINE"; public static final String PARM_READ_MODE = "READ_MODE"; public static final String PARM_ADD_MODE = "ADD_MODE"; public static final String PARM_KEEP = "KEEP"; public static final String VAL_FIRST = "FIRST"; public static final String VAL_LAST = "LAST"; public static final String VAL_RANDOM = "RANDOM"; public static final String VAL_TRUE = "TRUE"; public static final String VAL_FALSE = "FALSE"; public static final String INDEX = "<html><head><title>URL for the dataset</title><head>" + "<body><h4>From a data file (default: <JMETER_HOME>/bin/[data_file])</h4>" + "<p>Load file in memory:<br />" + "http://hostname:port/sts/INITFILE?FILENAME=file.txt</p>" + "<p>Get one line from list:<br />" + "http://hostname:port/sts/READ?READ_MODE=[<i>FIRST</i>,<i>LAST</i>,<i>RANDOM</i>]&KEEP=[<i>TRUE</i>,<i>FALSE</i>]&FILENAME=file.txt</p>" + "<p>Return the number of remaining lines of a linked list:<br />" + "http://hostname:port/sts/LENGTH?FILENAME=file.txt</p>" + "<p>Add a line into a file: (GET OR POST HTTP protocol)<br />" + "GET : http://hostname:port/sts/ADD?FILENAME=file.txt&LINE=D0001123&ADD_MODE=[<i>FIRST</i>,<i>LAST</i>]<br />" + "GET Parameters : FILENAME=file.txt&LINE=D0001123&ADD_MODE=[<i>FIRST</i>,<i>LAST</i>]<br />" + "POST : http://hostname:port/sts/ADD<br />" + "POST Parameters : FILENAME=file.txt,LINE=D0001123,ADD_MODE=[<i>FIRST</i>,<i>LAST</i>]</p>" + "<p>Save the specified linked list in a file to the default location:<br />" + "http://hostname:port/sts/SAVE?FILENAME=file.txt</p>" + "<p>Display the list of loaded files and the number of remaining lines for each linked list:<br />" + "http://hostname:port/sts/STATUS</p>" + "<p>Remove all of the elements from the specified list:<br />" + "http://hostname:port/sts/RESET?FILENAME=file.txt</p>" + "<p>Shutdown the Simple Table Server:<br />" + "http://hostname:port/sts/STOP</p></body></html>"; private String myDataDirectory; private boolean bTimestamp; private Random myRandom; // CRLF ou LF ou CR public static String lineSeparator = System.getProperty("line.separator"); private Map<String, LinkedList<String>> database = new HashMap<String, LinkedList<String>>(); public HttpSimpleTableServer(int port, boolean timestamp, String dataDir) { super(port); myDataDirectory = dataDir; bTimestamp = timestamp; myRandom = new Random(); } @Override public Response serve(IHTTPSession session) { Method method = session.getMethod(); String uri = session.getUri(); String msg = "<html><title>KO</title>" + lineSeparator + "<body>Error : unknown command !</body>" + lineSeparator + "</html>"; Map<String, String> files = new HashMap<String, String>(); if (Method.POST.equals(method)) { try { session.parseBody(files); } catch (IOException ioe) { return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage()); } catch (ResponseException re) { return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage()); } } Map<String, String> parms = session.getParms(); if (uri.equals(ROOT) || uri.equals(ROOT2)) { msg = INDEX; } else { msg = doAction(uri, method, parms); } Response response = new NanoHTTPD.Response(msg); // no cache for the response response.addHeader("Cache-Control", "no-cache, no-store, must-revalidate"); response.addHeader("Pragma", "no-cache"); response.addHeader("Expires", "0"); return response; } protected synchronized String doAction(String uri, Method method, Map<String, String> parms) { String msg = "<html><title>KO</title>" + lineSeparator + "<body>Error : unknown command !</body>" + lineSeparator + "</html>"; if (uri.equals(ROOT + URI_INITFILE)) { msg = initFile(parms.get(PARM_FILENAME)); } if (uri.equals(ROOT + URI_READ)) { msg = read(parms.get(PARM_READ_MODE), parms.get(PARM_KEEP), parms.get(PARM_FILENAME)); } if (uri.equals(ROOT + URI_ADD) && (Method.POST.equals(method) || (Method.GET.equals(method)))) { msg = add(parms.get(PARM_ADD_MODE), parms.get(PARM_LINE), parms.get(PARM_FILENAME)); } if (uri.equals(ROOT + URI_LENGTH)) { msg = length(parms.get(PARM_FILENAME)); } if (uri.equals(ROOT + URI_SAVE)) { msg = save(parms.get(PARM_FILENAME)); } if (uri.equals(ROOT + URI_STATUS)) { msg = status(); } if (uri.equals(ROOT + URI_RESET)) { msg = reset(parms.get(PARM_FILENAME)); } if (uri.equals(ROOT + URI_STOP)) { stopServer(); } return msg; } private String status() { if (database.isEmpty()) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : Database was empty !</body>" + lineSeparator + "</html>"; } String msg = ""; for (String key : database.keySet()) { msg += key + " = " + database.get(key).size() + "<br />" + lineSeparator; } return "<html><title>OK</title>" + lineSeparator + "<body>" + lineSeparator + msg + "</body></html>"; } private String read(String readMode, String keepMode, String filename) { if (null == filename) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : FILENAME parameter was missing !</body>" + lineSeparator + "</html>"; } if (!database.containsKey(filename)) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : " + filename + " not loaded yet !</body>" + lineSeparator + "</html>"; } if (database.get(filename).isEmpty()) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : No more line !</body>" + lineSeparator + "</html>"; } if (null == readMode) { readMode = VAL_FIRST; } if (null == keepMode) { keepMode = VAL_TRUE; } if (!VAL_FIRST.equals(readMode) && !VAL_LAST.equals(readMode) && !VAL_RANDOM.equals(readMode)) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : READ_MODE value has to be FIRST, LAST or RANDOM !</body>" + lineSeparator + "</html>"; } if (!VAL_TRUE.equals(keepMode) && !VAL_FALSE.equals(keepMode)) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : KEEP value has to be TRUE or FALSE !</body>" + lineSeparator + "</html>"; } String line; int index = 0; if (VAL_LAST.equals(readMode)) { index = database.get(filename).size() - 1; } if (VAL_RANDOM.equals(readMode)) { index = myRandom.nextInt(database.get(filename).size()); } line = database.get(filename).remove(index); if (VAL_TRUE.equals(keepMode)) { database.get(filename).add(line); } return "<html><title>OK</title>" + lineSeparator + "<body>" + line + "</body>" + lineSeparator + "</html>"; } private String add(String addMode, String line, String filename) { if (null == filename) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : FILENAME parameter was missing !</body>" + lineSeparator + "</html>"; } if (null == line) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : LINE parameter was missing !</body>" + lineSeparator + "</html>"; } if (!database.containsKey(filename)) { database.put(filename, new LinkedList<String>()); } if (null == addMode) { addMode = VAL_FIRST; } if (!VAL_FIRST.equals(addMode) && !VAL_LAST.equals(addMode)) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : ADD_MODE value has to be FIRST or LAST !</body>" + lineSeparator + "</html>"; } if (VAL_FIRST.equals(addMode)) { database.get(filename).addFirst(line); } else { database.get(filename).add(line); } return "<html><title>OK</title>" + lineSeparator + "<body></body>" + lineSeparator + "</html>"; } private String save(String filename) { if (null == filename) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : FILENAME parameter was missing !</body>" + lineSeparator + "</html>"; } if (filename.matches(".*[\\\\/:].*") || filename.equals(".") || filename.equals("..")) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : Illegal character found !</body>" + lineSeparator + "</html>"; } if (filename.length() > 128) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : Maximum size reached (128) !</body>" + lineSeparator + "</html>"; } if (!database.containsKey(filename)) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : LinkedList not found !</body>" + lineSeparator + "</html>"; } BufferedWriter out = null; String saveFilename = filename; if (bTimestamp) { Date dNow = new Date(); SimpleDateFormat ft = new SimpleDateFormat( "yyyyMMdd'T'HH'h'mm'm'ss's.'"); saveFilename = ft.format(dNow) + filename; } try { Iterator<String> it = database.get(filename).iterator(); out = new BufferedWriter(new FileWriter(new File(myDataDirectory, saveFilename))); while (it.hasNext()) { out.write(it.next()); out.write(lineSeparator); } } catch (FileNotFoundException e1) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : " + e1.getMessage() + "</body>" + lineSeparator + "</html>"; } catch (IOException e2) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : " + e2.getMessage() + "</body>" + lineSeparator + "</html>"; } finally { if (null != out) { try { out.close(); } catch (IOException e3) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : " + e3.getMessage() + "</body>" + lineSeparator + "</html>"; } } } return "<html><title>OK</title>" + lineSeparator + "<body>" + database.get(filename).size() + "</body>" + lineSeparator + "</html>"; } private String length(String filename) { if (null == filename) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : FILENAME parameter was missing !</body>" + lineSeparator + "</html>"; } if (!database.containsKey(filename)) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : " + filename + " not loaded yet !</body>" + lineSeparator + "</html>"; } return "<html><title>OK</title>" + lineSeparator + "<body>" + database.get(filename).size() + "</body>" + lineSeparator + "</html>"; } private String reset(String filename) { if (null == filename) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : FILENAME parameter was missing !</body>" + lineSeparator + "</html>"; } if (database.containsKey(filename)) { database.get(filename).clear(); } return "<html><title>OK</title>" + lineSeparator + "<body></body>" + lineSeparator + "</html>"; } private String initFile(String filename) { if (null == filename) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : FILENAME parameter was missing !</body>" + lineSeparator + "</html>"; } if (filename.matches(".*[\\\\/:].*") || filename.equals(".") || filename.equals("..")) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : Illegal character found !</body>" + lineSeparator + "</html>"; } if (filename.length() > 128) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : Maximum size reached (128) !</body>" + lineSeparator + "</html>"; } LinkedList<String> lines = new LinkedList<String>(); BufferedReader bufferReader = null; File f = new File(myDataDirectory, filename); if (f.exists()) { try { bufferReader = new BufferedReader(new FileReader(f), 50 * 1024); String line; while ((line = bufferReader.readLine()) != null) { lines.add(line); } } catch (FileNotFoundException e1) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : " + e1.getMessage() + "</body>" + lineSeparator + "</html>"; } catch (IOException e2) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : " + e2.getMessage() + "</body>" + lineSeparator + "</html>"; } finally { if (null != bufferReader) { try { bufferReader.close(); } catch (IOException e3) { return "<html><title>KO</title>" + lineSeparator + "<body>Error : " + e3.getMessage() + "</body>" + lineSeparator + "</html>"; } } } database.put(filename, lines); return "<html><title>OK</title>" + lineSeparator + "<body>" + lines.size() + "</body>" + lineSeparator + "</html>"; } return "<html><title>KO</title>" + lineSeparator + "<body>Error : file not found !</body>" + lineSeparator + "</html>"; } @Override public void stopServer() { log.info("HTTP Simple Table Server is shutting down..."); stop(); } public static void main(String args[]) { JMeterUtils.loadJMeterProperties("jmeter.properties"); String dataset = JMeterUtils.getPropDefault( "jmeterPlugin.sts.datasetDirectory", HttpSimpleTableControl.DEFAULT_DATA_DIR); int port = JMeterUtils.getPropDefault("jmeterPlugin.sts.port", HttpSimpleTableControl.DEFAULT_PORT); boolean timestamp = JMeterUtils.getPropDefault( "jmeterPlugin.sts.addTimestamp", HttpSimpleTableControl.DEFAULT_TIMESTAMP); // default level LoggingManager.setPriority("INFO"); // allow override by system properties LoggingManager.setLoggingLevels(System.getProperties()); HttpSimpleTableServer serv = new HttpSimpleTableServer(port, timestamp, dataset); log.info("Creating HttpSimpleTable ..."); log.info("------------------------------"); log.info("SERVER_PORT : " + port); log.info("DATASET_DIR : " + dataset); log.info("TIMESTAMP : " + timestamp); log.info("------------------------------"); log.info("STS_VERSION : " + STS_VERSION); ServerRunner.executeInstance(serv); } public void waitForKey() { log.info("Hit Enter to stop"); try { System.in.read(); } catch (Throwable ignored) { } } }