com.liferay.portal.kernel.servlet.ServletResponseUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.liferay.portal.kernel Show documentation
Show all versions of com.liferay.portal.kernel Show documentation
Contains interfaces for the portal services. Interfaces are only loaded by the global class loader and are shared by all plugins.
/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.servlet;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.nio.charset.CharsetEncoderUtil;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.HttpUtil;
import com.liferay.portal.kernel.util.MimeTypesUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.PropsUtil;
import com.liferay.portal.kernel.util.RandomAccessInputStream;
import com.liferay.portal.kernel.util.ServerDetector;
import com.liferay.portal.kernel.util.StreamUtil;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Brian Wing Shun Chan
* @author Shuyang Zhou
*/
public class ServletResponseUtil {
public static List getRanges(
HttpServletRequest request, HttpServletResponse response,
long length)
throws IOException {
String rangeString = request.getHeader(HttpHeaders.RANGE);
if (Validator.isNull(rangeString)) {
return Collections.emptyList();
}
if (!rangeString.matches(_RANGE_REGEX)) {
throw new IOException(
"Range header does not match regular expression " +
rangeString);
}
List ranges = new ArrayList<>();
String[] rangeFields = StringUtil.split(rangeString.substring(6));
if (rangeFields.length > _MAX_RANGE_FIELDS) {
StringBundler sb = new StringBundler(8);
sb.append("Request range ");
sb.append(rangeString);
sb.append(" with ");
sb.append(rangeFields.length);
sb.append(" range fields has exceeded maximum allowance as ");
sb.append("specified by the property \"");
sb.append(PropsKeys.WEB_SERVER_SERVLET_MAX_RANGE_FIELDS);
sb.append("\"");
throw new IOException(sb.toString());
}
for (String rangeField : rangeFields) {
int index = rangeField.indexOf(StringPool.DASH);
long start = GetterUtil.getLong(rangeField.substring(0, index), -1);
long end = GetterUtil.getLong(
rangeField.substring(index + 1, rangeField.length()), -1);
if (start == -1) {
start = length - end;
end = length - 1;
}
else if ((end == -1) || (end > (length - 1))) {
end = length - 1;
}
if (start > end) {
throw new IOException(
"Range start " + start + " is greater than end " + end);
}
Range range = new Range(start, end, length);
ranges.add(range);
}
return ranges;
}
public static boolean isClientAbortException(IOException ioe) {
Class> clazz = ioe.getClass();
String className = clazz.getName();
if (className.equals(_CLIENT_ABORT_EXCEPTION)) {
return true;
}
else {
return false;
}
}
public static void sendFile(
HttpServletRequest request, HttpServletResponse response,
String fileName, byte[] bytes)
throws IOException {
sendFile(request, response, fileName, bytes, null);
}
public static void sendFile(
HttpServletRequest request, HttpServletResponse response,
String fileName, byte[] bytes, String contentType)
throws IOException {
sendFile(request, response, fileName, bytes, contentType, null);
}
public static void sendFile(
HttpServletRequest request, HttpServletResponse response,
String fileName, byte[] bytes, String contentType,
String contentDispositionType)
throws IOException {
setHeaders(
request, response, fileName, contentType, contentDispositionType);
write(response, bytes);
}
public static void sendFile(
HttpServletRequest request, HttpServletResponse response,
String fileName, InputStream inputStream)
throws IOException {
sendFile(request, response, fileName, inputStream, null);
}
public static void sendFile(
HttpServletRequest request, HttpServletResponse response,
String fileName, InputStream inputStream, long contentLength,
String contentType)
throws IOException {
sendFile(
request, response, fileName, inputStream, contentLength,
contentType, null);
}
public static void sendFile(
HttpServletRequest request, HttpServletResponse response,
String fileName, InputStream inputStream, long contentLength,
String contentType, String contentDispositionType)
throws IOException {
setHeaders(
request, response, fileName, contentType, contentDispositionType);
write(response, inputStream, contentLength);
}
public static void sendFile(
HttpServletRequest request, HttpServletResponse response,
String fileName, InputStream inputStream, String contentType)
throws IOException {
sendFile(request, response, fileName, inputStream, 0, contentType);
}
public static void sendFileWithRangeHeader(
HttpServletRequest request, HttpServletResponse response,
String fileName, InputStream inputStream, long contentLength,
String contentType)
throws IOException {
if (_log.isDebugEnabled()) {
_log.debug("Accepting ranges for the file " + fileName);
}
response.setHeader(
HttpHeaders.ACCEPT_RANGES, HttpHeaders.ACCEPT_RANGES_BYTES_VALUE);
List ranges = null;
try {
ranges = getRanges(request, response, contentLength);
}
catch (IOException ioe) {
_log.error(ioe);
response.setHeader(
HttpHeaders.CONTENT_RANGE, "bytes */" + contentLength);
response.sendError(
HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return;
}
if ((ranges == null) || ranges.isEmpty()) {
sendFile(
request, response, fileName, inputStream, contentLength,
contentType);
}
else {
if (_log.isDebugEnabled()) {
_log.debug(
"Request has range header " +
request.getHeader(HttpHeaders.RANGE));
}
write(
request, response, fileName, ranges, inputStream, contentLength,
contentType);
}
}
public static void write(
HttpServletRequest request, HttpServletResponse response,
String fileName, List ranges, InputStream inputStream,
long fullLength, String contentType)
throws IOException {
OutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
Range fullRange = new Range(0, fullLength - 1, fullLength);
Range firstRange = null;
if (!ranges.isEmpty()) {
firstRange = ranges.get(0);
}
if ((firstRange == null) || firstRange.equals(fullRange)) {
if (_log.isDebugEnabled()) {
_log.debug("Writing full range");
}
response.setContentType(contentType);
setHeaders(
request, response, fileName, contentType, null, fullRange);
copyRange(
inputStream, outputStream, fullRange.getStart(),
fullRange.getLength());
}
else if (ranges.size() == 1) {
if (_log.isDebugEnabled()) {
_log.debug("Attempting to write a single range");
}
Range range = ranges.get(0);
response.setContentType(contentType);
setHeaders(
request, response, fileName, contentType, null, range);
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
copyRange(
inputStream, outputStream, range.getStart(),
range.getLength());
}
else if (ranges.size() > 1) {
if (_log.isDebugEnabled()) {
_log.debug("Attempting to write multiple ranges");
}
ServletOutputStream servletOutputStream =
(ServletOutputStream)outputStream;
String boundary =
"liferay-multipart-boundary-" + System.currentTimeMillis();
String multipartContentType =
"multipart/byteranges; boundary=" + boundary;
response.setContentType(multipartContentType);
setHeaders(
request, response, fileName, multipartContentType, null);
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
for (int i = 0; i < ranges.size(); i++) {
Range range = ranges.get(i);
servletOutputStream.println();
servletOutputStream.println(
StringPool.DOUBLE_DASH + boundary);
servletOutputStream.println(
HttpHeaders.CONTENT_TYPE + ": " + contentType);
servletOutputStream.println(
HttpHeaders.CONTENT_RANGE + ": " +
range.getContentRange());
servletOutputStream.println();
inputStream = copyRange(
inputStream, outputStream, range.getStart(),
range.getLength());
}
servletOutputStream.println();
servletOutputStream.println(
StringPool.DOUBLE_DASH + boundary + StringPool.DOUBLE_DASH);
}
}
finally {
try {
inputStream.close();
}
catch (IOException ioe) {
}
}
}
public static void write(
HttpServletResponse response,
BufferCacheServletResponse bufferCacheServletResponse)
throws IOException {
if (bufferCacheServletResponse.isByteMode()) {
write(response, bufferCacheServletResponse.getByteBuffer());
}
else if (bufferCacheServletResponse.isCharMode()) {
write(response, bufferCacheServletResponse.getCharBuffer());
}
}
public static void write(HttpServletResponse response, byte[] bytes)
throws IOException {
write(response, bytes, 0, 0);
}
public static void write(
HttpServletResponse response, byte[] bytes, int offset,
int contentLength)
throws IOException {
try {
// LEP-3122
if (!response.isCommitted()) {
// LEP-536
if (contentLength == 0) {
contentLength = bytes.length;
}
response.setContentLength(contentLength);
response.flushBuffer();
if (response instanceof BufferCacheServletResponse) {
BufferCacheServletResponse bufferCacheServletResponse =
(BufferCacheServletResponse)response;
bufferCacheServletResponse.setByteBuffer(
ByteBuffer.wrap(bytes, offset, contentLength));
}
else {
ServletOutputStream servletOutputStream =
response.getOutputStream();
if ((contentLength == 0) && ServerDetector.isJetty()) {
}
else {
servletOutputStream.write(bytes, offset, contentLength);
}
}
}
}
catch (IOException ioe) {
if ((ioe instanceof SocketException) ||
isClientAbortException(ioe)) {
if (_log.isWarnEnabled()) {
_log.warn(ioe);
}
}
else {
throw ioe;
}
}
}
public static void write(HttpServletResponse response, byte[][] bytesArray)
throws IOException {
try {
// LEP-3122
if (!response.isCommitted()) {
long contentLength = 0;
for (byte[] bytes : bytesArray) {
contentLength += bytes.length;
}
setContentLength(response, contentLength);
response.flushBuffer();
ServletOutputStream servletOutputStream =
response.getOutputStream();
for (byte[] bytes : bytesArray) {
servletOutputStream.write(bytes);
}
}
}
catch (IOException ioe) {
if ((ioe instanceof SocketException) ||
isClientAbortException(ioe)) {
if (_log.isWarnEnabled()) {
_log.warn(ioe);
}
}
else {
throw ioe;
}
}
}
public static void write(
HttpServletResponse response, ByteBuffer byteBuffer)
throws IOException {
if (response instanceof BufferCacheServletResponse) {
BufferCacheServletResponse bufferCacheServletResponse =
(BufferCacheServletResponse)response;
bufferCacheServletResponse.setByteBuffer(byteBuffer);
}
else {
write(
response, byteBuffer.array(),
byteBuffer.arrayOffset() + byteBuffer.position(),
byteBuffer.arrayOffset() + byteBuffer.limit());
}
}
public static void write(
HttpServletResponse response, CharBuffer charBuffer)
throws IOException {
if (response instanceof BufferCacheServletResponse) {
BufferCacheServletResponse bufferCacheServletResponse =
(BufferCacheServletResponse)response;
bufferCacheServletResponse.setCharBuffer(charBuffer);
}
else {
ByteBuffer byteBuffer = CharsetEncoderUtil.encode(
StringPool.UTF8, charBuffer);
write(response, byteBuffer);
}
}
public static void write(HttpServletResponse response, File file)
throws IOException {
if (response instanceof BufferCacheServletResponse) {
BufferCacheServletResponse bufferCacheServletResponse =
(BufferCacheServletResponse)response;
ByteBuffer byteBuffer = ByteBuffer.wrap(FileUtil.getBytes(file));
bufferCacheServletResponse.setByteBuffer(byteBuffer);
}
else {
FileInputStream fileInputStream = new FileInputStream(file);
try (FileChannel fileChannel = fileInputStream.getChannel()) {
long contentLength = fileChannel.size();
setContentLength(response, contentLength);
response.flushBuffer();
fileChannel.transferTo(
0, contentLength,
Channels.newChannel(response.getOutputStream()));
}
}
}
public static void write(
HttpServletResponse response, InputStream inputStream)
throws IOException {
write(response, inputStream, 0);
}
public static void write(
HttpServletResponse response, InputStream inputStream,
long contentLength)
throws IOException {
if (response.isCommitted()) {
StreamUtil.cleanUp(inputStream);
return;
}
if (contentLength > 0) {
response.setHeader(
HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength));
}
response.flushBuffer();
StreamUtil.transfer(inputStream, response.getOutputStream());
}
public static void write(HttpServletResponse response, String s)
throws IOException {
if (response instanceof BufferCacheServletResponse) {
BufferCacheServletResponse bufferCacheServletResponse =
(BufferCacheServletResponse)response;
bufferCacheServletResponse.setString(s);
}
else {
ByteBuffer byteBuffer = CharsetEncoderUtil.encode(
StringPool.UTF8, s);
write(response, byteBuffer);
}
}
protected static InputStream copyRange(
InputStream inputStream, OutputStream outputStream, long start,
long length)
throws IOException {
if (inputStream instanceof FileInputStream) {
FileInputStream fileInputStream = (FileInputStream)inputStream;
FileChannel fileChannel = fileInputStream.getChannel();
fileChannel.transferTo(
start, length, Channels.newChannel(outputStream));
return fileInputStream;
}
else if (inputStream instanceof ByteArrayInputStream) {
ByteArrayInputStream byteArrayInputStream =
(ByteArrayInputStream)inputStream;
byteArrayInputStream.reset();
byteArrayInputStream.skip(start);
StreamUtil.transfer(byteArrayInputStream, outputStream, length);
return byteArrayInputStream;
}
else if (inputStream instanceof RandomAccessInputStream) {
RandomAccessInputStream randomAccessInputStream =
(RandomAccessInputStream)inputStream;
randomAccessInputStream.seek(start);
StreamUtil.transfer(
randomAccessInputStream, outputStream, StreamUtil.BUFFER_SIZE,
false, length);
return randomAccessInputStream;
}
return copyRange(
new RandomAccessInputStream(inputStream), outputStream, start,
length);
}
protected static void setContentLength(
HttpServletResponse response, long contentLength) {
response.setHeader(
HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength));
}
protected static void setHeaders(
HttpServletRequest request, HttpServletResponse response,
String fileName, String contentType, String contentDispositionType) {
if (_log.isDebugEnabled()) {
_log.debug("Sending file of type " + contentType);
}
// LEP-2201
if (Validator.isNotNull(contentType)) {
response.setContentType(contentType);
}
if (!response.containsHeader(HttpHeaders.CACHE_CONTROL)) {
response.setHeader(
HttpHeaders.CACHE_CONTROL,
HttpHeaders.CACHE_CONTROL_PRIVATE_VALUE);
}
if (Validator.isNull(fileName)) {
return;
}
String contentDispositionFileName = "filename=\"" + fileName + "\"";
// If necessary for non-ASCII characters, encode based on RFC 2184.
// However, not all browsers support RFC 2184. See LEP-3127.
boolean ascii = true;
for (int i = 0; i < fileName.length(); i++) {
if (!Validator.isAscii(fileName.charAt(i))) {
ascii = false;
break;
}
}
if (!ascii) {
String encodedFileName = HttpUtil.encodeURL(fileName, true);
if (BrowserSnifferUtil.isIe(request)) {
contentDispositionFileName =
"filename=\"" + encodedFileName + "\"";
}
else {
contentDispositionFileName =
"filename*=UTF-8''" + encodedFileName;
}
}
if (Validator.isNull(contentDispositionType)) {
String extension = GetterUtil.getString(
FileUtil.getExtension(fileName));
extension = StringUtil.toLowerCase(extension);
String[] mimeTypesContentDispositionInline = null;
try {
mimeTypesContentDispositionInline = PropsUtil.getArray(
PropsKeys.MIME_TYPES_CONTENT_DISPOSITION_INLINE);
}
catch (Exception e) {
mimeTypesContentDispositionInline = new String[0];
}
if (ArrayUtil.contains(
mimeTypesContentDispositionInline, extension)) {
contentDispositionType = HttpHeaders.CONTENT_DISPOSITION_INLINE;
contentType = MimeTypesUtil.getContentType(fileName);
response.setContentType(contentType);
}
else {
contentDispositionType =
HttpHeaders.CONTENT_DISPOSITION_ATTACHMENT;
}
}
StringBundler sb = new StringBundler(4);
sb.append(contentDispositionType);
sb.append(StringPool.SEMICOLON);
sb.append(StringPool.SPACE);
sb.append(contentDispositionFileName);
if (_log.isDebugEnabled()) {
_log.debug("Setting content disposition header " + sb.toString());
}
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, sb.toString());
}
protected static void setHeaders(
HttpServletRequest request, HttpServletResponse response,
String fileName, String contentType, String contentDispositionType,
Range range) {
setHeaders(
request, response, fileName, contentType, contentDispositionType);
if (range != null) {
response.setHeader(
HttpHeaders.CONTENT_RANGE, range.getContentRange());
response.setHeader(
HttpHeaders.CONTENT_LENGTH, String.valueOf(range.getLength()));
}
}
private static final String _CLIENT_ABORT_EXCEPTION =
"org.apache.catalina.connector.ClientAbortException";
private static final int _MAX_RANGE_FIELDS = GetterUtil.getInteger(
PropsUtil.get(PropsKeys.WEB_SERVER_SERVLET_MAX_RANGE_FIELDS));
private static final String _RANGE_REGEX =
"^bytes=\\d*-\\d*(,\\s?\\d*-\\d*)*$";
private static final Log _log = LogFactoryUtil.getLog(
ServletResponseUtil.class);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy