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 021package org.granite.messaging.webapp; 022 023import java.io.ByteArrayInputStream; 024import java.io.ByteArrayOutputStream; 025import java.io.File; 026import java.io.FileOutputStream; 027import java.io.IOException; 028import java.io.InputStream; 029import java.io.OutputStream; 030 031import javax.servlet.Filter; 032import javax.servlet.FilterChain; 033import javax.servlet.FilterConfig; 034import javax.servlet.ServletException; 035import javax.servlet.ServletInputStream; 036import javax.servlet.ServletOutputStream; 037import javax.servlet.ServletRequest; 038import javax.servlet.ServletResponse; 039import javax.servlet.http.HttpServletRequest; 040import javax.servlet.http.HttpServletRequestWrapper; 041import javax.servlet.http.HttpServletResponse; 042import javax.servlet.http.HttpServletResponseWrapper; 043 044import org.granite.logging.Logger; 045import org.granite.util.ServletParams; 046 047/** 048 * @author Franck WOLFF 049 */ 050public 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}