001 /**
002 * GRANITE DATA SERVICES
003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 * This file is part of the Granite Data Services Platform.
006 *
007 * Granite Data Services is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * Granite Data Services is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 * General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 * USA, or see <http://www.gnu.org/licenses/>.
021 */
022 package org.granite.messaging.webapp;
023
024 import java.io.ByteArrayInputStream;
025 import java.io.ByteArrayOutputStream;
026 import java.io.File;
027 import java.io.FileOutputStream;
028 import java.io.IOException;
029 import java.io.InputStream;
030 import java.io.OutputStream;
031
032 import javax.servlet.Filter;
033 import javax.servlet.FilterChain;
034 import javax.servlet.FilterConfig;
035 import javax.servlet.ServletException;
036 import javax.servlet.ServletInputStream;
037 import javax.servlet.ServletOutputStream;
038 import javax.servlet.ServletRequest;
039 import javax.servlet.ServletResponse;
040 import javax.servlet.http.HttpServletRequest;
041 import javax.servlet.http.HttpServletRequestWrapper;
042 import javax.servlet.http.HttpServletResponse;
043 import javax.servlet.http.HttpServletResponseWrapper;
044
045 import org.granite.logging.Logger;
046 import org.granite.util.ServletParams;
047
048 /**
049 * @author Franck WOLFF
050 */
051 public class DumpFilter implements Filter {
052
053 private static final Logger log = Logger.getLogger(DumpFilter.class);
054 private static final String HEXS = "0123456789ABCDEF";
055 private static final String DUMP_DIR = "dumpDir";
056
057 File dumpDir = null;
058
059 public void init(FilterConfig config) throws ServletException {
060 String dumpDirString = ServletParams.get(config, DUMP_DIR, String.class, null);
061 if (dumpDirString != null) {
062 File dumpDir = new File(dumpDirString);
063 if (!dumpDir.exists() || !dumpDir.isDirectory() || !dumpDir.canWrite())
064 log.warn("Ignoring dump directory (is it a writable directory?): %s", dumpDir);
065 else
066 this.dumpDir = dumpDir;
067 }
068 }
069
070 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
071 throws IOException, ServletException {
072
073 DumpRequestWrapper requestWrapper = new DumpRequestWrapper((HttpServletRequest)request);
074 DumpResponseWrapper responseWrapper= new DumpResponseWrapper((HttpServletResponse)response);
075
076 dumpBytes("request", requestWrapper.getBytes());
077 chain.doFilter(requestWrapper, responseWrapper);
078 dumpBytes("response", responseWrapper.getBytes());
079 }
080
081 public void destroy() {
082 dumpDir = null;
083 }
084
085 private void dumpBytes(String label, byte[] bytes) {
086 StringBuilder hexSb = new StringBuilder();
087 StringBuilder charSb = new StringBuilder();
088
089 for (int i = 0; i < bytes.length; i++) {
090 int b = bytes[i] & 0xFF;
091 if (hexSb.length() > 0) {
092 hexSb.append(' ');
093 charSb.append(' ');
094 }
095 hexSb.append(HEXS.charAt(b >> 4)).append(HEXS.charAt(b & 0x0F));
096 if (b >= 0x20 && b <= 0x7e)
097 charSb.append(' ').append((char)b);
098 else
099 charSb.append("##");
100 }
101
102 log.info("[RAW %s] {\n%s\n%s\n}", label.toUpperCase(), hexSb.toString(), charSb.toString());
103
104 if (dumpDir != null) {
105 File file = new File(dumpDir.getPath() + File.separator + label + "_" + System.currentTimeMillis() + ".amf");
106 for (int i = 1; i < 100 && file.exists(); i++)
107 file = new File(file.getAbsolutePath() + "." + i);
108
109 OutputStream os = null;
110 try {
111 os = new FileOutputStream(file);
112 os.write(bytes);
113 } catch (Exception e) {
114 log.error(e, "Could not write dump file: %s", file);
115 } finally {
116 if (os != null) try {
117 os.close();
118 } catch (Exception e) {
119 }
120 }
121 }
122 }
123
124 class DumpRequestWrapper extends HttpServletRequestWrapper {
125
126 private byte[] bytes = null;
127
128 public DumpRequestWrapper(HttpServletRequest request) throws IOException {
129 super(request);
130
131 setCharacterEncoding("UTF-8");
132
133 InputStream is = null;
134 try {
135 is = request.getInputStream();
136
137 ByteArrayOutputStream out = new ByteArrayOutputStream(128);
138 for (int b = is.read(); b != -1; b = is.read())
139 out.write(b);
140
141 this.bytes = out.toByteArray();
142 } catch (Exception e) {
143 throw new RuntimeException(e);
144 }
145 }
146
147 @Override
148 public ServletInputStream getInputStream() throws IOException {
149
150 final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
151
152 return new ServletInputStream() {
153 @Override
154 public int read() throws IOException {
155 return bais.read();
156 }
157 };
158 }
159
160 public byte[] getBytes() {
161 return bytes;
162 }
163 }
164
165 class DumpResponseWrapper extends HttpServletResponseWrapper {
166
167 private ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
168 private ServletOutputStream out = null;
169
170 public DumpResponseWrapper(HttpServletResponse response) throws IOException {
171 super(response);
172 this.out = response.getOutputStream();
173 }
174
175 @Override
176 public ServletOutputStream getOutputStream() throws IOException {
177
178 return new ServletOutputStream() {
179 @Override
180 public void write(int b) throws IOException {
181 baos.write(b);
182 out.write(b);
183 }
184 };
185 }
186
187 public byte[] getBytes() {
188 return baos.toByteArray();
189 }
190 }
191 }