w3c.css.servlet.CssValidator Maven / Gradle / Ivy
//
// $Id$
// 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.util.ApplContext;
import org.w3c.css.util.Codecs;
import org.w3c.css.util.CssVersion;
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$
*/
@SuppressWarnings("serial")
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 textunknown = "text/unknown";
final static String soap12 = "application/soap+xml";
final static String json = "application/json";
final static String opt_file = "file";
final static String opt_text = "text";
final static String opt_lang = "lang";
final static String opt_output = "output";
final static String opt_warning = "warning";
final static String opt_error = "error";
final static String opt_profile = "profile";
final static String opt_usermedium = "usermedium";
final static String opt_vextwarning = "vextwarning";
final static String opt_type = "type";
public final static String server_name =
"Jigsaw/2.3.0 W3C_CSS_Validator_JFouffa/2.0 (See )";
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.
* @throws ServletException if a servlet exception has occurred.
*/
public void init(ServletConfig config) throws ServletException {
String pval;
super.init(config);
// [SECURITY] don't forget this !
Util.servlet = true;
pval = config.getInitParameter("debug");
if (pval != null && !pval.isEmpty()) {
// servlet debug mode
// define a boolean property CSS.StyleSheet.debug if you want more
// debug.
Util.onDebug = pval.equals("true");
System.err.println("RUN IN DEBUG MODE: "
+ Util.onDebug);
} else if (Util.onDebug) {
System.err.println("RUN IN DEBUG MODE" +
" but activated outside the servlet");
}
pval = config.getInitParameter("import");
if (pval != null && !pval.isEmpty() && pval.equals("false")) {
Util.importSecurity = true;
}
pval = config.getInitParameter("entitysize");
if (pval != null && !pval.isEmpty()) {
try {
Util.maxEntitySize = Long.parseLong(pval);
} catch (NumberFormatException nfe) {
// the definition was wrong
nfe.printStackTrace();
}
}
// 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));
}
}
private void processVendorExtensionParameter(
String vendorExtensionParameter, ApplContext context) {
if (vendorExtensionParameter == null ||
vendorExtensionParameter.isEmpty()) {
vendorExtensionParameter =
getServletConfig().getInitParameter("vendorExtensionsAsWarnings");
}
context.setTreatVendorExtensionsAsWarnings(Boolean.valueOf(vendorExtensionParameter));
// TODO for now we use the same parameter for both vendor extensions and CSS Hacks.
context.setTreatCssHacksAsWarnings(Boolean.valueOf(vendorExtensionParameter));
}
/**
* 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.
* @throws ServletException if the request could not be handled.
* @throws 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(opt_lang);
} catch (Exception e) {
lang = null;
}
if (lang == null || lang.isEmpty()) {
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(opt_output);
String uri = null;
try {
uri = req.getParameter("uri"); // null if the parameter does not exist
// 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(opt_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(opt_warning);
String error = req.getParameter(opt_error);
String profile = req.getParameter(opt_profile);
String usermedium = req.getParameter(opt_usermedium);
String type = req.getParameter(opt_type);
InputStream in = req.getInputStream();
if (type == null)
type = "none";
String credential = req.getHeader("Authorization");
if ((credential != null) && (credential.length() > 1)) {
ac.setCredential(credential);
}
// CSS version
ac.setCssVersionAndProfile(profile);
// media, only if we are not using CSS1
if (ac.getCssVersion() != CssVersion.CSS1) {
if (usermedium == null || usermedium.isEmpty()) {
usermedium = "all";
}
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;
}
if (Util.onDebug) {
System.err.println("[DEBUG] version is : " + ac.getCssVersionString()
+ " profile is " + ac.getProfileString()
+ " 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;
}
// Allow vendor extensions to just show up as warnings.
processVendorExtensionParameter(req.getParameter(opt_vextwarning), ac);
// 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");
if (Util.checkURI(uri)) {
DocumentParser URLparser = new DocumentParser(ac, uri);
handleRequest(ac, res, uri, URLparser.getStyleSheet(), output,
warningLevel, errorReport);
} else {
res.setHeader("Rejected", "Requested URI Forbidden by Rule");
handleError(res, ac, output, "Forbidden", new IOException(
"URI Forbidden by rule"), false);
}
} 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
// HTMLParserStyleSheetHandler handler = new HTMLParserStyleSheetHandler(null, ac);
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("");
} 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
* @throws ServletException if the request could not be handled
* @throws 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";
String vendorExtensionAsWarnings = null;
String inputType = "none";
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);
for (NVPair pair : Codecs.mpFormDataDecode(buf, req.getContentType())) {
switch (pair.getName()) {
case opt_file:
file = (FakeFile) pair.getValue();
break;
case opt_text:
text = (String) pair.getValue();
break;
case opt_lang:
lang = (String) pair.getValue();
break;
case opt_output:
output = (String) pair.getValue();
break;
case opt_warning:
warning = (String) pair.getValue();
break;
case opt_error:
error = (String) pair.getValue();
break;
case opt_profile:
profile = (String) pair.getValue();
break;
case opt_usermedium:
usermedium = (String) pair.getValue();
break;
case opt_vextwarning:
vendorExtensionAsWarnings = (String) pair.getValue();
break;
case opt_type:
inputType = (String) pair.getValue();
break;
default:
// log extra parameters?
}
}
} catch (Exception e) {
System.out.println("Oups! Error in Util/Codecs.java?!?");
e.printStackTrace();
}
if (lang == null || lang.isEmpty()) {
lang = req.getHeader("Accept-Language");
} else {
lang += ',' + req.getHeader("Accept-Language");
}
ApplContext ac = new ApplContext(lang);
ac.setLink(req.getQueryString());
if (output == null) {
output = texthtml;
}
// 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;
}
// Allow vendor extensions to just show up as warnings.
processVendorExtensionParameter(vendorExtensionAsWarnings, ac);
ac.setCssVersionAndProfile(profile);
if (ac.getCssVersion() == CssVersion.CSS1) {
if (usermedium != null && !"all".equals(usermedium)) {
// explicitly set to a non -default value
// let's raise an issue later.
ac.setMedium(usermedium);
}
} else {
if (usermedium == null || usermedium.isEmpty()) {
usermedium = "all";
}
ac.setMedium(usermedium);
}
// CSS version
String fileName = "";
InputStream is = null;
boolean isCSS = false;
if (file != null) {
isCSS = file.getContentType().equals(textcss);
if (file.getSize() == 0) {
file.write("\n".getBytes(), 0, 1);
isCSS = true;
}
ac.setFakeFile(file);
fileName = file.getName();
Util.verbose("File : " + fileName);
} else {
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
// TODO hardcode options using defined strings instead of in the code
switch (inputType) {
case "css":
isCSS = true;
break;
case "html":
isCSS = false;
break;
case "none":
default:
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, ac.getMedium(),
new URL(fileName), 0);
handleRequest(ac, res, fileName, parser.getStyleSheet(),
output, warningLevel, errorReport);
} else {
// else, trying HTML
// HTMLParserStyleSheetHandler handler = new HTMLParserStyleSheetHandler(null, ac);
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");
}
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);
}
String outformat;
// if the output parameter was a mime type, we convert it
// to an understandable value for the StyleReportFactory
switch (output) {
case texthtml:
outformat = ("text/xml".equals(ac.getInput())) ? "xhtml" : "html";
break;
case soap12:
outformat = soap12;
break;
case json:
outformat = "json";
break;
case textplain:
outformat = "text";
break;
default:
outformat = output;
}
styleSheet.findConflicts(ac);
StyleReport style = StyleReportFactory.getStyleReport(ac, title,
styleSheet, outformat, 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");
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "content-type,accept-charset");
res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, OPTIONS");
res.setHeader("Access-Control-Max-Age", "600");
}
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 - 2025 Weber Informatics LLC | Privacy Policy