All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.w3c.css.servlet.CssValidator Maven / Gradle / Ivy

The newest version!
//
// $Id: CssValidator.java,v 1.43 2010-01-05 13:49:59 ylafon Exp $
// From Philippe Le Hegaret ([email protected])
//
// (c) COPYRIGHT MIT and INRIA, 1997.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.css.servlet;

import org.w3c.css.css.CssParser;
import org.w3c.css.css.DocumentParser;
import org.w3c.css.css.StyleReport;
import org.w3c.css.css.StyleReportFactory;
import org.w3c.css.css.StyleSheet;
import org.w3c.css.css.StyleSheetParser;
import org.w3c.css.css.TagSoupStyleSheetHandler;
import org.w3c.css.error.ErrorReport;
import org.w3c.css.error.ErrorReportFactory;
import org.w3c.css.index.IndexGenerator;
import org.w3c.css.properties.PropertiesLoader;
import org.w3c.css.util.ApplContext;
import org.w3c.css.util.Codecs;
import org.w3c.css.util.FakeFile;
import org.w3c.css.util.HTTPURL;
import org.w3c.css.util.NVPair;
import org.w3c.css.util.Utf8Properties;
import org.w3c.css.util.Util;
import org.w3c.www.mime.MimeType;
import org.w3c.www.mime.MimeTypeFormatException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ProtocolException;
import java.net.URL;

/**
 * This class is a servlet to use the validator.
 * 
 * @version $Revision: 1.43 $
 */
public final class CssValidator extends HttpServlet {

    final static String texthtml    = "text/html";

    final static String applxhtml   = "application/xhtml+xml";
    
    final static String textplain   = "text/plain";
    
    final static String textcss   = "text/css";

    final static String textunknwon = "text/unknown";

    final static String soap12      = "application/soap+xml";

    final static String json      = "application/json";

    final static String server_name = "Jigsaw/2.2.5 "
	+ "W3C_CSS_Validator_JFouffa/2.0";

    final static String headers_name = "X-W3C-Validator-";
    /**
     * Create a new CssValidator.
     */
    public CssValidator() {
    }

