View Javadoc

    1   // ========================================================================
    2   // Copyright 2002-2005 Mort Bay Consulting Pty. Ltd.
    3   // ------------------------------------------------------------------------
    4   // Licensed under the Apache License, Version 2.0 (the "License");
    5   // you may not use this file except in compliance with the License.
    6   // You may obtain a copy of the License at
    7   // http://www.apache.org/licenses/LICENSE-2.0
    8   // Unless required by applicable law or agreed to in writing, software
    9   // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  // ========================================================================
    14
    15  package org.mortbay.jetty;
    16
    17  import java.util.Enumeration;
    18  import java.util.List;
    19  import java.util.StringTokenizer;
    20
    21  import org.mortbay.log.Log;
    22  import org.mortbay.util.LazyList;
    23
    24  /* ------------------------------------------------------------ */
    25  /** Byte range inclusive of end points.
    26   * <PRE>
    27   *
    28   *   parses the following types of byte ranges:
    29   *
    30   *       bytes=100-499
    31   *       bytes=-300
    32   *       bytes=100-
    33   *       bytes=1-2,2-3,6-,-2
    34   *
    35   *   given an entity length, converts range to string
    36   *
    37   *       bytes 100-499/500
    38   *
    39   * </PRE>
    40   *
    41   * Based on RFC2616 3.12, 14.16, 14.35.1, 14.35.2
    42   * @version $version$
    43   * @author Helmut Hissen
    44   */
    45  public class InclusiveByteRange
    46  {
    47      long first = 0;
    48      long last  = 0;
    49
    50      public InclusiveByteRange(long first, long last)
    51      {
    52          this.first = first;
    53          this.last = last;
    54      }
    55
    56      public long getFirst()
    57      {
    58          return first;
    59      }
    60
    61      public long getLast()
    62      {
    63          return last;
    64      }
    65
    66
    67
    68      /* ------------------------------------------------------------ */
    69      /**
    70       * @param headers Enumeration of Range header fields.
    71       * @param size Size of the resource.
    72       * @return LazyList of satisfiable ranges
    73       */
    74      public static List satisfiableRanges(Enumeration headers,long size)
    75      {
    76          Object satRanges=null;
    77
    78          // walk through all Range headers
    79      headers:
    80          while (headers.hasMoreElements())
    81          {
    82              String header = (String) headers.nextElement();
    83              StringTokenizer tok = new StringTokenizer(header,"=,",false);
    84              String t=null;
    85              try
    86              {
    87                  // read all byte ranges for this header
    88                  while (tok.hasMoreTokens())
    89                  {
    90                      t=tok.nextToken().trim();
    91
    92                      long first = -1;
    93                      long last  = -1;
    94                      int d=t.indexOf('-');
    95                      if (d<0 || t.indexOf("-",d+1)>=0)
    96                      {
    97                          if ("bytes".equals(t))
    98                              continue;
    99                          Log.warn("Bad range format: {}",t);
    100                         continue headers;
    101                     }
    102                     else if (d==0)
    103                     {
    104                         if (d+1<t.length())
    105                             last = Long.parseLong(t.substring(d+1).trim());
    106                         else
    107                         {
    108                             Log.warn("Bad range format: {}",t);
    109                             continue headers;
    110                         }
    111                     }
    112                     else if (d+1<t.length())
    113                     {
    114                         first = Long.parseLong(t.substring(0,d).trim());
    115                         last = Long.parseLong(t.substring(d+1).trim());
    116                     }
    117                     else
    118                         first = Long.parseLong(t.substring(0,d).trim());
    119
    120
    121                     if (first == -1 && last == -1)
    122                         continue headers;
    123
    124                     if (first != -1 && last != -1 && (first > last))
    125                         continue headers;
    126
    127                     if (first<size)
    128                     {
    129                         InclusiveByteRange range = new
    130                             InclusiveByteRange(first, last);
    131                         satRanges=LazyList.add(satRanges,range);
    132                     }
    133                 }
    134             }
    135             catch(Exception e)
    136             {
    137                 Log.warn("Bad range format: "+t);
    138                 Log.ignore(e);
    139             }
    140         }
    141         return LazyList.getList(satRanges,true);
    142     }
    143
    144     /* ------------------------------------------------------------ */
    145     public long getFirst(long size)
    146     {
    147         if (first<0)
    148         {
    149             long tf=size-last;
    150             if (tf<0)
    151                 tf=0;
    152             return tf;
    153         }
    154         return first;
    155     }
    156
    157     /* ------------------------------------------------------------ */
    158     public long getLast(long size)
    159     {
    160         if (first<0)
    161             return size-1;
    162
    163         if (last<0 ||last>=size)
    164             return size-1;
    165         return last;
    166     }
    167
    168     /* ------------------------------------------------------------ */
    169     public long getSize(long size)
    170     {
    171         return getLast(size)-getFirst(size)+1;
    172     }
    173
    174
    175     /* ------------------------------------------------------------ */
    176     public String toHeaderRangeString(long size)
    177     {
    178         StringBuffer sb = new StringBuffer(40);
    179         sb.append("bytes ");
    180         sb.append(getFirst(size));
    181         sb.append('-');
    182         sb.append(getLast(size));
    183         sb.append("/");
    184         sb.append(size);
    185         return sb.toString();
    186     }
    187
    188     /* ------------------------------------------------------------ */
    189     public static String to416HeaderRangeString(long size)
    190     {
    191         StringBuffer sb = new StringBuffer(40);
    192         sb.append("bytes */");
    193         sb.append(size);
    194         return sb.toString();
    195     }
    196
    197
    198     /* ------------------------------------------------------------ */
    199     public String toString()
    200     {
    201         StringBuffer sb = new StringBuffer(60);
    202         sb.append(Long.toString(first));
    203         sb.append(":");
    204         sb.append(Long.toString(last));
    205         return sb.toString();
    206     }
    207
    208
    209 }
    210
    211
    212