001    /**
002     * Copyright (c) 2000-2013 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.kernel.servlet;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.nio.charset.CharsetEncoderUtil;
020    import com.liferay.portal.kernel.util.ArrayUtil;
021    import com.liferay.portal.kernel.util.FileUtil;
022    import com.liferay.portal.kernel.util.GetterUtil;
023    import com.liferay.portal.kernel.util.HttpUtil;
024    import com.liferay.portal.kernel.util.MimeTypesUtil;
025    import com.liferay.portal.kernel.util.PropsKeys;
026    import com.liferay.portal.kernel.util.PropsUtil;
027    import com.liferay.portal.kernel.util.RandomAccessInputStream;
028    import com.liferay.portal.kernel.util.ServerDetector;
029    import com.liferay.portal.kernel.util.StreamUtil;
030    import com.liferay.portal.kernel.util.StringBundler;
031    import com.liferay.portal.kernel.util.StringPool;
032    import com.liferay.portal.kernel.util.StringUtil;
033    import com.liferay.portal.kernel.util.Validator;
034    
035    import java.io.ByteArrayInputStream;
036    import java.io.File;
037    import java.io.FileInputStream;
038    import java.io.IOException;
039    import java.io.InputStream;
040    import java.io.OutputStream;
041    
042    import java.net.SocketException;
043    
044    import java.nio.ByteBuffer;
045    import java.nio.CharBuffer;
046    import java.nio.channels.Channels;
047    import java.nio.channels.FileChannel;
048    
049    import java.util.ArrayList;
050    import java.util.Collections;
051    import java.util.List;
052    
053    import javax.servlet.ServletOutputStream;
054    import javax.servlet.http.HttpServletRequest;
055    import javax.servlet.http.HttpServletResponse;
056    
057    /**
058     * @author Brian Wing Shun Chan
059     * @author Shuyang Zhou
060     */
061    public class ServletResponseUtil {
062    
063            public static List<Range> getRanges(
064                            HttpServletRequest request, HttpServletResponse response,
065                            long length)
066                    throws IOException {
067    
068                    String rangeString = request.getHeader(HttpHeaders.RANGE);
069    
070                    if (Validator.isNull(rangeString)) {
071                            return Collections.emptyList();
072                    }
073    
074                    if (!rangeString.matches(_RANGE_REGEX)) {
075                            throw new IOException(
076                                    "Range header does not match regular expression " +
077                                    rangeString);
078                    }
079    
080                    List<Range> ranges = new ArrayList<Range>();
081    
082                    String[] rangeFields = StringUtil.split(rangeString.substring(6));
083    
084                    if (rangeFields.length > _MAX_RANGE_FIELDS) {
085                            StringBundler sb = new StringBundler(8);
086    
087                            sb.append("Request range ");
088                            sb.append(rangeString);
089                            sb.append(" with ");
090                            sb.append(rangeFields.length);
091                            sb.append(" range fields has exceeded maximum allowance as ");
092                            sb.append("specified by the property \"");
093                            sb.append(PropsKeys.WEB_SERVER_SERVLET_MAX_RANGE_FIELDS);
094                            sb.append("\"");
095    
096                            throw new IOException(sb.toString());
097                    }
098    
099                    for (String rangeField : rangeFields) {
100                            int index = rangeField.indexOf(StringPool.DASH);
101    
102                            long start = GetterUtil.getLong(rangeField.substring(0, index), -1);
103                            long end = GetterUtil.getLong(
104                                    rangeField.substring(index + 1, rangeField.length()), -1);
105    
106                            if (start == -1) {
107                                    start = length - end;
108                                    end = length - 1;
109                            }
110                            else if ((end == -1) || (end > (length - 1))) {
111                                    end = length - 1;
112                            }
113    
114                            if (start > end) {
115                                    throw new IOException(
116                                            "Range start " + start + " is greater than end " + end);
117                            }
118    
119                            Range range = new Range(start, end, length);
120    
121                            ranges.add(range);
122                    }
123    
124                    return ranges;
125            }
126    
127            public static boolean isClientAbortException(IOException ioe) {
128                    Class<?> clazz = ioe.getClass();
129    
130                    String className = clazz.getName();
131    
132                    if (className.equals(_CLIENT_ABORT_EXCEPTION)) {
133                            return true;
134                    }
135                    else {
136                            return false;
137                    }
138            }
139    
140            public static void sendFile(
141                            HttpServletRequest request, HttpServletResponse response,
142                            String fileName, byte[] bytes)
143                    throws IOException {
144    
145                    sendFile(request, response, fileName, bytes, null);
146            }
147    
148            public static void sendFile(
149                            HttpServletRequest request, HttpServletResponse response,
150                            String fileName, byte[] bytes, String contentType)
151                    throws IOException {
152    
153                    sendFile(request, response, fileName, bytes, contentType, null);
154            }
155    
156            public static void sendFile(
157                            HttpServletRequest request, HttpServletResponse response,
158                            String fileName, byte[] bytes, String contentType,
159                            String contentDispositionType)
160                    throws IOException {
161    
162                    setHeaders(
163                            request, response, fileName, contentType, contentDispositionType);
164    
165                    write(response, bytes);
166            }
167    
168            public static void sendFile(
169                            HttpServletRequest request, HttpServletResponse response,
170                            String fileName, InputStream inputStream)
171                    throws IOException {
172    
173                    sendFile(request, response, fileName, inputStream, null);
174            }
175    
176            public static void sendFile(
177                            HttpServletRequest request, HttpServletResponse response,
178                            String fileName, InputStream inputStream, long contentLength,
179                            String contentType)
180                    throws IOException {
181    
182                    sendFile(
183                            request, response, fileName, inputStream, contentLength,
184                            contentType, null);
185            }
186    
187            public static void sendFile(
188                            HttpServletRequest request, HttpServletResponse response,
189                            String fileName, InputStream inputStream, long contentLength,
190                            String contentType, String contentDispositionType)
191                    throws IOException {
192    
193                    setHeaders(
194                            request, response, fileName, contentType, contentDispositionType);
195    
196                    write(response, inputStream, contentLength);
197            }
198    
199            public static void sendFile(
200                            HttpServletRequest request, HttpServletResponse response,
201                            String fileName, InputStream inputStream, String contentType)
202                    throws IOException {
203    
204                    sendFile(request, response, fileName, inputStream, 0, contentType);
205            }
206    
207            /**
208             * @deprecated As of 6.1.0
209             */
210            public static void sendFile(
211                            HttpServletResponse response, String fileName, byte[] bytes)
212                    throws IOException {
213    
214                    sendFile(null, response, fileName, bytes);
215            }
216    
217            /**
218             * @deprecated As of 6.1.0
219             */
220            public static void sendFile(
221                            HttpServletResponse response, String fileName, byte[] bytes,
222                            String contentType)
223                    throws IOException {
224    
225                    sendFile(null, response, fileName, bytes, contentType);
226            }
227    
228            /**
229             * @deprecated As of 6.1.0
230             */
231            public static void sendFile(
232                            HttpServletResponse response, String fileName,
233                            InputStream inputStream)
234                    throws IOException {
235    
236                    sendFile(null, response, fileName, inputStream);
237            }
238    
239            /**
240             * @deprecated As of 6.1.0
241             */
242            public static void sendFile(
243                            HttpServletResponse response, String fileName,
244                            InputStream inputStream, int contentLength, String contentType)
245                    throws IOException {
246    
247                    sendFile(
248                            null, response, fileName, inputStream, contentLength, contentType);
249            }
250    
251            /**
252             * @deprecated As of 6.1.0
253             */
254            public static void sendFile(
255                            HttpServletResponse response, String fileName,
256                            InputStream inputStream, String contentType)
257                    throws IOException {
258    
259                    sendFile(null, response, fileName, inputStream, contentType);
260            }
261    
262            public static void sendFileWithRangeHeader(
263                            HttpServletRequest request, HttpServletResponse response,
264                            String fileName, InputStream inputStream, long contentLength,
265                            String contentType)
266                    throws IOException {
267    
268                    if (_log.isDebugEnabled()) {
269                            _log.debug("Accepting ranges for the file " + fileName);
270                    }
271    
272                    response.setHeader(
273                            HttpHeaders.ACCEPT_RANGES, HttpHeaders.ACCEPT_RANGES_BYTES_VALUE);
274    
275                    List<Range> ranges = null;
276    
277                    try {
278                            ranges = getRanges(request, response, contentLength);
279                    }
280                    catch (IOException ioe) {
281                            if (_log.isErrorEnabled()) {
282                                    _log.error(ioe);
283                            }
284    
285                            response.setHeader(
286                                    HttpHeaders.CONTENT_RANGE, "bytes */" + contentLength);
287    
288                            response.sendError(
289                                    HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
290    
291                            return;
292                    }
293    
294                    if ((ranges == null) || ranges.isEmpty()) {
295                            sendFile(
296                                    request, response, fileName, inputStream, contentLength,
297                                    contentType);
298                    }
299                    else {
300                            if (_log.isDebugEnabled()) {
301                                    _log.debug(
302                                            "Request has range header " +
303                                                    request.getHeader(HttpHeaders.RANGE));
304                            }
305    
306                            write(
307                                    request, response, fileName, ranges, inputStream, contentLength,
308                                    contentType);
309                    }
310            }
311    
312            public static void write(
313                            HttpServletRequest request, HttpServletResponse response,
314                            String fileName, List<Range> ranges, InputStream inputStream,
315                            long fullLength, String contentType)
316                    throws IOException {
317    
318                    OutputStream outputStream = null;
319    
320                    try {
321                            outputStream = response.getOutputStream();
322    
323                            Range fullRange = new Range(0, fullLength - 1, fullLength);
324    
325                            Range firstRange = null;
326    
327                            if (!ranges.isEmpty()) {
328                                    firstRange = ranges.get(0);
329                            }
330    
331                            if ((firstRange == null) || firstRange.equals(fullRange)) {
332                                    if (_log.isDebugEnabled()) {
333                                            _log.debug("Writing full range");
334                                    }
335    
336                                    response.setContentType(contentType);
337    
338                                    setHeaders(
339                                            request, response, fileName, contentType, null, fullRange);
340    
341                                    copyRange(
342                                            inputStream, outputStream, fullRange.getStart(),
343                                            fullRange.getLength());
344                            }
345                            else if (ranges.size() == 1) {
346                                    if (_log.isDebugEnabled()) {
347                                            _log.debug("Attempting to write a single range");
348                                    }
349    
350                                    Range range = ranges.get(0);
351    
352                                    response.setContentType(contentType);
353    
354                                    setHeaders(
355                                            request, response, fileName, contentType, null, range);
356    
357                                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
358    
359                                    copyRange(
360                                            inputStream, outputStream, range.getStart(),
361                                            range.getLength());
362                            }
363                            else if (ranges.size() > 1 ) {
364                                    if (_log.isDebugEnabled()) {
365                                            _log.debug("Attempting to write multiple ranges");
366                                    }
367    
368                                    ServletOutputStream servletOutputStream =
369                                            (ServletOutputStream)outputStream;
370    
371                                    String boundary =
372                                            "liferay-multipart-boundary-" + System.currentTimeMillis();
373    
374                                    String multipartContentType =
375                                            "multipart/byteranges; boundary=" + boundary;
376    
377                                    response.setContentType(multipartContentType);
378    
379                                    setHeaders(
380                                            request, response, fileName, multipartContentType, null);
381    
382                                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
383    
384                                    for (int i = 0; i < ranges.size(); i++) {
385                                            Range range = ranges.get(i);
386    
387                                            servletOutputStream.println();
388                                            servletOutputStream.println(
389                                                    StringPool.DOUBLE_DASH + boundary);
390                                            servletOutputStream.println(
391                                                    HttpHeaders.CONTENT_TYPE + ": " + contentType);
392                                            servletOutputStream.println(
393                                                    HttpHeaders.CONTENT_RANGE + ": " +
394                                                            range.getContentRange());
395                                            servletOutputStream.println();
396    
397                                            inputStream = copyRange(
398                                                    inputStream, outputStream, range.getStart(),
399                                                    range.getLength());
400                                    }
401    
402                                    servletOutputStream.println();
403                                    servletOutputStream.println(
404                                            StringPool.DOUBLE_DASH + boundary + StringPool.DOUBLE_DASH);
405                            }
406                    }
407                    finally {
408                            try {
409                                    inputStream.close();
410                            }
411                            catch (IOException ioe) {
412                            }
413                    }
414            }
415    
416            public static void write(
417                            HttpServletResponse response,
418                            BufferCacheServletResponse bufferCacheServletResponse)
419                    throws IOException {
420    
421                    if (bufferCacheServletResponse.isByteMode()) {
422                            write(response, bufferCacheServletResponse.getByteBuffer());
423                    }
424                    else if (bufferCacheServletResponse.isCharMode()) {
425                            write(response, bufferCacheServletResponse.getCharBuffer());
426                    }
427            }
428    
429            public static void write(HttpServletResponse response, byte[] bytes)
430                    throws IOException {
431    
432                    write(response, bytes, 0, 0);
433            }
434    
435            public static void write(
436                            HttpServletResponse response, byte[] bytes, int offset,
437                            int contentLength)
438                    throws IOException {
439    
440                    try {
441    
442                            // LEP-3122
443    
444                            if (!response.isCommitted()) {
445    
446                                    // LEP-536
447    
448                                    if (contentLength == 0) {
449                                            contentLength = bytes.length;
450                                    }
451    
452                                    response.setContentLength(contentLength);
453    
454                                    response.flushBuffer();
455    
456                                    if (response instanceof BufferCacheServletResponse) {
457                                            BufferCacheServletResponse bufferCacheServletResponse =
458                                                    (BufferCacheServletResponse)response;
459    
460                                            bufferCacheServletResponse.setByteBuffer(
461                                                    ByteBuffer.wrap(bytes, offset, contentLength));
462                                    }
463                                    else {
464                                            ServletOutputStream servletOutputStream =
465                                                    response.getOutputStream();
466    
467                                            if ((contentLength == 0) && ServerDetector.isJetty()) {
468                                            }
469                                            else {
470                                                    servletOutputStream.write(bytes, offset, contentLength);
471                                            }
472                                    }
473                            }
474                    }
475                    catch (IOException ioe) {
476                            if ((ioe instanceof SocketException) ||
477                                    isClientAbortException(ioe)) {
478    
479                                    if (_log.isWarnEnabled()) {
480                                            _log.warn(ioe);
481                                    }
482                            }
483                            else {
484                                    throw ioe;
485                            }
486                    }
487            }
488    
489            public static void write(HttpServletResponse response, byte[][] bytesArray)
490                    throws IOException {
491    
492                    try {
493    
494                            // LEP-3122
495    
496                            if (!response.isCommitted()) {
497                                    long contentLength = 0;
498    
499                                    for (byte[] bytes : bytesArray) {
500                                            contentLength += bytes.length;
501                                    }
502    
503                                    setContentLength(response, contentLength);
504    
505                                    response.flushBuffer();
506    
507                                    ServletOutputStream servletOutputStream =
508                                            response.getOutputStream();
509    
510                                    for (byte[] bytes : bytesArray) {
511                                            servletOutputStream.write(bytes);
512                                    }
513                            }
514                    }
515                    catch (IOException ioe) {
516                            if ((ioe instanceof SocketException) ||
517                                    isClientAbortException(ioe)) {
518    
519                                    if (_log.isWarnEnabled()) {
520                                            _log.warn(ioe);
521                                    }
522                            }
523                            else {
524                                    throw ioe;
525                            }
526                    }
527            }
528    
529            public static void write(
530                            HttpServletResponse response, ByteBuffer byteBuffer)
531                    throws IOException {
532    
533                    if (response instanceof BufferCacheServletResponse) {
534                            BufferCacheServletResponse bufferCacheServletResponse =
535                                    (BufferCacheServletResponse)response;
536    
537                            bufferCacheServletResponse.setByteBuffer(byteBuffer);
538                    }
539                    else {
540                            write(
541                                    response, byteBuffer.array(),
542                                    byteBuffer.arrayOffset() + byteBuffer.position(),
543                                    byteBuffer.arrayOffset() + byteBuffer.limit());
544                    }
545            }
546    
547            public static void write(
548                            HttpServletResponse response, CharBuffer charBuffer)
549                    throws IOException {
550    
551                    if (response instanceof BufferCacheServletResponse) {
552                            BufferCacheServletResponse bufferCacheServletResponse =
553                                    (BufferCacheServletResponse)response;
554    
555                            bufferCacheServletResponse.setCharBuffer(charBuffer);
556                    }
557                    else {
558                            ByteBuffer byteBuffer = CharsetEncoderUtil.encode(
559                                    StringPool.UTF8, charBuffer);
560    
561                            write(response, byteBuffer);
562                    }
563            }
564    
565            public static void write(HttpServletResponse response, File file)
566                    throws IOException {
567    
568                    if (response instanceof BufferCacheServletResponse) {
569                            BufferCacheServletResponse bufferCacheServletResponse =
570                                    (BufferCacheServletResponse)response;
571    
572                            ByteBuffer byteBuffer = ByteBuffer.wrap(FileUtil.getBytes(file));
573    
574                            bufferCacheServletResponse.setByteBuffer(byteBuffer);
575                    }
576                    else {
577                            FileInputStream fileInputStream = new FileInputStream(file);
578    
579                            FileChannel fileChannel = fileInputStream.getChannel();
580    
581                            try {
582                                    long contentLength = fileChannel.size();
583    
584                                    setContentLength(response, contentLength);
585    
586                                    response.flushBuffer();
587    
588                                    fileChannel.transferTo(
589                                            0, contentLength,
590                                            Channels.newChannel(response.getOutputStream()));
591                            }
592                            finally {
593                                    fileChannel.close();
594                            }
595                    }
596            }
597    
598            public static void write(
599                            HttpServletResponse response, InputStream inputStream)
600                    throws IOException {
601    
602                    write(response, inputStream, 0);
603            }
604    
605            public static void write(
606                            HttpServletResponse response, InputStream inputStream,
607                            long contentLength)
608                    throws IOException {
609    
610                    OutputStream outputStream = null;
611    
612                    try {
613                            if (response.isCommitted()) {
614                                    return;
615                            }
616    
617                            if (contentLength > 0) {
618                                    setContentLength(response, contentLength);
619                            }
620    
621                            response.flushBuffer();
622    
623                            StreamUtil.transfer(inputStream, response.getOutputStream(), false);
624                    }
625                    finally {
626                            StreamUtil.cleanUp(inputStream, outputStream);
627                    }
628            }
629    
630            public static void write(HttpServletResponse response, String s)
631                    throws IOException {
632    
633                    if (response instanceof BufferCacheServletResponse) {
634                            BufferCacheServletResponse bufferCacheServletResponse =
635                                    (BufferCacheServletResponse)response;
636    
637                            bufferCacheServletResponse.setString(s);
638                    }
639                    else {
640                            ByteBuffer byteBuffer = CharsetEncoderUtil.encode(
641                                    StringPool.UTF8, s);
642    
643                            write(response, byteBuffer);
644                    }
645            }
646    
647            protected static InputStream copyRange(
648                            InputStream inputStream, OutputStream outputStream, long start,
649                            long length)
650                    throws IOException {
651    
652                    if (inputStream instanceof FileInputStream) {
653                            FileInputStream fileInputStream = (FileInputStream)inputStream;
654    
655                            FileChannel fileChannel = fileInputStream.getChannel();
656    
657                            fileChannel.transferTo(
658                                    start, length, Channels.newChannel(outputStream));
659    
660                            return fileInputStream;
661                    }
662                    else if (inputStream instanceof ByteArrayInputStream) {
663                            ByteArrayInputStream byteArrayInputStream =
664                                    (ByteArrayInputStream)inputStream;
665    
666                            byteArrayInputStream.reset();
667                            byteArrayInputStream.skip(start);
668    
669                            StreamUtil.transfer(byteArrayInputStream, outputStream, length);
670    
671                            return byteArrayInputStream;
672                    }
673                    else if (inputStream instanceof RandomAccessInputStream) {
674                            RandomAccessInputStream randomAccessInputStream =
675                                    (RandomAccessInputStream)inputStream;
676    
677                            randomAccessInputStream.seek(start);
678    
679                            StreamUtil.transfer(
680                                    randomAccessInputStream, outputStream, StreamUtil.BUFFER_SIZE,
681                                    false, length);
682    
683                            return randomAccessInputStream;
684                    }
685    
686                    return copyRange(
687                            new RandomAccessInputStream(inputStream), outputStream, start,
688                            length);
689            }
690    
691            protected static void setContentLength(
692                    HttpServletResponse response, long contentLength) {
693    
694                    response.setHeader(
695                            HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength));
696            }
697    
698            protected static void setHeaders(
699                    HttpServletRequest request, HttpServletResponse response,
700                    String fileName, String contentType, String contentDispositionType) {
701    
702                    if (_log.isDebugEnabled()) {
703                            _log.debug("Sending file of type " + contentType);
704                    }
705    
706                    // LEP-2201
707    
708                    if (Validator.isNotNull(contentType)) {
709                            response.setContentType(contentType);
710                    }
711    
712                    if (!response.containsHeader(HttpHeaders.CACHE_CONTROL)) {
713                            response.setHeader(
714                                    HttpHeaders.CACHE_CONTROL,
715                                    HttpHeaders.CACHE_CONTROL_PRIVATE_VALUE);
716                    }
717    
718                    if (Validator.isNull(fileName)) {
719                            return;
720                    }
721    
722                    String contentDispositionFileName = "filename=\"" + fileName + "\"";
723    
724                    // If necessary for non-ASCII characters, encode based on RFC 2184.
725                    // However, not all browsers support RFC 2184. See LEP-3127.
726    
727                    boolean ascii = true;
728    
729                    for (int i = 0; i < fileName.length(); i++) {
730                            if (!Validator.isAscii(fileName.charAt(i))) {
731                                    ascii = false;
732    
733                                    break;
734                            }
735                    }
736    
737                    if (!ascii) {
738                            String encodedFileName = HttpUtil.encodeURL(fileName, true);
739    
740                            if (BrowserSnifferUtil.isIe(request)) {
741                                    contentDispositionFileName =
742                                            "filename=\"" + encodedFileName + "\"";
743                            }
744                            else {
745                                    contentDispositionFileName =
746                                            "filename*=UTF-8''" + encodedFileName;
747                            }
748                    }
749    
750                    if (Validator.isNull(contentDispositionType)) {
751                            String extension = GetterUtil.getString(
752                                    FileUtil.getExtension(fileName));
753    
754                            extension = StringUtil.toLowerCase(extension);
755    
756                            String[] mimeTypesContentDispositionInline = null;
757    
758                            try {
759                                    mimeTypesContentDispositionInline = PropsUtil.getArray(
760                                            PropsKeys.MIME_TYPES_CONTENT_DISPOSITION_INLINE);
761                            }
762                            catch (Exception e) {
763                                    mimeTypesContentDispositionInline = new String[0];
764                            }
765    
766                            if (ArrayUtil.contains(
767                                            mimeTypesContentDispositionInline, extension)) {
768    
769                                    contentDispositionType = HttpHeaders.CONTENT_DISPOSITION_INLINE;
770    
771                                    contentType = MimeTypesUtil.getContentType(fileName);
772    
773                                    response.setContentType(contentType);
774                            }
775                            else {
776                                    contentDispositionType =
777                                            HttpHeaders.CONTENT_DISPOSITION_ATTACHMENT;
778                            }
779                    }
780    
781                    StringBundler sb = new StringBundler(4);
782    
783                    sb.append(contentDispositionType);
784                    sb.append(StringPool.SEMICOLON);
785                    sb.append(StringPool.SPACE);
786                    sb.append(contentDispositionFileName);
787    
788                    if (_log.isDebugEnabled()) {
789                            _log.debug("Setting content disposition header " + sb.toString());
790                    }
791    
792                    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, sb.toString());
793            }
794    
795            protected static void setHeaders(
796                    HttpServletRequest request, HttpServletResponse response,
797                    String fileName, String contentType, String contentDispositionType,
798                    Range range) {
799    
800                    setHeaders(
801                            request, response, fileName, contentType, contentDispositionType);
802    
803                    if (range != null) {
804                            response.setHeader(
805                                    HttpHeaders.CONTENT_RANGE, range.getContentRange());
806    
807                            response.setHeader(
808                                    HttpHeaders.CONTENT_LENGTH, String.valueOf(range.getLength()));
809                    }
810            }
811    
812            private static final String _CLIENT_ABORT_EXCEPTION =
813                    "org.apache.catalina.connector.ClientAbortException";
814    
815            private static final int _MAX_RANGE_FIELDS = GetterUtil.getInteger(
816                    PropsUtil.get(PropsKeys.WEB_SERVER_SERVLET_MAX_RANGE_FIELDS));
817    
818            private static final String _RANGE_REGEX =
819                    "^bytes=\\d*-\\d*(,\\s?\\d*-\\d*)*$";
820    
821            private static Log _log = LogFactoryUtil.getLog(ServletResponseUtil.class);
822    
823    }