]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/server/InclusiveByteRange.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / server / InclusiveByteRange.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.server;
20
21 import java.util.Enumeration;
22 import java.util.List;
23 import java.util.StringTokenizer;
24
25 import org.eclipse.jetty.util.LazyList;
26 import org.eclipse.jetty.util.log.Log;
27 import org.eclipse.jetty.util.log.Logger;
28
29 /* ------------------------------------------------------------ */
30 /** Byte range inclusive of end points.
31  * <PRE>
32  * 
33  *   parses the following types of byte ranges:
34  * 
35  *       bytes=100-499
36  *       bytes=-300
37  *       bytes=100-
38  *       bytes=1-2,2-3,6-,-2
39  *
40  *   given an entity length, converts range to string
41  * 
42  *       bytes 100-499/500
43  * 
44  * </PRE>
45  * 
46  * Based on RFC2616 3.12, 14.16, 14.35.1, 14.35.2
47  * <p>
48  * And yes the spec does strangely say that while 10-20, is bytes 10 to 20 and 10- is bytes 10 until the end that -20 IS NOT bytes 0-20, but the last 20 bytes of the content.
49  * 
50  * @version $version$
51  * 
52  */
53 public class InclusiveByteRange 
54 {
55     private static final Logger LOG = Log.getLogger(InclusiveByteRange.class);
56
57     long first = 0;
58     long last  = 0;    
59
60     public InclusiveByteRange(long first, long last)
61     {
62         this.first = first;
63         this.last = last;
64     }
65     
66     public long getFirst()
67     {
68         return first;
69     }
70
71     public long getLast()
72     {
73         return last;
74     }    
75
76
77     
78     /* ------------------------------------------------------------ */
79     /** 
80      * @param headers Enumeration of Range header fields.
81      * @param size Size of the resource.
82      * @return LazyList of satisfiable ranges
83      */
84     public static List<InclusiveByteRange> satisfiableRanges(Enumeration<String> headers, long size)
85     {
86         Object satRanges=null;
87         
88         // walk through all Range headers
89     headers:
90         while (headers.hasMoreElements())
91         {
92             String header = headers.nextElement();
93             StringTokenizer tok = new StringTokenizer(header,"=,",false);
94             String t=null;
95             try
96             {
97                 // read all byte ranges for this header 
98                 while (tok.hasMoreTokens())
99                 {
100                     try
101                     {
102                         t = tok.nextToken().trim();
103
104                         long first = -1;
105                         long last = -1;
106                         int d = t.indexOf('-');
107                         if (d < 0 || t.indexOf("-",d + 1) >= 0)
108                         {
109                             if ("bytes".equals(t))
110                                 continue;
111                             LOG.warn("Bad range format: {}",t);
112                             continue headers;
113                         }
114                         else if (d == 0)
115                         {
116                             if (d + 1 < t.length())
117                                 last = Long.parseLong(t.substring(d + 1).trim());
118                             else
119                             {
120                                 LOG.warn("Bad range format: {}",t);
121                                 continue;
122                             }
123                         }
124                         else if (d + 1 < t.length())
125                         {
126                             first = Long.parseLong(t.substring(0,d).trim());
127                             last = Long.parseLong(t.substring(d + 1).trim());
128                         }
129                         else
130                             first = Long.parseLong(t.substring(0,d).trim());
131
132                         if (first == -1 && last == -1)
133                             continue headers;
134
135                         if (first != -1 && last != -1 && (first > last))
136                             continue headers;
137
138                         if (first < size)
139                         {
140                             InclusiveByteRange range = new InclusiveByteRange(first,last);
141                             satRanges = LazyList.add(satRanges,range);
142                         }
143                     }
144                     catch (NumberFormatException e)
145                     {
146                         LOG.warn("Bad range format: {}",t);
147                         LOG.ignore(e);
148                         continue;
149                     }
150                 }
151             }
152             catch(Exception e)
153             {
154                 LOG.warn("Bad range format: {}",t);
155                 LOG.ignore(e);
156             }    
157         }
158         return LazyList.getList(satRanges,true);
159     }
160
161     /* ------------------------------------------------------------ */
162     public long getFirst(long size)
163     {
164         if (first<0)
165         {
166             long tf=size-last;
167             if (tf<0)
168                 tf=0;
169             return tf;
170         }
171         return first;
172     }
173     
174     /* ------------------------------------------------------------ */
175     public long getLast(long size)
176     {
177         if (first<0)
178             return size-1;
179         
180         if (last<0 ||last>=size)
181             return size-1;
182         return last;
183     }
184     
185     /* ------------------------------------------------------------ */
186     public long getSize(long size)
187     {
188         return getLast(size)-getFirst(size)+1;
189     }
190
191
192     /* ------------------------------------------------------------ */
193     public String toHeaderRangeString(long size)
194     {
195         StringBuilder sb = new StringBuilder(40);
196         sb.append("bytes ");
197         sb.append(getFirst(size));
198         sb.append('-');
199         sb.append(getLast(size));
200         sb.append("/");
201         sb.append(size);
202         return sb.toString();
203     }
204
205     /* ------------------------------------------------------------ */
206     public static String to416HeaderRangeString(long size)
207     {
208         StringBuilder sb = new StringBuilder(40);
209         sb.append("bytes */");
210         sb.append(size);
211         return sb.toString();
212     }
213
214
215     /* ------------------------------------------------------------ */
216     @Override
217     public String toString()
218     {
219         StringBuilder sb = new StringBuilder(60);
220         sb.append(Long.toString(first));
221         sb.append(":");
222         sb.append(Long.toString(last));
223         return sb.toString();
224     }
225
226
227 }
228
229
230