001    // This file is part of the Attempto Java Packages.
002    // Copyright 2008-2009, Attempto Group, University of Zurich (see http://attempto.ifi.uzh.ch).
003    //
004    // The Attempto Java Packages is free software: you can redistribute it and/or modify it under the
005    // terms of the GNU Lesser General Public License as published by the Free Software Foundation,
006    // either version 3 of the License, or (at your option) any later version.
007    //
008    // The Attempto Java Packages is distributed in the hope that it will be useful, but WITHOUT ANY
009    // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
010    // PURPOSE. See the GNU Lesser General Public License for more details.
011    //
012    // You should have received a copy of the GNU Lesser General Public License along with the Attempto
013    // Java Packages. If not, see http://www.gnu.org/licenses/.
014    
015    package ch.uzh.ifi.attempto.echocomp;
016    
017    import java.io.ByteArrayInputStream;
018    import java.io.ByteArrayOutputStream;
019    import java.io.IOException;
020    import java.io.UnsupportedEncodingException;
021    
022    import javax.servlet.Filter;
023    import javax.servlet.FilterChain;
024    import javax.servlet.FilterConfig;
025    import javax.servlet.ServletException;
026    import javax.servlet.ServletInputStream;
027    import javax.servlet.ServletRequest;
028    import javax.servlet.ServletResponse;
029    import javax.servlet.http.HttpServletRequest;
030    import javax.servlet.http.HttpServletRequestWrapper;
031    
032    /**
033     * This filter is a workaround for the problem that Firefox 3.0.0 to 3.0.4 somehow sends wrong
034     * XML headers to the server.
035     * See the discussion in <a href="http://echo.nextapp.com/site/node/5230" target="_blank">this thread</a>
036     * of the Echo forum.
037     * This code is inspired by the workaround proposed by the user "Nadir".
038     *<p>
039     * In order to apply this filter, the following lines have to be added to web.xml:
040     * 
041     * <pre>
042     * &lt;filter&gt;
043     *   &lt;filter-name&gt;headercontrol&lt;/filter-name&gt;
044     *   &lt;filter-class&gt;ch.uzh.ifi.attempto.echocomp.HeaderControlFilter&lt;/filter-class&gt;
045     *   &lt;init-param&gt;
046     *     &lt;param-name&gt;request.reencoding&lt;/param-name&gt;
047     *     &lt;param-value&gt;UTF-8&lt;/param-value&gt;
048     *   &lt;/init-param&gt;
049     * &lt;/filter&gt;
050     * 
051     * &lt;filter-mapping&gt;
052     *   &lt;filter-name&gt;headercontrol&lt;/filter-name&gt;
053     *   &lt;url-pattern&gt;*&lt;/url-pattern&gt;
054     * &lt;/filter-mapping&gt;
055     * </pre>
056     */
057    public class HeaderControlFilter implements Filter {
058            
059            protected String reencParam = null;
060            
061            public void init(FilterConfig filterConfig) throws ServletException {
062                    this.reencParam = filterConfig.getInitParameter("request.reencoding");
063            }
064    
065            public void destroy() {
066            }
067            
068            public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
069                    HttpServletRequest httpRequest = (HttpServletRequest) req;
070                    // Firefox 3.0.4 requires a less strict check. Before it was:
071                    // if (reencParam != null && req.getCharacterEncoding() != null && !reencParam.equals(req.getCharacterEncoding())) {
072                    if (reencParam != null && req.getCharacterEncoding() != null) {
073                            req = new HeaderControlRequest(httpRequest, reencParam);
074                    }
075                    chain.doFilter(req, resp);
076            }
077            
078    }
079    
080    
081    class HeaderControlRequest extends HttpServletRequestWrapper {
082            
083            String encoding;
084            ServletInputStream inputStream;
085            
086            public HeaderControlRequest(HttpServletRequest req, String encoding) {
087                    super(req);
088                    this.encoding = encoding;
089            }
090            
091            public ServletInputStream getInputStream() throws IOException {
092                    if (inputStream == null) {
093                            inputStream = new InputStreamReencoder(super.getInputStream(), super.getCharacterEncoding(), encoding);
094                    }
095                    return inputStream;
096            }
097            
098    }
099    
100    
101    class InputStreamReencoder extends ServletInputStream {
102            
103            ByteArrayInputStream byteInputStream;
104            
105            public InputStreamReencoder(ServletInputStream inputStream, String encIn, String encOut) {
106                    ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
107                    byte[] buffer = new byte[4096];
108                    
109                    int bytesRead = 0;
110                    try {
111                            do {
112                                    bytesRead = inputStream.read(buffer);
113                                    if (bytesRead > 0) {
114                                            byteOutputStream.write(buffer, 0, bytesRead);
115                                    }
116                            } while (bytesRead > 0);
117                    } catch (IOException e) {
118                            e.printStackTrace();
119                    } finally {
120                            if (inputStream != null) {
121                                    try {
122                                            inputStream.close();
123                                    } catch (IOException ex) {}
124                            }
125                    }
126                    
127                    byte[] data = byteOutputStream.toByteArray();
128                    try {
129                            data = new String(data, encIn).trim().getBytes(encOut);
130                            byteInputStream = new ByteArrayInputStream(data);
131                    } catch (UnsupportedEncodingException ex) {}
132            }
133            
134            public int read() throws IOException {
135                    return byteInputStream.read();
136            }
137    
138    }