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