001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.servlet.filters.gzip;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
018    import com.liferay.portal.kernel.io.unsync.UnsyncPrintWriter;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.servlet.BrowserSnifferUtil;
022    import com.liferay.portal.kernel.servlet.HttpHeaders;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.util.RSSThreadLocal;
025    
026    import java.io.IOException;
027    import java.io.OutputStreamWriter;
028    import java.io.PrintWriter;
029    
030    import javax.servlet.ServletOutputStream;
031    import javax.servlet.http.HttpServletRequest;
032    import javax.servlet.http.HttpServletResponse;
033    import javax.servlet.http.HttpServletResponseWrapper;
034    
035    /**
036     * @author Jayson Falkner
037     * @author Brian Wing Shun Chan
038     * @author Shuyang Zhou
039     */
040    public class GZipResponse extends HttpServletResponseWrapper {
041    
042            public GZipResponse(
043                    HttpServletRequest request, HttpServletResponse response) {
044    
045                    super(response);
046    
047                    _response = response;
048    
049                    // Clear previous content length setting. GZip response does not buffer
050                    // output to get final content length. The response will be chunked
051                    // unless an outer filter calculates the content length.
052    
053                    _response.setContentLength(-1);
054    
055                    _response.addHeader(HttpHeaders.CONTENT_ENCODING, _GZIP);
056    
057                    _firefox = BrowserSnifferUtil.isFirefox(request);
058            }
059    
060            public void finishResponse() throws IOException {
061                    try {
062                            if (_printWriter != null) {
063                                    _printWriter.close();
064                            }
065                            else if (_servletOutputStream != null) {
066                                    _servletOutputStream.close();
067                            }
068                    }
069                    catch (IOException e) {
070                    }
071    
072                    if (_unsyncByteArrayOutputStream != null) {
073                            _response.setContentLength(_unsyncByteArrayOutputStream.size());
074    
075                            _unsyncByteArrayOutputStream.writeTo(_response.getOutputStream());
076                    }
077            }
078    
079            public void flushBuffer() throws IOException {
080                    if (_servletOutputStream != null) {
081                            _servletOutputStream.flush();
082                    }
083            }
084    
085            public ServletOutputStream getOutputStream() throws IOException {
086                    if (_printWriter != null) {
087                            throw new IllegalStateException();
088                    }
089    
090                    if (_servletOutputStream == null) {
091                            if (_firefox && RSSThreadLocal.isExportRSS()) {
092                                    _unsyncByteArrayOutputStream =
093                                            new UnsyncByteArrayOutputStream();
094    
095                                    _servletOutputStream = new GZipServletOutputStream(
096                                            _unsyncByteArrayOutputStream);
097                            }
098                            else {
099                                    _servletOutputStream = new GZipServletOutputStream(
100                                            _response.getOutputStream());
101                            }
102                    }
103    
104                    return _servletOutputStream;
105            }
106    
107            public PrintWriter getWriter() throws IOException {
108                    if (_printWriter != null) {
109                            return _printWriter;
110                    }
111    
112                    if (_servletOutputStream != null) {
113                            throw new IllegalStateException();
114                    }
115    
116                    if (_log.isWarnEnabled()) {
117                            _log.warn("Use getOutputStream for optimum performance");
118                    }
119    
120                    _servletOutputStream = getOutputStream();
121    
122                    _printWriter = new UnsyncPrintWriter(new OutputStreamWriter(
123                            //_stream, _res.getCharacterEncoding()));
124                            _servletOutputStream, StringPool.UTF8));
125    
126                    return _printWriter;
127            }
128    
129            public void setContentLength(int contentLength) {
130            }
131    
132            private static final String _GZIP = "gzip";
133    
134            private static final Log _log = LogFactoryUtil.getLog(GZipResponse.class);
135    
136            private boolean _firefox;
137            private PrintWriter _printWriter;
138            private HttpServletResponse _response;
139            private ServletOutputStream _servletOutputStream;
140            private UnsyncByteArrayOutputStream _unsyncByteArrayOutputStream;
141    
142    }