package org.autoplot.servlet; import org.autoplot.JythonUtil; import org.autoplot.ScriptContext; import org.autoplot.ApplicationModel; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.autoplot.jythonsupport.JythonRefactory; import org.das2.datum.TimeUtil; import org.das2.datum.format.TimeDatumFormatter; import org.python.util.PythonInterpreter; import org.autoplot.scriptconsole.LoggingOutputStream; /** * Allow the clients to run scripts on the server. * For now, these are logged for security to the folder /tmp/autoplotservlet (or AUTOPLOT_SERVLET_HOME). * AUTOPLOT_SERVLET_HOME/allowhosts contains a list of allowed clients. * See script.jsp for more information. * * @author jbf */ public class ScriptServlet extends HttpServlet { /** * Processes requests for both HTTP GET and POST methods. * @param request servlet request * @param response servlet response * @throws javax.servlet.ServletException * @throws java.io.IOException */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { ApplicationModel appmodel = new ApplicationModel(); appmodel.addDasPeersToAppAndWait(); String script= request.getParameter("script"); if ( script==null ) { script= "setCanvasSize( 600, 400 )\n"+ "setDataSourceURL( 'http://www.sarahandjeremy.net/jeremy/1wire/data/2008/0B000800408DD710.20080117.d2s' )\n"+ "setTitle( 'Garage 20080117' )\n" + "response.setContentType('image/png')\n" + "out = response.getOutputStream()\n" + "writeToPng( out )\n"; } // do minimal taint checking. String[] ss= script.split("\n"); for (String s : ss) { if (s.contains("import")) throw new IllegalArgumentException("imports not allowed for security"); if (s.contains("eval")) throw new IllegalArgumentException("eval not allowed for security"); if (s.contains("formatDataSet")) throw new IllegalArgumentException("formatDataSet not allowed for security"); } String ts= new TimeDatumFormatter("%Y%m%dT%H%M%S.%{milli}").format( TimeUtil.now() ); String who= request.getRemoteAddr(); if ( who.equals("0:0:0:0:0:0:0:1") ) who= "localhost"; if ( who.equals("127.0.0.1") ) who= "localhost"; String home= System.getProperty( "AUTOPLOT_SERVLET_HOME" ); if ( home==null ) home= "/tmp/autoplotservlet/"; home= new File(home).getCanonicalPath(); home= home + File.separator; new File(home).mkdirs(); File hostsallow= new File( home + "allowhosts" ); if ( !hostsallow.exists() ) { PrintWriter write= new PrintWriter( new FileWriter( hostsallow ) ); write.println("# Initially, only clients from the localhost can connect. List the allowed clients, one per line."); write.println("# Globs like 192.168.0.* may be used."); write.println("localhost"); write.close(); } if ( hostsallow.exists() ) { boolean reject= true; BufferedReader r= new BufferedReader( new FileReader( hostsallow ) ); String h= r.readLine(); while ( h!=null ) { int i= h.indexOf("#"); if (i>-1 ) h= h.substring(0,i); if ( h.trim().length()==0 ) { h= r.readLine(); continue; } h= h.replaceAll("\\*","\\.\\*"); if ( Pattern.matches( h, who ) ) { reject= false; } h= r.readLine(); } if ( reject ) { response.sendError(403, hostsallow + " does not permit host=\""+who+"\""); return; } } else { response.sendError(403, hostsallow + " file does not exist: "+hostsallow ); } File f= new File( home + ts+"."+who+".jy" ); FileWriter w= new FileWriter(f); w.append(script); w.close(); ScriptContext.getDocumentModel().getOptions().setAutolayout(false); PythonInterpreter interp = JythonUtil.createInterpreter( true, true ); interp.set("java",null); interp.set("org",null); interp.set("getFile",null); interp.set("downloadResourceAsTempFile",null); LoggingOutputStream los1= new LoggingOutputStream( Logger.getLogger("autoplot.servlet.scriptservlet"), Level.INFO ); interp.setOut( los1 ); interp.set( "response", response ); // To support load balancing, insert the actual host that resolved the request response.setHeader( "X-Served-By", java.net.InetAddress.getLocalHost().getCanonicalHostName() ); //TODO: this limits to one user! LoggingOutputStream los2= new LoggingOutputStream( Logger.getLogger("autoplot.servlet.scriptservlet"), Level.INFO ); ScriptContext._setOutputStream( los2 ); script= JythonRefactory.fixImports(script); interp.exec(script); try { los1.close(); } catch ( IOException ex ) {} try { los2.close(); } catch ( IOException ex ) {} } catch ( Exception ex ) { response.sendError(403, ex.toString() ); } finally { } } // /** * Handles the HTTP GET method. * @param request servlet request * @param response servlet response */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP POST method. * @param request servlet request * @param response servlet response */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. */ public String getServletInfo() { return "Autoplot ScriptServlet"; }// }