/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * 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 the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>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.apereo.portal.utils.web; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Locale; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.output.CountingOutputStream; import org.apache.commons.io.output.NullOutputStream; import org.apache.commons.io.output.NullWriter; import org.apache.commons.io.output.ProxyWriter; import org.apereo.portal.portlet.om.IPortletWindow; import org.apereo.portal.utils.DelegatingServletOutputStream; /** * Portlet response wrapper. Makes sure the portlet doesn't screw with the portal's response * * <p>Any mutator method calls are not passed on and logged at warn level. The writer/stream objects * discard all data written and log byte/char counts at warn level on close. * */ public class PortletHttpServletResponseWrapper extends AbstractHttpServletResponseWrapper { private final IPortletWindow portletWindow; private ServletOutputStream servletOutputStream; private PrintWriter printWriter; public PortletHttpServletResponseWrapper( HttpServletResponse httpServletResponse, IPortletWindow portletWindow) { super(httpServletResponse); this.portletWindow = portletWindow; } @Override public ServletOutputStream getOutputStream() throws IOException { if (this.servletOutputStream == null) { final OutputStream out; if (logger.isDebugEnabled()) { out = new ByteArrayOutputStream() { @Override public void close() throws IOException { super.close(); final byte[] data = this.toByteArray(); if (data.length > 0) { logger.warn( "Ignored {} bytes written to ServletOutputStream by {}\n\n{}", new Object[] { data.length, portletWindow, new String(data) }); } } }; } else { out = new CountingOutputStream(NullOutputStream.NULL_OUTPUT_STREAM) { @Override public void close() throws IOException { super.close(); final long byteCount = this.getByteCount(); if (byteCount > 0) { logger.warn( "Ignored {} bytes written to ServletOutputStream by {}, turn on DEBUG logging to see the output", byteCount, portletWindow); } } }; } this.servletOutputStream = new DelegatingServletOutputStream(out); } return this.servletOutputStream; } @Override public PrintWriter getWriter() throws IOException { if (this.printWriter == null) { if (logger.isDebugEnabled()) { this.printWriter = new PrintWriter( new StringWriter() { @Override public void close() throws IOException { super.close(); final String data = this.toString(); if (data.length() > 0) { logger.warn( "Ignored {} chars written to PrintWriter by {}\n\n{}", new Object[] { data.length(), portletWindow, data }); } } }); } else { this.printWriter = new PrintWriter( new ProxyWriter(NullWriter.NULL_WRITER) { private long count = 0; @Override public void close() throws IOException { super.close(); if (count > 0) { logger.warn( "Ignored {} chars written to PrintWriter by {}, turn on DEBUG logging to see the output", count, portletWindow); } } @Override protected void afterWrite(int n) throws IOException { count += n; } }); } } return this.printWriter; } @Override public void flushBuffer() throws IOException { this.logger.warn( "Ignoring call to HttpServletResponse.flushBuffer() from {}", portletWindow); } @Override public void resetBuffer() { this.logger.warn( "Ignoring call to HttpServletResponse.resetBuffer() from {}", portletWindow); } @Override public void reset() { this.logger.warn("Ignoring call to HttpServletResponse.reset() from {}", portletWindow); } @Override public void setBufferSize(int size) { this.logger.warn( "Ignoring call to HttpServletResponse.setBufferSize({}) from {}", size, portletWindow); } @Override public void setContentType(String type) { this.logger.warn( "Ignoring call to HttpServletResponse.setContentType({}) from {}", type, portletWindow); } @Override public void setStatus(int sc) { this.logger.warn( "Ignoring call to HttpServletResponse.setStatus({}) from {}", sc, portletWindow); } @Override public void setStatus(int sc, String sm) { this.logger.warn( "Ignoring call to HttpServletResponse.setStatus({}, {}) from {}", new Object[] {sc, sm, portletWindow}); } @Override public void addCookie(Cookie cookie) { this.logger.warn( "Ignoring call to HttpServletResponse.addCookie({}) from {}", cookie, portletWindow); } @Override public void sendError(int sc, String msg) throws IOException { this.logger.warn( "Ignoring call to HttpServletResponse.sendError({}, {}) from {}", new Object[] {sc, msg, portletWindow}); } @Override public void sendError(int sc) throws IOException { this.logger.warn( "Ignoring call to HttpServletResponse.sendError({}) from {}", sc, portletWindow); } @Override public void sendRedirect(String location) throws IOException { this.logger.warn( "Ignoring call to HttpServletResponse.sendRedirect({}) from {}", location, portletWindow); } @Override public void setCharacterEncoding(String charset) { this.logger.warn( "Ignoring call to HttpServletResponse.setCharacterEncoding({}) from {}", charset, portletWindow); } @Override public void setDateHeader(String name, long date) { this.logger.warn( "Ignoring call to HttpServletResponse.setDateHeader({}, {}) from {}", new Object[] {name, date, portletWindow}); } @Override public void addDateHeader(String name, long date) { this.logger.warn( "Ignoring call to HttpServletResponse.addDateHeader({}, {}) from {}", new Object[] {name, date, portletWindow}); } @Override public void setHeader(String name, String value) { this.logger.warn( "Ignoring call to HttpServletResponse.setHeader({}, {}) from {}", new Object[] {name, value, portletWindow}); } @Override public void setContentLength(int len) { this.logger.warn( "Ignoring call to HttpServletResponse.setContentLength({}) from {}", len, portletWindow); } @Override public void addHeader(String name, String value) { this.logger.warn( "Ignoring call to HttpServletResponse.addHeader({}, {}) from {}", new Object[] {name, value, portletWindow}); } @Override public void setIntHeader(String name, int value) { this.logger.warn( "Ignoring call to HttpServletResponse.setIntHeader({}, {}) from {}", new Object[] {name, value, portletWindow}); } @Override public void addIntHeader(String name, int value) { this.logger.warn( "Ignoring call to HttpServletResponse.addIntHeader({}, {}) from {}", new Object[] {name, value, portletWindow}); } @Override public void setLocale(Locale loc) { this.logger.warn( "Ignoring call to HttpServletResponse.setLocale({}) from {}", loc, portletWindow); } }