001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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(
127                                    //_stream, _res.getCharacterEncoding()));
128                                    _servletOutputStream, StringPool.UTF8));
129    
130                    return _printWriter;
131            }
132    
133            @Override
134            public void setContentLength(int contentLength) {
135            }
136    
137            private static final String _GZIP = "gzip";
138    
139            private static Log _log = LogFactoryUtil.getLog(GZipResponse.class);
140    
141            private boolean _firefox;
142            private PrintWriter _printWriter;
143            private HttpServletResponse _response;
144            private ServletOutputStream _servletOutputStream;
145            private UnsyncByteArrayOutputStream _unsyncByteArrayOutputStream;
146    
147    }