    /**
     * Initializes the servlet and logs the initialization. The init method is
     * called once, automatically, by the network service each time it loads
     * the servlet. It is guaranteed to finish before any service requests are
     * accepted. On fatal initialization errors, an UnavailableException should
     * be thrown. Do not call the method System.exit.
     *
     * 

* The init method stores the ServletConfig object. Servlet writers who * specialize this method should call either super.init, or store the * ServletConfig object themselves. If an implementor decides to store the * ServletConfig object in a different location, then the getServletConfig * method must also be overridden. * *

*

* Init parameters: *
debug *
true if you want to be in debug mode. *
aural *
true if you want to be in aural mode. *
import *
false if you don't want to activate the import * statement. For security reasons, you shoud be careful when you lunch the * servlet on a HTTP server with special access authorization. *
input *
html if the user have an HTML input or * xml otherwise. deprecated *
* * @param config * servlet configuration information. * @exception ServletException * if a servlet exception has occurred. */ public void init(ServletConfig config) throws ServletException { super.init(config); // [SECURITY] don't forget this ! Util.servlet = true; if (config.getInitParameter("debug") != null) { // servlet debug mode // define a boolean property CSS.StyleSheet.debug if you want more // debug. Util.onDebug = config.getInitParameter("debug").equals("true"); System.err.println("RUN IN DEBUG MODE: " + config.getInitParameter("debug").equals("true")); } else if (Util.onDebug) { System.err.println("RUN IN DEBUG MODE"+ " but activated outside the servlet"); } if ((config.getInitParameter("import") != null) && (config.getInitParameter("import").equals("false"))) { Util.importSecurity = true; } // The following code will check if the index files are missing or outdated // If so, the files will be regenerated // This is done in a Thread so that the validation can carry on. new Thread () { public void run () { IndexGenerator.generatesIndex(true); } }.start(); } private PrintWriter getLocalPrintWriter(OutputStream os, String encoding) throws IOException { if (encoding != null) { return new PrintWriter(new OutputStreamWriter(os, encoding)); } else { return new PrintWriter(new OutputStreamWriter(os, Utf8Properties.ENCODING)); } } /** * Performs the HTTP GET operation. * An HTTP BAD_REQUEST error is reported if * an error occurs. This servlet writers shouldn't set the headers for the * requested entity (content type and encoding). * *

* Note that the GET operation is expected to be safe, without * any side effects for which users might be held responsible. For example, * most form queries have no side effects. Requests intended to change * stored data should use some other HTTP method. (There have been cases of * significant security breaches reported because web-based applications * used GET inappropriately.) * *

* The GET operation is also expected to be idempotent, meaning * that it can safely be repeated. This is not quite the same as being * safe, but in some common examples the requirements have the same result. * For example, repeating queries is both safe and idempotent * (unless payment is required!), but buying something or modifying data * is neither safe nor idempotent. * *

*

* Forms parameters: *
URL *
the URL to be parsed. *
submitURL *
if the user want to parse an URL. *
text *
The text to be parsed. *
submitTEXT *
if the user want to parse the text. *
output *
HTML if the user want an HTML output or XML otherwise. *
input *
HTML if the user have an HTML input or XML otherwise. *
* * @param req * encapsulates the request to the servlet. * @param res * encapsulates the response from the servlet. * @exception ServletException * if the request could not be handled. * @exception IOException * if detected when handling the request. * @see org.w3c.css.css.StyleSheetGenerator */ public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { boolean errorReport = true; int warningLevel = 2; CssParser parser = null; String lang = null; try { lang = req.getParameter("lang"); } catch(Exception e) { lang = null; } if(lang == null || lang.equals("")) { lang = req.getHeader("Accept-Language"); } else { lang += ',' + req.getHeader("Accept-Language"); } ApplContext ac = new ApplContext(lang); ac.setLink(req.getQueryString()); ac.setContentEncoding(req.getHeader("Accept-Charset")); String output = req.getParameter("output"); String uri = null; try { uri = req.getParameter("uri"); // null if the parameter does not // exist } catch (Exception ex) { // pb in URI decoding (bad escaping, most probably) handleError(res, ac, output, "No file", new IOException( "Invalid escape sequence in URI"), false); } String text = null; try { text = req.getParameter("text"); } catch (Exception ex) { // pb in URI decoding (bad escaping, most probably) // not sure it will work here, as it may be catched by the first // getParameter call handleError(res, ac, output, "Invalid text", new IOException( "Invalid escape sequence in URI"), false); } String warning = req.getParameter("warning"); String error = req.getParameter("error"); String profile = req.getParameter("profile"); String usermedium = req.getParameter("usermedium"); String type = req.getParameter("type"); if (type == null) type = "none"; String credential = req.getHeader("Authorization"); if ((credential != null) && (credential.length() > 1)) { ac.setCredential(credential); } if (usermedium == null || "".equals(usermedium)) { usermedium = "all"; } InputStream in = req.getInputStream(); ac.setMedium(usermedium); if (req.getParameter("debug") != null) { Util.onDebug = req.getParameter("debug").equals("true"); if (Util.onDebug) { System.err.println("SWITCH DEBUG MODE REQUEST"); } } else { Util.onDebug = false; } //text = Util.suppressWhiteSpace(text); uri = Util.suppressWhiteSpace(uri); if (output == null) { output = texthtml; } // CSS version if (profile != null && (!"none".equals(profile) || "".equals(profile))) { if ("css1".equals(profile) || "css2".equals(profile) || "css21".equals(profile) || "css3".equals(profile) || "svg".equals(profile) || "svgbasic".equals(profile) || "svgtiny".equals(profile)) { ac.setCssVersion(profile); } else { ac.setProfile(profile); ac.setCssVersion(PropertiesLoader.config.getProperty("defaultProfile")); } } else { ac.setProfile("none"); ac.setCssVersion(PropertiesLoader.config.getProperty("defaultProfile")); } if (Util.onDebug) { System.err.println("[DEBUG] profile is : " + ac.getCssVersion() + " medium is " + usermedium); } // verify the request if ((uri == null) && (text == null)) { // res.sendError(res.SC_BAD_REQUEST, // "You have send an invalid request."); handleError(res, ac, output, "No file", new IOException(ac.getMsg().getServletString("invalid-request")), false); return; } in.close(); // set the warning output if (warning != null) { if (warning.equals("no")) { warningLevel = -1; } else { try { warningLevel = Integer.parseInt(warning); } catch (Exception e) { System.err.println(e); } } ac.setWarningLevel(warningLevel); } // set the error report if (error != null && error.equals("no")) { errorReport = false; } // debug mode Util.verbose("\nServlet request "); if (uri != null) { Util.verbose("Source file : " + uri); } else { Util.verbose("TEXTAREA Input"); } // verbose("From " + req.getRemoteHost() + // " (" + req.getRemoteAddr() + ") at " + (new Date()) ); if (uri != null) { // HTML document try { uri = HTTPURL.getURL(uri).toString(); // needed to be sure // that it is a valid // url uri = uri.replaceAll(" ", "%20"); DocumentParser URLparser = new DocumentParser(ac, uri); handleRequest(ac, res, uri, URLparser.getStyleSheet(), output, warningLevel, errorReport); } catch (ProtocolException pex) { if (Util.onDebug) { pex.printStackTrace(); } res.setHeader("WWW-Authenticate", pex.getMessage()); res.sendError(HttpServletResponse.SC_UNAUTHORIZED); } catch (Exception e) { handleError(res, ac, output, uri, e, true); } } else if (text != null) { String fileName = "TextArea"; Util.verbose("- " + fileName + " Data -"); Util.verbose(text); Util.verbose("- End of " + fileName + " Data"); InputStream is = new ByteArrayInputStream(text.getBytes()); fileName = "file://localhost/" + fileName; try { if ("css".equals(type) || ( "none".equals(type) && isCSS(text))) { // if CSS: parser = new StyleSheetParser(); parser.parseStyleElement(ac, is, null, usermedium, new URL(fileName), 0); handleRequest(ac, res, fileName, parser .getStyleSheet(), output, warningLevel, errorReport); } else { // else, trying HTML TagSoupStyleSheetHandler handler = new TagSoupStyleSheetHandler(null, ac); handler.parse(is, fileName); handleRequest(ac, res, fileName, handler.getStyleSheet(), output, warningLevel, errorReport); } } catch (ProtocolException pex) { if (Util.onDebug) { pex.printStackTrace(); } res.setHeader("WWW-Authenticate", pex.getMessage()); res.sendError(HttpServletResponse.SC_UNAUTHORIZED); } catch (Exception e) { handleError(res, ac, output, fileName, e, false); } } Util.verbose("CssValidator: Request terminated.\n"); } /** * This method is used for the direct input * If the <style> tag is found, it may be an HTML entry * The exception is when this tag is inside comment * It might also be an HTML document with no CSS => why ? * Or with only imports (we can't chack thoses imports...) * @param text, the textarea to test * @return false if it contains the style tag well formed */ private boolean isCSS(String text) { try { text = text.toLowerCase(); int p = text.indexOf(" text.indexOf(""); } catch (Exception e) { System.err.println("error: " + e.getMessage()); return true; } } /** * Performs the HTTP POST operation. An HTTP BAD_REQUEST error is reported * if an error occurs. The headers that are set should include content type, * length, and encoding. Setting content length allows the servlet to take * advantage of HTTP "connection keep alive". If content length can not be * set in advance, the performance penalties associated with not using keep * alives will sometimes be avoided if the response entity fits in an * internal buffer. The servlet implementor must write the headers before * the response data because the headers can be flushed at any time after * the data starts to be written. * *

* This method does not need to be either "safe" or "idempotent". Operations * requested through POST could be ones for which users need to be held * accountable. Specific examples including updating stored data or buying * things online. * *

*

* Forms parameters: *
file *
The input file to be parsed. *
output *
The format output. *
input *
HTML if the user have an HTML input or XML otherwise. *
* * @param req * encapsulates the request to the servlet * @param res * encapsulates the response from the servlet * @exception ServletException * if the request could not be handled * @exception IOException * if detected when handling the request * @see org.w3c.css.css.StyleSheetGenerator */ public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String lang = null; try { lang = req.getParameter("lang"); } catch(Exception e) { lang = null; } boolean errorReport = true; int warningLevel = 2; CssParser parser = null; FakeFile file = null; String text = null; String output = null; //boolean XMLinput = false; String warning = null; String error = null; String profile = "none"; String usermedium = "all"; ServletInputStream in = req.getInputStream(); byte[] buf = new byte[2048]; byte[] general = new byte[65536]; int count = 0; int len; if (req.getParameter("debug") != null) { Util.onDebug = req.getParameter("debug").equals("true"); if (Util.onDebug) { System.err.println("SWITCH DEBUG MODE REQUEST"); } } else { Util.onDebug = false; } Util.verbose("\nCssValidator: Servlet request "); // verbose("From " + req.getRemoteHost() + // " (" + req.getRemoteAddr() + ") at " + (new Date()) ); Util.verbose("Content-length : " + req.getContentLength()); if (req.getContentType().trim().startsWith("multipart/form-data")) { Util.verbose("Content-type : multipart/form-data"); } try { while ((len = in.readLine(buf, 0, buf.length)) != -1) { if (len >= 2 && buf[len - 1] == '\n' && buf[len - 2] == '\r') { len -= 1; buf[len - 1] = (byte) '\n'; } if (len != 0 && buf[len - 1] == '\r') { buf[len - 1] = (byte) '\n'; } if (general.length < (count + len)) { byte[] old = general; general = new byte[old.length * 2]; System.arraycopy(old, 0, general, 0, old.length); } System.arraycopy(buf, 0, general, count, len); count += len; } } finally { in.close(); } try { buf = new byte[count]; System.arraycopy(general, 0, buf, 0, count); NVPair[] tmp = Codecs.mpFormDataDecode(buf, req.getContentType()); for (int i = 0; i < tmp.length; i++) { if (tmp[i].getName().equals("file")) { file = (FakeFile) tmp[i].getValue(); } else if (tmp[i].getName().equals("text")) { text = (String) tmp[i].getValue(); } else if (tmp[i].getName().equals("lang")) { lang = (String) tmp[i].getValue(); } else if (tmp[i].getName().equals("output")) { output = (String) tmp[i].getValue(); } else if (tmp[i].getName().equals("warning")) { warning = (String) tmp[i].getValue(); } else if (tmp[i].getName().equals("error")) { warning = (String) tmp[i].getValue(); //} else if (tmp[i].getName().equals("input")) { // XMLinput = ((String) tmp[i].getValue()).equals("XML"); } else if (tmp[i].getName().equals("profile")) { profile = (String) tmp[i].getValue(); } else if (tmp[i].getName().equals("usermedium")) { usermedium = (String) tmp[i].getValue(); if (usermedium == null || "".equals(usermedium)) { usermedium = "all"; } } } } catch (Exception e) { System.out.println("Oups! Error in Util/Codecs.java?!?"); e.printStackTrace(); } if(lang == null || lang.equals("")) { lang = req.getHeader("Accept-Language"); } else { lang += ',' + req.getHeader("Accept-Language"); } ApplContext ac = new ApplContext(lang); ac.setLink(req.getQueryString()); ac.setMedium(usermedium); if (output == null) { output = texthtml; } if ((file == null || file.getSize() == 0) && (text == null || text.length() == 0)) { // res.sendError(res.SC_BAD_REQUEST, // "You have send an invalid request"); handleError(res, ac, output, "No file", new IOException(ac.getMsg().getServletString( "invalid-request")), false); return; } // set the warning output if (warning != null) { if (warning.equals("no")) { warningLevel = -1; } else { try { warningLevel = Integer.parseInt(warning); } catch (Exception e) { System.err.println(e); } } ac.setWarningLevel(warningLevel); } // set the error report if (error != null && error.equals("no")) { errorReport = false; } // CSS version if (profile != null && (!"none".equals(profile) ||"".equals(profile))) { if ("css1".equals(profile) || "css2".equals(profile) || "css21".equals(profile) || "css3".equals(profile) || "svg".equals(profile) || "svgbasic".equals(profile) || "svgtiny".equals(profile)) { ac.setCssVersion(profile); } else { ac.setProfile(profile); ac.setCssVersion(PropertiesLoader.config.getProperty( "defaultProfile")); } } else { ac.setProfile("none"); ac.setCssVersion(PropertiesLoader.config.getProperty( "defaultProfile")); } String fileName = ""; InputStream is = null; boolean isCSS = false; if (file != null && file.getSize() != 0) { ac.setFakeFile(file); fileName = file.getName(); Util.verbose("File : " + fileName); // another way to get file type... isCSS = file.getContentType().equals(textcss); } else if (text != null ) { ac.setFakeText(text); fileName = "TextArea"; Util.verbose("- " + fileName + " Data -"); Util.verbose(text); Util.verbose("- End of " + fileName + " Data"); //quick test that works in most cases to determine wether it's //HTML or CSS isCSS = isCSS(text); } fileName = "file://localhost/" + fileName; try { URL u = new URL(fileName); is = ac.getFakeInputStream(u); ac.setFakeURL(fileName); if (isCSS) { //if CSS: parser = new StyleSheetParser(); parser.parseStyleElement(ac, is, null, usermedium, new URL(fileName), 0); handleRequest(ac, res, fileName, parser.getStyleSheet(), output, warningLevel, errorReport); } else { // else, trying HTML TagSoupStyleSheetHandler handler; handler = new TagSoupStyleSheetHandler(null, ac); handler.parse(is, fileName); handleRequest(ac, res, fileName, handler.getStyleSheet(), output, warningLevel, errorReport); } } catch (ProtocolException pex) { if (Util.onDebug) { //pex.printStackTrace(); } res.setHeader("WWW-Authenticate", pex.getMessage()); res.sendError(HttpServletResponse.SC_UNAUTHORIZED); } catch (Exception e) { handleError(res, ac, output, fileName, e, false); } Util.verbose("CssValidator: Request terminated.\n"); } private void handleRequest(ApplContext ac, HttpServletResponse res, String title, StyleSheet styleSheet, String output, int warningLevel, boolean errorReport) throws Exception { buildHeader(ac, res, output); if (styleSheet == null) { throw new IOException(ac.getMsg().getServletString("process") + " " + title); } // if the output parameter was a mime type, we convert it // to an understandable value for the StyleReportFactory if ("text/xml".equals(ac.getInput()) && texthtml.equals(output)) { output = "xhtml"; } else if (texthtml.equals(output)) { output = "html"; } else if (soap12.equals(output)) { output = "soap12"; } else if (json.equals(output)) { output = "json"; } else if(textplain.equals(output)) { output = "text"; } styleSheet.findConflicts(ac); StyleReport style = StyleReportFactory.getStyleReport(ac, title, styleSheet, output, warningLevel); if (!errorReport) { style.desactivateError(); } PrintWriter out = getLocalPrintWriter(res.getOutputStream(), ac .getContentEncoding()); int nb_errors = styleSheet.getErrors().getErrorCount(); res.setHeader(headers_name + "Errors", String.valueOf(nb_errors)); res.setHeader(headers_name + "Status", nb_errors == 0 ? "Valid" : "Invalid"); try { style.print(out); } finally { out.close(); } } /** * Generates the response header * @param ac * @param res * @param output * @throws MimeTypeFormatException */ private void buildHeader(ApplContext ac, HttpServletResponse res, String output) { // I don't want cache for the response (inhibits proxy) res.setHeader("Pragma", "no-cache"); // @@deprecated res.setHeader("Cache-Control", "no-cache"); // Here is a little joke :-) // res.setHeader("Server", server_name); if(output == null) { output = new String(texthtml); } // set the content-type for the response MimeType outputMt = null; if (output.equals(texthtml) || output.equals("html")) { outputMt = MimeType.TEXT_HTML.getClone(); } else if (output.equals(applxhtml) || output.equals("xhtml")) { outputMt = MimeType.APPLICATION_XHTML_XML.getClone(); } else if (output.equals(soap12) || output.equals("soap12")) { // invert the comments on the following lines to (de)activate // the soap Mime Type try { outputMt = new MimeType(soap12); } catch (MimeTypeFormatException e) { outputMt = MimeType.TEXT_PLAIN.getClone(); } //outputMt = MimeType.TEXT_PLAIN.getClone(); } else if(output.equals("ucn")) { outputMt = MimeType.APPLICATION_XML.getClone(); } else if(output.equals("json")) { try { outputMt = new MimeType(json); } catch (MimeTypeFormatException e) { outputMt = MimeType.TEXT_PLAIN.getClone(); } } else { // Change this line if you want text/html output when incorrect // output is passed outputMt = MimeType.TEXT_PLAIN.getClone(); } if(ac != null) { // ignore content encoding if output is SOAP if(output.equals("soap12")) { ac.setContentEncoding(null); } if (ac.getContentEncoding() != null) { outputMt.setParameter("charset", ac.getContentEncoding()); } res.setContentType(outputMt.toString()); if (ac.getContentLanguage() != null) { res.setHeader("Content-Language", ac.getContentLanguage()); } else { res.setHeader("Content-Language", "en"); } } else { res.setHeader("Content-Language", "en"); res.setHeader("charset", Utf8Properties.ENCODING); } res.setHeader("Vary", "Accept-Language"); } private void handleError(HttpServletResponse res, ApplContext ac, String output, String title, Exception e, boolean validURI) throws IOException { System.err.println("[ERROR VALIDATOR] " + title); System.err.println(e.toString()); e.printStackTrace(); buildHeader(ac, res, output); res.setStatus(500); if((e instanceof java.net.UnknownHostException) || ((e instanceof java.io.FileNotFoundException) && ((e.getMessage().indexOf("Not Found") != -1) || (e.getMessage().indexOf("Service Unavailable") != -1)))) { validURI = true; } else { validURI = false; } PrintWriter out = getLocalPrintWriter(res.getOutputStream(), ac .getContentEncoding()); ErrorReport error = ErrorReportFactory.getErrorReport(ac, title, output, e, validURI); res.setHeader(headers_name + "Status", "Abort"); try { error.print(out); } finally { out.close(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy