001    /**
002     * Copyright (c) 2000-2013 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.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                                    int contentLength = 0;
498    
499                                    for (byte[] bytes : bytesArray) {
500                                            contentLength += bytes.length;
501                                    }
502    
503                                    response.setContentLength(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(), byteBuffer.position(),
542                                    byteBuffer.limit());
543                    }
544            }
545    
546            public static void write(
547                            HttpServletResponse response, CharBuffer charBuffer)
548                    throws IOException {
549    
550                    if (response instanceof BufferCacheServletResponse) {
551                            BufferCacheServletResponse bufferCacheServletResponse =
552                                    (BufferCacheServletResponse)response;
553    
554                            bufferCacheServletResponse.setCharBuffer(charBuffer);
555                    }
556                    else {
557                            ByteBuffer byteBuffer = CharsetEncoderUtil.encode(
558                                    StringPool.UTF8, charBuffer);
559    
560                            write(response, byteBuffer);
561                    }
562            }
563    
564            public static void write(HttpServletResponse response, File file)
565                    throws IOException {
566    
567                    if (response instanceof BufferCacheServletResponse) {
568                            BufferCacheServletResponse bufferCacheServletResponse =
569                                    (BufferCacheServletResponse)response;
570    
571                            ByteBuffer byteBuffer = ByteBuffer.wrap(FileUtil.getBytes(file));
572    
573                            bufferCacheServletResponse.setByteBuffer(byteBuffer);
574                    }
575                    else {
576                            FileInputStream fileInputStream = new FileInputStream(file);
577    
578                            FileChannel fileChannel = fileInputStream.getChannel();
579    
580                            try {
581                                    int contentLength = (int)fileChannel.size();
582    
583                                    response.setContentLength(contentLength);
584    
585                                    response.flushBuffer();
586    
587                                    fileChannel.transferTo(
588                                            0, contentLength,
589                                            Channels.newChannel(response.getOutputStream()));
590                            }
591                            finally {
592                                    fileChannel.close();
593                            }
594                    }
595            }
596    
597            public static void write(
598                            HttpServletResponse response, InputStream inputStream)
599                    throws IOException {
600    
601                    write(response, inputStream, 0);
602            }
603    
604            public static void write(
605                            HttpServletResponse response, InputStream inputStream,
606                            long contentLength)
607                    throws IOException {
608    
609                    OutputStream outputStream = null;
610    
611                    try {
612                            if (response.isCommitted()) {
613                                    return;
614                            }
615    
616                            if (contentLength > 0) {
617                                    response.setContentLength((int)contentLength);
618                            }
619    
620                            response.flushBuffer();
621    
622                            StreamUtil.transfer(inputStream, response.getOutputStream(), false);
623                    }
624                    finally {
625                            StreamUtil.cleanUp(inputStream, outputStream);
626                    }
627            }
628    
629            public static void write(HttpServletResponse response, String s)
630                    throws IOException {
631    
632                    if (response instanceof BufferCacheServletResponse) {
633                            BufferCacheServletResponse bufferCacheServletResponse =
634                                    (BufferCacheServletResponse)response;
635    
636                            bufferCacheServletResponse.setString(s);
637                    }
638                    else {
639                            ByteBuffer byteBuffer = CharsetEncoderUtil.encode(
640                                    StringPool.UTF8, s);
641    
642                            write(response, byteBuffer);
643                    }
644            }
645    
646            protected static InputStream copyRange(
647                            InputStream inputStream, OutputStream outputStream, long start,
648                            long length)
649                    throws IOException {
650    
651                    if (inputStream instanceof FileInputStream) {
652                            FileInputStream fileInputStream = (FileInputStream)inputStream;
653    
654                            FileChannel fileChannel = fileInputStream.getChannel();
655    
656                            fileChannel.transferTo(
657                                    start, length, Channels.newChannel(outputStream));
658    
659                            return fileInputStream;
660                    }
661                    else if (inputStream instanceof ByteArrayInputStream) {
662                            ByteArrayInputStream byteArrayInputStream =
663                                    (ByteArrayInputStream)inputStream;
664    
665                            byteArrayInputStream.reset();
666                            byteArrayInputStream.skip(start);
667    
668                            StreamUtil.transfer(byteArrayInputStream, outputStream, length);
669    
670                            return byteArrayInputStream;
671                    }
672                    else if (inputStream instanceof RandomAccessInputStream) {
673                            RandomAccessInputStream randomAccessInputStream =
674                                    (RandomAccessInputStream)inputStream;
675    
676                            randomAccessInputStream.seek(start);
677    
678                            StreamUtil.transfer(
679                                    randomAccessInputStream, outputStream, StreamUtil.BUFFER_SIZE,
680                                    false, length);
681    
682                            return randomAccessInputStream;
683                    }
684    
685                    return copyRange(
686                            new RandomAccessInputStream(inputStream), outputStream, start,
687                            length);
688            }
689    
690            protected static void setHeaders(
691                    HttpServletRequest request, HttpServletResponse response,
692                    String fileName, String contentType, String contentDispositionType) {
693    
694                    if (_log.isDebugEnabled()) {
695                            _log.debug("Sending file of type " + contentType);
696                    }
697    
698                    // LEP-2201
699    
700                    if (Validator.isNotNull(contentType)) {
701                            response.setContentType(contentType);
702                    }
703    
704                    if (!response.containsHeader(HttpHeaders.CACHE_CONTROL)) {
705                            response.setHeader(
706                                    HttpHeaders.CACHE_CONTROL,
707                                    HttpHeaders.CACHE_CONTROL_PRIVATE_VALUE);
708                    }
709    
710                    if (Validator.isNull(fileName)) {
711                            return;
712                    }
713    
714                    String contentDispositionFileName = "filename=\"" + fileName + "\"";
715    
716                    // If necessary for non-ASCII characters, encode based on RFC 2184.
717                    // However, not all browsers support RFC 2184. See LEP-3127.
718    
719                    boolean ascii = true;
720    
721                    for (int i = 0; i < fileName.length(); i++) {
722                            if (!Validator.isAscii(fileName.charAt(i))) {
723                                    ascii = false;
724    
725                                    break;
726                            }
727                    }
728    
729                    if (!ascii) {
730                            String encodedFileName = HttpUtil.encodeURL(fileName, true);
731    
732                            if (BrowserSnifferUtil.isIe(request)) {
733                                    contentDispositionFileName =
734                                            "filename=\"" + encodedFileName + "\"";
735                            }
736                            else {
737                                    contentDispositionFileName =
738                                            "filename*=UTF-8''" + encodedFileName;
739                            }
740                    }
741    
742                    if (Validator.isNull(contentDispositionType)) {
743                            String extension = GetterUtil.getString(
744                                    FileUtil.getExtension(fileName));
745    
746                            extension = StringUtil.toLowerCase(extension);
747    
748                            String[] mimeTypesContentDispositionInline = null;
749    
750                            try {
751                                    mimeTypesContentDispositionInline = PropsUtil.getArray(
752                                            PropsKeys.MIME_TYPES_CONTENT_DISPOSITION_INLINE);
753                            }
754                            catch (Exception e) {
755                                    mimeTypesContentDispositionInline = new String[0];
756                            }
757    
758                            if (ArrayUtil.contains(
759                                            mimeTypesContentDispositionInline, extension)) {
760    
761                                    contentDispositionType = HttpHeaders.CONTENT_DISPOSITION_INLINE;
762    
763                                    contentType = MimeTypesUtil.getContentType(fileName);
764    
765                                    response.setContentType(contentType);
766                            }
767                            else {
768                                    contentDispositionType =
769                                            HttpHeaders.CONTENT_DISPOSITION_ATTACHMENT;
770                            }
771                    }
772    
773                    StringBundler sb = new StringBundler(4);
774    
775                    sb.append(contentDispositionType);
776                    sb.append(StringPool.SEMICOLON);
777                    sb.append(StringPool.SPACE);
778                    sb.append(contentDispositionFileName);
779    
780                    if (_log.isDebugEnabled()) {
781                            _log.debug("Setting content disposition header " + sb.toString());
782                    }
783    
784                    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, sb.toString());
785            }
786    
787            protected static void setHeaders(
788                    HttpServletRequest request, HttpServletResponse response,
789                    String fileName, String contentType, String contentDispositionType,
790                    Range range) {
791    
792                    setHeaders(
793                            request, response, fileName, contentType, contentDispositionType);
794    
795                    if (range != null) {
796                            response.setHeader(
797                                    HttpHeaders.CONTENT_RANGE, range.getContentRange());
798    
799                            response.setHeader(
800                                    HttpHeaders.CONTENT_LENGTH, String.valueOf(range.getLength()));
801                    }
802            }
803    
804            private static final String _CLIENT_ABORT_EXCEPTION =
805                    "org.apache.catalina.connector.ClientAbortException";
806    
807            private static final int _MAX_RANGE_FIELDS = GetterUtil.getInteger(
808                    PropsUtil.get(PropsKeys.WEB_SERVER_SERVLET_MAX_RANGE_FIELDS));
809    
810            private static final String _RANGE_REGEX =
811                    "^bytes=\\d*-\\d*(,\\s?\\d*-\\d*)*$";
812    
813            private static Log _log = LogFactoryUtil.getLog(ServletResponseUtil.class);
814    
815    }