001    /**
002     * Copyright (c) 2000-2012 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.ContentTypes;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.kernel.util.UnsyncPrintWriterPool;
025    import com.liferay.util.RSSThreadLocal;
026    
027    import java.io.IOException;
028    import java.io.OutputStreamWriter;
029    import java.io.PrintWriter;
030    
031    import javax.servlet.ServletOutputStream;
032    import javax.servlet.http.HttpServletRequest;
033    import javax.servlet.http.HttpServletResponse;
034    import javax.servlet.http.HttpServletResponseWrapper;
035    
036    /**
037     * @author Jayson Falkner
038     * @author Brian Wing Shun Chan
039     * @author Shuyang Zhou
040     */
041    public class GZipResponse extends HttpServletResponseWrapper {
042    
043            public GZipResponse(
044                    HttpServletRequest request, HttpServletResponse response) {
045    
046                    super(response);
047    
048                    _response = response;
049    
050                    // Clear previous content length setting. GZip response does not buffer
051                    // output to get final content length. The response will be chunked
052                    // unless an outer filter calculates the content length.
053    
054                    _response.setContentLength(-1);
055    
056                    _response.addHeader(HttpHeaders.CONTENT_ENCODING, _GZIP);
057    
058                    _firefox = BrowserSnifferUtil.isFirefox(request);
059            }
060    
061            public void finishResponse() throws IOException {
062                    try {
063                            if (_printWriter != null) {
064                                    _printWriter.close();
065                            }
066                            else if (_servletOutputStream != null) {
067                                    _servletOutputStream.close();
068                            }
069                    }
070                    catch (IOException e) {
071                    }
072    
073                    if (_unsyncByteArrayOutputStream != null) {
074                            _response.setContentLength(_unsyncByteArrayOutputStream.size());
075    
076                            _unsyncByteArrayOutputStream.writeTo(_response.getOutputStream());
077                    }
078            }
079    
080            @Override
081            public void flushBuffer() throws IOException {
082                    if (_servletOutputStream != null) {
083                            _servletOutputStream.flush();
084                    }
085            }
086    
087            @Override
088            public ServletOutputStream getOutputStream() throws IOException {
089                    if (_printWriter != null) {
090                            throw new IllegalStateException();
091                    }
092    
093                    if (_servletOutputStream == null) {
094                            if (_gZipContentType) {
095                                    _servletOutputStream = _response.getOutputStream();
096                            }
097                            else {
098                                    if (_firefox && RSSThreadLocal.isExportRSS()) {
099                                            _unsyncByteArrayOutputStream =
100                                                    new UnsyncByteArrayOutputStream();
101    
102                                            _servletOutputStream = new GZipServletOutputStream(
103                                                    _unsyncByteArrayOutputStream);
104                                    }
105                                    else {
106                                            _servletOutputStream = new GZipServletOutputStream(
107                                                    _response.getOutputStream());
108                                    }
109                            }
110                    }
111    
112                    return _servletOutputStream;
113            }
114    
115            @Override
116            public PrintWriter getWriter() throws IOException {
117                    if (_printWriter != null) {
118                            return _printWriter;
119                    }
120    
121                    if (_servletOutputStream != null) {
122                            throw new IllegalStateException();
123                    }
124    
125                    if (_log.isWarnEnabled()) {
126                            _log.warn("Use getOutputStream for optimum performance");
127                    }
128    
129                    _servletOutputStream = getOutputStream();
130    
131                    _printWriter = UnsyncPrintWriterPool.borrow(
132                            new OutputStreamWriter(//_stream, _res.getCharacterEncoding()));
133                                    _servletOutputStream, StringPool.UTF8));
134    
135                    return _printWriter;
136            }
137    
138            @Override
139            public void setContentLength(int contentLength) {
140            }
141    
142            @Override
143            public void setContentType(String contentType) {
144                    super.setContentType(contentType);
145    
146                    if (contentType != null) {
147                            if (contentType.equals(ContentTypes.APPLICATION_GZIP) ||
148                                    contentType.equals(ContentTypes.APPLICATION_X_GZIP)) {
149    
150                                    _gZipContentType = true;
151                            }
152                    }
153            }
154    
155            private static final String _GZIP = "gzip";
156    
157            private static Log _log = LogFactoryUtil.getLog(GZipResponse.class);
158    
159            private boolean _firefox;
160            private boolean _gZipContentType;
161            private PrintWriter _printWriter;
162            private HttpServletResponse _response;
163            private ServletOutputStream _servletOutputStream;
164            private UnsyncByteArrayOutputStream _unsyncByteArrayOutputStream;
165    
166    }