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.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.servlet.BrowserSnifferUtil;
021    import com.liferay.portal.kernel.servlet.HttpHeaders;
022    import com.liferay.portal.kernel.util.StringPool;
023    import com.liferay.portal.kernel.util.UnsyncPrintWriterPool;
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            @Override
080            public void flushBuffer() throws IOException {
081                    if (_servletOutputStream != null) {
082                            _servletOutputStream.flush();
083                    }
084            }
085    
086            @Override
087            public ServletOutputStream getOutputStream() throws IOException {
088                    if (_printWriter != null) {
089                            throw new IllegalStateException();
090                    }
091    
092                    if (_servletOutputStream == null) {
093                            if (_firefox && RSSThreadLocal.isExportRSS()) {
094                                    _unsyncByteArrayOutputStream =
095                                            new UnsyncByteArrayOutputStream();
096    
097                                    _servletOutputStream = new GZipServletOutputStream(
098                                            _unsyncByteArrayOutputStream);
099                            }
100                            else {
101                                    _servletOutputStream = new GZipServletOutputStream(
102                                            _response.getOutputStream());
103                            }
104                    }
105    
106                    return _servletOutputStream;
107            }
108    
109            @Override
110            public PrintWriter getWriter() throws IOException {
111                    if (_printWriter != null) {
112                            return _printWriter;
113                    }
114    
115                    if (_servletOutputStream != null) {
116                            throw new IllegalStateException();
117                    }
118    
119                    if (_log.isWarnEnabled()) {
120                            _log.warn("Use getOutputStream for optimum performance");
121                    }
122    
123                    _servletOutputStream = getOutputStream();
124    
125                    _printWriter = UnsyncPrintWriterPool.borrow(
126                            new OutputStreamWriter(//_stream, _res.getCharacterEncoding()));
127                                    _servletOutputStream, StringPool.UTF8));
128    
129                    return _printWriter;
130            }
131    
132            @Override
133            public void setContentLength(int contentLength) {
134            }
135    
136            private static final String _GZIP = "gzip";
137    
138            private static Log _log = LogFactoryUtil.getLog(GZipResponse.class);
139    
140            private boolean _firefox;
141            private PrintWriter _printWriter;
142            private HttpServletResponse _response;
143            private ServletOutputStream _servletOutputStream;
144            private UnsyncByteArrayOutputStream _unsyncByteArrayOutputStream;
145    
146    }