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