/** * Attempts to send an internal server error HTTP error, if possible. Otherwise simply pushes the * exception message to the output stream. * * @param message Message to be printed to the logger and to the output stream. * @param t Exception that caused the error. */ protected void filterError(String message, Throwable t) { log.error("XSLT filter error: " + message, t); if (false == origResponse.isCommitted()) { // Reset the buffer and previous status code. origResponse.reset(); origResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); origResponse.setContentType("text/html; charset=UTF-8"); } // Response committed. Just push the error to the output stream. try { final OutputStream os = origResponse.getOutputStream(); final PrintWriter osw = new PrintWriter(new OutputStreamWriter(os, "iso8859-1")); osw.write("<html><body><!-- " + XSLTFilterConstants.ERROR_TOKEN + " -->"); osw.write("<h1 style=\"color: red; margin-top: 1em;\">"); osw.write("Internal server exception"); osw.write("</h1>"); osw.write("<b>URI</b>: " + origRequest.getRequestURI() + "\n<br/><br/>"); serializeException(osw, t); if (t instanceof ServletException && ((ServletException) t).getRootCause() != null) { osw.write("<br/><br/><h2>ServletException root cause:</h2>"); serializeException(osw, ((ServletException) t).getRootCause()); } osw.write("</body></html>"); osw.flush(); } catch (IOException e) { // Not much to do in such case (connection broken most likely). log.debug("Filter error could not be returned to client."); } }
/** * Return the character output stream for this response. This is either the original stream or a * buffered stream. * * @exception IllegalStateException Thrown when byte stream has been already initialized ({@link * #getOutputStream()}). */ public PrintWriter getWriter() throws IOException { if (stream != null) { throw new IllegalStateException( "Byte stream has been already initialized. Use streams consequently."); } if (writer != null) { return writer; } if (passthrough) { writer = this.origResponse.getWriter(); return writer; } /* * TODO: The character encoding should be extracted in {@link #setContentType()}, * saved somewhere locally and used here. The response's character encoding may be * different (depends on the stylesheet). */ final String charEnc = origResponse.getCharacterEncoding(); this.stream = new DeferredOutputStream(); if (charEnc != null) { writer = new PrintWriter(new OutputStreamWriter(stream, charEnc)); } else { writer = new PrintWriter(stream); } return writer; }
/** We override this method to detect XML data streams. */ public void setContentType(String contentType) { // Check if XSLT processing has been suppressed for this request. final boolean processingSuppressed = processingSuppressed(origRequest); if (processingSuppressed) { // Processing is suppressed. log.debug("XSLT processing disabled for the request."); } if (!processingSuppressed && (contentType.startsWith("text/xml") || contentType.startsWith("application/xml"))) { /* * We have an XML data stream. Set the real response to proper content type. * TODO: Should we make the encoding a configurable setting? */ origResponse.setContentType("text/html; charset=UTF-8"); } else { /* * The input is something we won't process anyway, so simply passthrough all * data directly to the output stream. */ if (!processingSuppressed) { log.info( "Content type is not text/xml or application/xml (" + contentType + "), passthrough."); } origResponse.setContentType(contentType); passthrough = true; // If the output stream is already initialized, passthrough everything. if (stream != null && stream instanceof DeferredOutputStream) { try { ((DeferredOutputStream) stream).passthrough(origResponse.getOutputStream()); } catch (IOException e) { ((DeferredOutputStream) stream).setExceptionOnNext(e); } } } }
/** * Return the byte output stream for this response. This is either the original stream or a * buffered stream. * * @exception IllegalStateException Thrown when character stream has been already initialized * ({@link #getWriter()}). */ public ServletOutputStream getOutputStream() throws IOException { if (writer != null) { throw new IllegalStateException( "Character stream has been already initialized. Use streams consequently."); } if (stream != null) { return stream; } if (passthrough) { stream = origResponse.getOutputStream(); } else { stream = new DeferredOutputStream(); } return stream; }
/** * This method must be invoked at the end of processing. The streams are closed and their content * is analyzed. Actual XSLT processing takes place here. */ @SuppressWarnings("unchecked") void finishResponse() throws IOException { if (writer != null) { writer.close(); } else { if (stream != null) stream.close(); } /* * If we're not in passthrough mode, then we need to finalize XSLT transformation. */ if (false == passthrough) { if (stream != null) { final byte[] bytes = ((DeferredOutputStream) stream).getBytes(); final boolean processingSuppressed = (origRequest.getAttribute(XSLTFilterConstants.NO_XSLT_PROCESSING) != null) | (origRequest.getParameter(XSLTFilterConstants.NO_XSLT_PROCESSING) != null); if (processingSuppressed) { // Just copy the buffered data to the output directly. final OutputStream os = origResponse.getOutputStream(); os.write(bytes); os.close(); } else { // Otherwise apply XSLT transformation to it. try { processWithXslt( bytes, (Map<String, Object>) origRequest.getAttribute(XSLTFilterConstants.XSLT_PARAMS_MAP), origResponse); } catch (TransformerException e) { final Throwable t = unwrapCause(e); if (t instanceof IOException) { throw (IOException) t; } filterError("Error applying stylesheet.", e); } } } } }