Mercurial Hosting > luan
comparison src/org/eclipse/jetty/http/HttpFields.java @ 802:3428c60d7cfc
replace jetty jars with source
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 07 Sep 2016 21:15:48 -0600 |
parents | |
children | 8e9db0bbf4f9 |
comparison
equal
deleted
inserted
replaced
801:6a21393191c1 | 802:3428c60d7cfc |
---|---|
1 // | |
2 // ======================================================================== | |
3 // Copyright (c) 1995-2014 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.http; | |
20 | |
21 import java.io.IOException; | |
22 import java.io.UnsupportedEncodingException; | |
23 import java.text.SimpleDateFormat; | |
24 import java.util.ArrayList; | |
25 import java.util.Calendar; | |
26 import java.util.Collections; | |
27 import java.util.Collection; | |
28 import java.util.Date; | |
29 import java.util.Enumeration; | |
30 import java.util.GregorianCalendar; | |
31 import java.util.HashMap; | |
32 import java.util.Iterator; | |
33 import java.util.List; | |
34 import java.util.Locale; | |
35 import java.util.Map; | |
36 import java.util.NoSuchElementException; | |
37 import java.util.StringTokenizer; | |
38 import java.util.TimeZone; | |
39 import java.util.concurrent.ConcurrentHashMap; | |
40 import java.util.concurrent.ConcurrentMap; | |
41 | |
42 import org.eclipse.jetty.io.Buffer; | |
43 import org.eclipse.jetty.io.BufferCache; | |
44 import org.eclipse.jetty.io.BufferCache.CachedBuffer; | |
45 import org.eclipse.jetty.io.BufferDateCache; | |
46 import org.eclipse.jetty.io.BufferUtil; | |
47 import org.eclipse.jetty.io.ByteArrayBuffer; | |
48 import org.eclipse.jetty.util.LazyList; | |
49 import org.eclipse.jetty.util.QuotedStringTokenizer; | |
50 import org.eclipse.jetty.util.StringMap; | |
51 import org.eclipse.jetty.util.StringUtil; | |
52 import org.eclipse.jetty.util.log.Log; | |
53 import org.eclipse.jetty.util.log.Logger; | |
54 | |
55 /* ------------------------------------------------------------ */ | |
56 /** | |
57 * HTTP Fields. A collection of HTTP header and or Trailer fields. | |
58 * | |
59 * <p>This class is not synchronized as it is expected that modifications will only be performed by a | |
60 * single thread. | |
61 * | |
62 * | |
63 */ | |
64 public class HttpFields | |
65 { | |
66 private static final Logger LOG = Log.getLogger(HttpFields.class); | |
67 | |
68 /* ------------------------------------------------------------ */ | |
69 public static final String __COOKIE_DELIM="\"\\\n\r\t\f\b%+ ;="; | |
70 public static final TimeZone __GMT = TimeZone.getTimeZone("GMT"); | |
71 public static final BufferDateCache __dateCache = new BufferDateCache("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US); | |
72 | |
73 /* -------------------------------------------------------------- */ | |
74 static | |
75 { | |
76 __GMT.setID("GMT"); | |
77 __dateCache.setTimeZone(__GMT); | |
78 } | |
79 | |
80 /* ------------------------------------------------------------ */ | |
81 public final static String __separators = ", \t"; | |
82 | |
83 /* ------------------------------------------------------------ */ | |
84 private static final String[] DAYS = | |
85 { "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; | |
86 private static final String[] MONTHS = | |
87 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"}; | |
88 | |
89 | |
90 /* ------------------------------------------------------------ */ | |
91 private static class DateGenerator | |
92 { | |
93 private final StringBuilder buf = new StringBuilder(32); | |
94 private final GregorianCalendar gc = new GregorianCalendar(__GMT); | |
95 | |
96 /** | |
97 * Format HTTP date "EEE, dd MMM yyyy HH:mm:ss 'GMT'" | |
98 */ | |
99 public String formatDate(long date) | |
100 { | |
101 buf.setLength(0); | |
102 gc.setTimeInMillis(date); | |
103 | |
104 int day_of_week = gc.get(Calendar.DAY_OF_WEEK); | |
105 int day_of_month = gc.get(Calendar.DAY_OF_MONTH); | |
106 int month = gc.get(Calendar.MONTH); | |
107 int year = gc.get(Calendar.YEAR); | |
108 int century = year / 100; | |
109 year = year % 100; | |
110 | |
111 int hours = gc.get(Calendar.HOUR_OF_DAY); | |
112 int minutes = gc.get(Calendar.MINUTE); | |
113 int seconds = gc.get(Calendar.SECOND); | |
114 | |
115 buf.append(DAYS[day_of_week]); | |
116 buf.append(','); | |
117 buf.append(' '); | |
118 StringUtil.append2digits(buf, day_of_month); | |
119 | |
120 buf.append(' '); | |
121 buf.append(MONTHS[month]); | |
122 buf.append(' '); | |
123 StringUtil.append2digits(buf, century); | |
124 StringUtil.append2digits(buf, year); | |
125 | |
126 buf.append(' '); | |
127 StringUtil.append2digits(buf, hours); | |
128 buf.append(':'); | |
129 StringUtil.append2digits(buf, minutes); | |
130 buf.append(':'); | |
131 StringUtil.append2digits(buf, seconds); | |
132 buf.append(" GMT"); | |
133 return buf.toString(); | |
134 } | |
135 | |
136 /* ------------------------------------------------------------ */ | |
137 /** | |
138 * Format "EEE, dd-MMM-yy HH:mm:ss 'GMT'" for cookies | |
139 */ | |
140 public void formatCookieDate(StringBuilder buf, long date) | |
141 { | |
142 gc.setTimeInMillis(date); | |
143 | |
144 int day_of_week = gc.get(Calendar.DAY_OF_WEEK); | |
145 int day_of_month = gc.get(Calendar.DAY_OF_MONTH); | |
146 int month = gc.get(Calendar.MONTH); | |
147 int year = gc.get(Calendar.YEAR); | |
148 year = year % 10000; | |
149 | |
150 int epoch = (int) ((date / 1000) % (60 * 60 * 24)); | |
151 int seconds = epoch % 60; | |
152 epoch = epoch / 60; | |
153 int minutes = epoch % 60; | |
154 int hours = epoch / 60; | |
155 | |
156 buf.append(DAYS[day_of_week]); | |
157 buf.append(','); | |
158 buf.append(' '); | |
159 StringUtil.append2digits(buf, day_of_month); | |
160 | |
161 buf.append('-'); | |
162 buf.append(MONTHS[month]); | |
163 buf.append('-'); | |
164 StringUtil.append2digits(buf, year/100); | |
165 StringUtil.append2digits(buf, year%100); | |
166 | |
167 buf.append(' '); | |
168 StringUtil.append2digits(buf, hours); | |
169 buf.append(':'); | |
170 StringUtil.append2digits(buf, minutes); | |
171 buf.append(':'); | |
172 StringUtil.append2digits(buf, seconds); | |
173 buf.append(" GMT"); | |
174 } | |
175 } | |
176 | |
177 /* ------------------------------------------------------------ */ | |
178 private static final ThreadLocal<DateGenerator> __dateGenerator =new ThreadLocal<DateGenerator>() | |
179 { | |
180 @Override | |
181 protected DateGenerator initialValue() | |
182 { | |
183 return new DateGenerator(); | |
184 } | |
185 }; | |
186 | |
187 /* ------------------------------------------------------------ */ | |
188 /** | |
189 * Format HTTP date "EEE, dd MMM yyyy HH:mm:ss 'GMT'" | |
190 */ | |
191 public static String formatDate(long date) | |
192 { | |
193 return __dateGenerator.get().formatDate(date); | |
194 } | |
195 | |
196 /* ------------------------------------------------------------ */ | |
197 /** | |
198 * Format "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'" for cookies | |
199 */ | |
200 public static void formatCookieDate(StringBuilder buf, long date) | |
201 { | |
202 __dateGenerator.get().formatCookieDate(buf,date); | |
203 } | |
204 | |
205 /* ------------------------------------------------------------ */ | |
206 /** | |
207 * Format "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'" for cookies | |
208 */ | |
209 public static String formatCookieDate(long date) | |
210 { | |
211 StringBuilder buf = new StringBuilder(28); | |
212 formatCookieDate(buf, date); | |
213 return buf.toString(); | |
214 } | |
215 | |
216 /* ------------------------------------------------------------ */ | |
217 private final static String __dateReceiveFmt[] = | |
218 { | |
219 "EEE, dd MMM yyyy HH:mm:ss zzz", | |
220 "EEE, dd-MMM-yy HH:mm:ss", | |
221 "EEE MMM dd HH:mm:ss yyyy", | |
222 | |
223 "EEE, dd MMM yyyy HH:mm:ss", "EEE dd MMM yyyy HH:mm:ss zzz", | |
224 "EEE dd MMM yyyy HH:mm:ss", "EEE MMM dd yyyy HH:mm:ss zzz", "EEE MMM dd yyyy HH:mm:ss", | |
225 "EEE MMM-dd-yyyy HH:mm:ss zzz", "EEE MMM-dd-yyyy HH:mm:ss", "dd MMM yyyy HH:mm:ss zzz", | |
226 "dd MMM yyyy HH:mm:ss", "dd-MMM-yy HH:mm:ss zzz", "dd-MMM-yy HH:mm:ss", "MMM dd HH:mm:ss yyyy zzz", | |
227 "MMM dd HH:mm:ss yyyy", "EEE MMM dd HH:mm:ss yyyy zzz", | |
228 "EEE, MMM dd HH:mm:ss yyyy zzz", "EEE, MMM dd HH:mm:ss yyyy", "EEE, dd-MMM-yy HH:mm:ss zzz", | |
229 "EEE dd-MMM-yy HH:mm:ss zzz", "EEE dd-MMM-yy HH:mm:ss", | |
230 }; | |
231 | |
232 /* ------------------------------------------------------------ */ | |
233 private static class DateParser | |
234 { | |
235 final SimpleDateFormat _dateReceive[]= new SimpleDateFormat[__dateReceiveFmt.length]; | |
236 | |
237 long parse(final String dateVal) | |
238 { | |
239 for (int i = 0; i < _dateReceive.length; i++) | |
240 { | |
241 if (_dateReceive[i] == null) | |
242 { | |
243 _dateReceive[i] = new SimpleDateFormat(__dateReceiveFmt[i], Locale.US); | |
244 _dateReceive[i].setTimeZone(__GMT); | |
245 } | |
246 | |
247 try | |
248 { | |
249 Date date = (Date) _dateReceive[i].parseObject(dateVal); | |
250 return date.getTime(); | |
251 } | |
252 catch (java.lang.Exception e) | |
253 { | |
254 // LOG.ignore(e); | |
255 } | |
256 } | |
257 | |
258 if (dateVal.endsWith(" GMT")) | |
259 { | |
260 final String val = dateVal.substring(0, dateVal.length() - 4); | |
261 | |
262 for (int i = 0; i < _dateReceive.length; i++) | |
263 { | |
264 try | |
265 { | |
266 Date date = (Date) _dateReceive[i].parseObject(val); | |
267 return date.getTime(); | |
268 } | |
269 catch (java.lang.Exception e) | |
270 { | |
271 // LOG.ignore(e); | |
272 } | |
273 } | |
274 } | |
275 return -1; | |
276 } | |
277 } | |
278 | |
279 /* ------------------------------------------------------------ */ | |
280 public static long parseDate(String date) | |
281 { | |
282 return __dateParser.get().parse(date); | |
283 } | |
284 | |
285 /* ------------------------------------------------------------ */ | |
286 private static final ThreadLocal<DateParser> __dateParser =new ThreadLocal<DateParser>() | |
287 { | |
288 @Override | |
289 protected DateParser initialValue() | |
290 { | |
291 return new DateParser(); | |
292 } | |
293 }; | |
294 | |
295 /* -------------------------------------------------------------- */ | |
296 public final static String __01Jan1970=formatDate(0); | |
297 public final static Buffer __01Jan1970_BUFFER=new ByteArrayBuffer(__01Jan1970); | |
298 public final static String __01Jan1970_COOKIE = formatCookieDate(0).trim(); | |
299 | |
300 /* -------------------------------------------------------------- */ | |
301 private final ArrayList<Field> _fields = new ArrayList<Field>(20); | |
302 private final HashMap<Buffer,Field> _names = new HashMap<Buffer,Field>(32); | |
303 | |
304 /* ------------------------------------------------------------ */ | |
305 /** | |
306 * Constructor. | |
307 */ | |
308 public HttpFields() | |
309 { | |
310 } | |
311 | |
312 // TODO externalize this cache so it can be configurable | |
313 private static ConcurrentMap<String, Buffer> __cache = new ConcurrentHashMap<String, Buffer>(); | |
314 private static int __cacheSize = Integer.getInteger("org.eclipse.jetty.http.HttpFields.CACHE",2000); | |
315 | |
316 /* -------------------------------------------------------------- */ | |
317 private Buffer convertValue(String value) | |
318 { | |
319 Buffer buffer = __cache.get(value); | |
320 if (buffer!=null) | |
321 return buffer; | |
322 | |
323 try | |
324 { | |
325 buffer = new ByteArrayBuffer(value,StringUtil.__ISO_8859_1); | |
326 | |
327 if (__cacheSize>0) | |
328 { | |
329 if (__cache.size()>__cacheSize) | |
330 __cache.clear(); | |
331 Buffer b=__cache.putIfAbsent(value,buffer); | |
332 if (b!=null) | |
333 buffer=b; | |
334 } | |
335 | |
336 return buffer; | |
337 } | |
338 catch (UnsupportedEncodingException e) | |
339 { | |
340 throw new RuntimeException(e); | |
341 } | |
342 } | |
343 | |
344 /* -------------------------------------------------------------- */ | |
345 /** | |
346 * Get Collection of header names. | |
347 */ | |
348 public Collection<String> getFieldNamesCollection() | |
349 { | |
350 final List<String> list = new ArrayList<String>(_fields.size()); | |
351 | |
352 for (Field f : _fields) | |
353 { | |
354 if (f!=null) | |
355 list.add(BufferUtil.to8859_1_String(f._name)); | |
356 } | |
357 return list; | |
358 } | |
359 | |
360 /* -------------------------------------------------------------- */ | |
361 /** | |
362 * Get enumeration of header _names. Returns an enumeration of strings representing the header | |
363 * _names for this request. | |
364 */ | |
365 public Enumeration<String> getFieldNames() | |
366 { | |
367 final Enumeration<?> buffers = Collections.enumeration(_names.keySet()); | |
368 return new Enumeration<String>() | |
369 { | |
370 public String nextElement() | |
371 { | |
372 return buffers.nextElement().toString(); | |
373 } | |
374 | |
375 public boolean hasMoreElements() | |
376 { | |
377 return buffers.hasMoreElements(); | |
378 } | |
379 }; | |
380 } | |
381 | |
382 /* ------------------------------------------------------------ */ | |
383 public int size() | |
384 { | |
385 return _fields.size(); | |
386 } | |
387 | |
388 /* ------------------------------------------------------------ */ | |
389 /** | |
390 * Get a Field by index. | |
391 * @return A Field value or null if the Field value has not been set | |
392 * | |
393 */ | |
394 public Field getField(int i) | |
395 { | |
396 return _fields.get(i); | |
397 } | |
398 | |
399 /* ------------------------------------------------------------ */ | |
400 private Field getField(String name) | |
401 { | |
402 return _names.get(HttpHeaders.CACHE.lookup(name)); | |
403 } | |
404 | |
405 /* ------------------------------------------------------------ */ | |
406 private Field getField(Buffer name) | |
407 { | |
408 return _names.get(HttpHeaders.CACHE.lookup(name)); | |
409 } | |
410 | |
411 /* ------------------------------------------------------------ */ | |
412 public boolean containsKey(Buffer name) | |
413 { | |
414 return _names.containsKey(HttpHeaders.CACHE.lookup(name)); | |
415 } | |
416 | |
417 /* ------------------------------------------------------------ */ | |
418 public boolean containsKey(String name) | |
419 { | |
420 return _names.containsKey(HttpHeaders.CACHE.lookup(name)); | |
421 } | |
422 | |
423 /* -------------------------------------------------------------- */ | |
424 /** | |
425 * @return the value of a field, or null if not found. For multiple fields of the same name, | |
426 * only the first is returned. | |
427 * @param name the case-insensitive field name | |
428 */ | |
429 public String getStringField(String name) | |
430 { | |
431 Field field = getField(name); | |
432 return field==null?null:field.getValue(); | |
433 } | |
434 | |
435 /* -------------------------------------------------------------- */ | |
436 /** | |
437 * @return the value of a field, or null if not found. For multiple fields of the same name, | |
438 * only the first is returned. | |
439 * @param name the case-insensitive field name | |
440 */ | |
441 public String getStringField(Buffer name) | |
442 { | |
443 Field field = getField(name); | |
444 return field==null?null:field.getValue(); | |
445 } | |
446 | |
447 /* -------------------------------------------------------------- */ | |
448 /** | |
449 * @return the value of a field, or null if not found. For multiple fields of the same name, | |
450 * only the first is returned. | |
451 * @param name the case-insensitive field name | |
452 */ | |
453 public Buffer get(Buffer name) | |
454 { | |
455 Field field = getField(name); | |
456 return field==null?null:field._value; | |
457 } | |
458 | |
459 | |
460 /* -------------------------------------------------------------- */ | |
461 /** | |
462 * Get multi headers | |
463 * | |
464 * @return Enumeration of the values, or null if no such header. | |
465 * @param name the case-insensitive field name | |
466 */ | |
467 public Collection<String> getValuesCollection(String name) | |
468 { | |
469 Field field = getField(name); | |
470 if (field==null) | |
471 return null; | |
472 | |
473 final List<String> list = new ArrayList<String>(); | |
474 | |
475 while(field!=null) | |
476 { | |
477 list.add(field.getValue()); | |
478 field=field._next; | |
479 } | |
480 return list; | |
481 } | |
482 | |
483 /* -------------------------------------------------------------- */ | |
484 /** | |
485 * Get multi headers | |
486 * | |
487 * @return Enumeration of the values | |
488 * @param name the case-insensitive field name | |
489 */ | |
490 public Enumeration<String> getValues(String name) | |
491 { | |
492 final Field field = getField(name); | |
493 if (field == null) | |
494 { | |
495 List<String> empty=Collections.emptyList(); | |
496 return Collections.enumeration(empty); | |
497 } | |
498 | |
499 return new Enumeration<String>() | |
500 { | |
501 Field f = field; | |
502 | |
503 public boolean hasMoreElements() | |
504 { | |
505 return f != null; | |
506 } | |
507 | |
508 public String nextElement() throws NoSuchElementException | |
509 { | |
510 if (f == null) throw new NoSuchElementException(); | |
511 Field n = f; | |
512 f = f._next; | |
513 return n.getValue(); | |
514 } | |
515 }; | |
516 } | |
517 | |
518 /* -------------------------------------------------------------- */ | |
519 /** | |
520 * Get multi headers | |
521 * | |
522 * @return Enumeration of the value Strings | |
523 * @param name the case-insensitive field name | |
524 */ | |
525 public Enumeration<String> getValues(Buffer name) | |
526 { | |
527 final Field field = getField(name); | |
528 if (field == null) | |
529 { | |
530 List<String> empty=Collections.emptyList(); | |
531 return Collections.enumeration(empty); | |
532 } | |
533 | |
534 return new Enumeration<String>() | |
535 { | |
536 Field f = field; | |
537 | |
538 public boolean hasMoreElements() | |
539 { | |
540 return f != null; | |
541 } | |
542 | |
543 public String nextElement() throws NoSuchElementException | |
544 { | |
545 if (f == null) throw new NoSuchElementException(); | |
546 Field n = f; | |
547 f = f._next; | |
548 return n.getValue(); | |
549 } | |
550 }; | |
551 } | |
552 | |
553 /* -------------------------------------------------------------- */ | |
554 /** | |
555 * Get multi field values with separator. The multiple values can be represented as separate | |
556 * headers of the same name, or by a single header using the separator(s), or a combination of | |
557 * both. Separators may be quoted. | |
558 * | |
559 * @param name the case-insensitive field name | |
560 * @param separators String of separators. | |
561 * @return Enumeration of the values, or null if no such header. | |
562 */ | |
563 public Enumeration<String> getValues(String name, final String separators) | |
564 { | |
565 final Enumeration<String> e = getValues(name); | |
566 if (e == null) | |
567 return null; | |
568 return new Enumeration<String>() | |
569 { | |
570 QuotedStringTokenizer tok = null; | |
571 | |
572 public boolean hasMoreElements() | |
573 { | |
574 if (tok != null && tok.hasMoreElements()) return true; | |
575 while (e.hasMoreElements()) | |
576 { | |
577 String value = e.nextElement(); | |
578 tok = new QuotedStringTokenizer(value, separators, false, false); | |
579 if (tok.hasMoreElements()) return true; | |
580 } | |
581 tok = null; | |
582 return false; | |
583 } | |
584 | |
585 public String nextElement() throws NoSuchElementException | |
586 { | |
587 if (!hasMoreElements()) throw new NoSuchElementException(); | |
588 String next = (String) tok.nextElement(); | |
589 if (next != null) next = next.trim(); | |
590 return next; | |
591 } | |
592 }; | |
593 } | |
594 | |
595 | |
596 /* -------------------------------------------------------------- */ | |
597 /** | |
598 * Set a field. | |
599 * | |
600 * @param name the name of the field | |
601 * @param value the value of the field. If null the field is cleared. | |
602 */ | |
603 public void put(String name, String value) | |
604 { | |
605 if (value==null) | |
606 remove(name); | |
607 else | |
608 { | |
609 Buffer n = HttpHeaders.CACHE.lookup(name); | |
610 Buffer v = convertValue(value); | |
611 put(n, v); | |
612 } | |
613 } | |
614 | |
615 /* -------------------------------------------------------------- */ | |
616 /** | |
617 * Set a field. | |
618 * | |
619 * @param name the name of the field | |
620 * @param value the value of the field. If null the field is cleared. | |
621 */ | |
622 public void put(Buffer name, String value) | |
623 { | |
624 Buffer n = HttpHeaders.CACHE.lookup(name); | |
625 Buffer v = convertValue(value); | |
626 put(n, v); | |
627 } | |
628 | |
629 /* -------------------------------------------------------------- */ | |
630 /** | |
631 * Set a field. | |
632 * | |
633 * @param name the name of the field | |
634 * @param value the value of the field. If null the field is cleared. | |
635 */ | |
636 public void put(Buffer name, Buffer value) | |
637 { | |
638 remove(name); | |
639 if (value == null) | |
640 return; | |
641 | |
642 if (!(name instanceof BufferCache.CachedBuffer)) | |
643 name = HttpHeaders.CACHE.lookup(name); | |
644 if (!(value instanceof CachedBuffer)) | |
645 value= HttpHeaderValues.CACHE.lookup(value).asImmutableBuffer(); | |
646 | |
647 // new value; | |
648 Field field = new Field(name, value); | |
649 _fields.add(field); | |
650 _names.put(name, field); | |
651 } | |
652 | |
653 /* -------------------------------------------------------------- */ | |
654 /** | |
655 * Set a field. | |
656 * | |
657 * @param name the name of the field | |
658 * @param list the List value of the field. If null the field is cleared. | |
659 */ | |
660 public void put(String name, List<?> list) | |
661 { | |
662 if (list == null || list.size() == 0) | |
663 { | |
664 remove(name); | |
665 return; | |
666 } | |
667 Buffer n = HttpHeaders.CACHE.lookup(name); | |
668 | |
669 Object v = list.get(0); | |
670 if (v != null) | |
671 put(n, HttpHeaderValues.CACHE.lookup(v.toString())); | |
672 else | |
673 remove(n); | |
674 | |
675 if (list.size() > 1) | |
676 { | |
677 java.util.Iterator<?> iter = list.iterator(); | |
678 iter.next(); | |
679 while (iter.hasNext()) | |
680 { | |
681 v = iter.next(); | |
682 if (v != null) put(n, HttpHeaderValues.CACHE.lookup(v.toString())); | |
683 } | |
684 } | |
685 } | |
686 | |
687 /* -------------------------------------------------------------- */ | |
688 /** | |
689 * Add to or set a field. If the field is allowed to have multiple values, add will add multiple | |
690 * headers of the same name. | |
691 * | |
692 * @param name the name of the field | |
693 * @param value the value of the field. | |
694 * @exception IllegalArgumentException If the name is a single valued field and already has a | |
695 * value. | |
696 */ | |
697 public void add(String name, String value) throws IllegalArgumentException | |
698 { | |
699 if (value==null) | |
700 return; | |
701 Buffer n = HttpHeaders.CACHE.lookup(name); | |
702 Buffer v = convertValue(value); | |
703 add(n, v); | |
704 } | |
705 | |
706 /* -------------------------------------------------------------- */ | |
707 /** | |
708 * Add to or set a field. If the field is allowed to have multiple values, add will add multiple | |
709 * headers of the same name. | |
710 * | |
711 * @param name the name of the field | |
712 * @param value the value of the field. | |
713 * @exception IllegalArgumentException If the name is a single valued field and already has a | |
714 * value. | |
715 */ | |
716 public void add(Buffer name, Buffer value) throws IllegalArgumentException | |
717 { | |
718 if (value == null) throw new IllegalArgumentException("null value"); | |
719 | |
720 if (!(name instanceof CachedBuffer)) | |
721 name = HttpHeaders.CACHE.lookup(name); | |
722 name=name.asImmutableBuffer(); | |
723 | |
724 if (!(value instanceof CachedBuffer) && HttpHeaderValues.hasKnownValues(HttpHeaders.CACHE.getOrdinal(name))) | |
725 value= HttpHeaderValues.CACHE.lookup(value); | |
726 value=value.asImmutableBuffer(); | |
727 | |
728 Field field = _names.get(name); | |
729 Field last = null; | |
730 while (field != null) | |
731 { | |
732 last = field; | |
733 field = field._next; | |
734 } | |
735 | |
736 // create the field | |
737 field = new Field(name, value); | |
738 _fields.add(field); | |
739 | |
740 // look for chain to add too | |
741 if (last != null) | |
742 last._next = field; | |
743 else | |
744 _names.put(name, field); | |
745 } | |
746 | |
747 /* ------------------------------------------------------------ */ | |
748 /** | |
749 * Remove a field. | |
750 * | |
751 * @param name | |
752 */ | |
753 public void remove(String name) | |
754 { | |
755 remove(HttpHeaders.CACHE.lookup(name)); | |
756 } | |
757 | |
758 /* ------------------------------------------------------------ */ | |
759 /** | |
760 * Remove a field. | |
761 * | |
762 * @param name | |
763 */ | |
764 public void remove(Buffer name) | |
765 { | |
766 if (!(name instanceof BufferCache.CachedBuffer)) | |
767 name = HttpHeaders.CACHE.lookup(name); | |
768 Field field = _names.remove(name); | |
769 while (field != null) | |
770 { | |
771 _fields.remove(field); | |
772 field = field._next; | |
773 } | |
774 } | |
775 | |
776 /* -------------------------------------------------------------- */ | |
777 /** | |
778 * Get a header as an long value. Returns the value of an integer field or -1 if not found. The | |
779 * case of the field name is ignored. | |
780 * | |
781 * @param name the case-insensitive field name | |
782 * @exception NumberFormatException If bad long found | |
783 */ | |
784 public long getLongField(String name) throws NumberFormatException | |
785 { | |
786 Field field = getField(name); | |
787 return field==null?-1L:field.getLongValue(); | |
788 } | |
789 | |
790 /* -------------------------------------------------------------- */ | |
791 /** | |
792 * Get a header as an long value. Returns the value of an integer field or -1 if not found. The | |
793 * case of the field name is ignored. | |
794 * | |
795 * @param name the case-insensitive field name | |
796 * @exception NumberFormatException If bad long found | |
797 */ | |
798 public long getLongField(Buffer name) throws NumberFormatException | |
799 { | |
800 Field field = getField(name); | |
801 return field==null?-1L:field.getLongValue(); | |
802 } | |
803 | |
804 /* -------------------------------------------------------------- */ | |
805 /** | |
806 * Get a header as a date value. Returns the value of a date field, or -1 if not found. The case | |
807 * of the field name is ignored. | |
808 * | |
809 * @param name the case-insensitive field name | |
810 */ | |
811 public long getDateField(String name) | |
812 { | |
813 Field field = getField(name); | |
814 if (field == null) | |
815 return -1; | |
816 | |
817 String val = valueParameters(BufferUtil.to8859_1_String(field._value), null); | |
818 if (val == null) | |
819 return -1; | |
820 | |
821 final long date = __dateParser.get().parse(val); | |
822 if (date==-1) | |
823 throw new IllegalArgumentException("Cannot convert date: " + val); | |
824 return date; | |
825 } | |
826 | |
827 /* -------------------------------------------------------------- */ | |
828 /** | |
829 * Sets the value of an long field. | |
830 * | |
831 * @param name the field name | |
832 * @param value the field long value | |
833 */ | |
834 public void putLongField(Buffer name, long value) | |
835 { | |
836 Buffer v = BufferUtil.toBuffer(value); | |
837 put(name, v); | |
838 } | |
839 | |
840 /* -------------------------------------------------------------- */ | |
841 /** | |
842 * Sets the value of an long field. | |
843 * | |
844 * @param name the field name | |
845 * @param value the field long value | |
846 */ | |
847 public void putLongField(String name, long value) | |
848 { | |
849 Buffer n = HttpHeaders.CACHE.lookup(name); | |
850 Buffer v = BufferUtil.toBuffer(value); | |
851 put(n, v); | |
852 } | |
853 | |
854 /* -------------------------------------------------------------- */ | |
855 /** | |
856 * Sets the value of an long field. | |
857 * | |
858 * @param name the field name | |
859 * @param value the field long value | |
860 */ | |
861 public void addLongField(String name, long value) | |
862 { | |
863 Buffer n = HttpHeaders.CACHE.lookup(name); | |
864 Buffer v = BufferUtil.toBuffer(value); | |
865 add(n, v); | |
866 } | |
867 | |
868 /* -------------------------------------------------------------- */ | |
869 /** | |
870 * Sets the value of an long field. | |
871 * | |
872 * @param name the field name | |
873 * @param value the field long value | |
874 */ | |
875 public void addLongField(Buffer name, long value) | |
876 { | |
877 Buffer v = BufferUtil.toBuffer(value); | |
878 add(name, v); | |
879 } | |
880 | |
881 /* -------------------------------------------------------------- */ | |
882 /** | |
883 * Sets the value of a date field. | |
884 * | |
885 * @param name the field name | |
886 * @param date the field date value | |
887 */ | |
888 public void putDateField(Buffer name, long date) | |
889 { | |
890 String d=formatDate(date); | |
891 Buffer v = new ByteArrayBuffer(d); | |
892 put(name, v); | |
893 } | |
894 | |
895 /* -------------------------------------------------------------- */ | |
896 /** | |
897 * Sets the value of a date field. | |
898 * | |
899 * @param name the field name | |
900 * @param date the field date value | |
901 */ | |
902 public void putDateField(String name, long date) | |
903 { | |
904 Buffer n = HttpHeaders.CACHE.lookup(name); | |
905 putDateField(n,date); | |
906 } | |
907 | |
908 /* -------------------------------------------------------------- */ | |
909 /** | |
910 * Sets the value of a date field. | |
911 * | |
912 * @param name the field name | |
913 * @param date the field date value | |
914 */ | |
915 public void addDateField(String name, long date) | |
916 { | |
917 String d=formatDate(date); | |
918 Buffer n = HttpHeaders.CACHE.lookup(name); | |
919 Buffer v = new ByteArrayBuffer(d); | |
920 add(n, v); | |
921 } | |
922 | |
923 /* ------------------------------------------------------------ */ | |
924 /** | |
925 * Format a set cookie value | |
926 * | |
927 * @param cookie The cookie. | |
928 */ | |
929 public void addSetCookie(HttpCookie cookie) | |
930 { | |
931 addSetCookie( | |
932 cookie.getName(), | |
933 cookie.getValue(), | |
934 cookie.getDomain(), | |
935 cookie.getPath(), | |
936 cookie.getMaxAge(), | |
937 cookie.getComment(), | |
938 cookie.isSecure(), | |
939 cookie.isHttpOnly(), | |
940 cookie.getVersion()); | |
941 } | |
942 | |
943 /** | |
944 * Format a set cookie value | |
945 * | |
946 * @param name the name | |
947 * @param value the value | |
948 * @param domain the domain | |
949 * @param path the path | |
950 * @param maxAge the maximum age | |
951 * @param comment the comment (only present on versions > 0) | |
952 * @param isSecure true if secure cookie | |
953 * @param isHttpOnly true if for http only | |
954 * @param version version of cookie logic to use (0 == default behavior) | |
955 */ | |
956 public void addSetCookie( | |
957 final String name, | |
958 final String value, | |
959 final String domain, | |
960 final String path, | |
961 final long maxAge, | |
962 final String comment, | |
963 final boolean isSecure, | |
964 final boolean isHttpOnly, | |
965 int version) | |
966 { | |
967 String delim=__COOKIE_DELIM; | |
968 | |
969 // Check arguments | |
970 if (name == null || name.length() == 0) | |
971 throw new IllegalArgumentException("Bad cookie name"); | |
972 | |
973 // Format value and params | |
974 StringBuilder buf = new StringBuilder(128); | |
975 String name_value_params; | |
976 QuotedStringTokenizer.quoteIfNeeded(buf, name, delim); | |
977 buf.append('='); | |
978 String start=buf.toString(); | |
979 boolean hasDomain = false; | |
980 boolean hasPath = false; | |
981 | |
982 if (value != null && value.length() > 0) | |
983 QuotedStringTokenizer.quoteIfNeeded(buf, value, delim); | |
984 | |
985 if (comment != null && comment.length() > 0) | |
986 { | |
987 buf.append(";Comment="); | |
988 QuotedStringTokenizer.quoteIfNeeded(buf, comment, delim); | |
989 } | |
990 | |
991 if (path != null && path.length() > 0) | |
992 { | |
993 hasPath = true; | |
994 buf.append(";Path="); | |
995 if (path.trim().startsWith("\"")) | |
996 buf.append(path); | |
997 else | |
998 QuotedStringTokenizer.quoteIfNeeded(buf,path,delim); | |
999 } | |
1000 if (domain != null && domain.length() > 0) | |
1001 { | |
1002 hasDomain = true; | |
1003 buf.append(";Domain="); | |
1004 QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase(Locale.ENGLISH),delim); | |
1005 } | |
1006 | |
1007 if (maxAge >= 0) | |
1008 { | |
1009 // Always add the expires param as some browsers still don't handle max-age | |
1010 buf.append(";Expires="); | |
1011 if (maxAge == 0) | |
1012 buf.append(__01Jan1970_COOKIE); | |
1013 else | |
1014 formatCookieDate(buf, System.currentTimeMillis() + 1000L * maxAge); | |
1015 | |
1016 if (version >0) | |
1017 { | |
1018 buf.append(";Max-Age="); | |
1019 buf.append(maxAge); | |
1020 } | |
1021 } | |
1022 | |
1023 if (isSecure) | |
1024 buf.append(";Secure"); | |
1025 if (isHttpOnly) | |
1026 buf.append(";HttpOnly"); | |
1027 | |
1028 name_value_params = buf.toString(); | |
1029 | |
1030 // remove existing set-cookie of same name | |
1031 Field field = getField(HttpHeaders.SET_COOKIE); | |
1032 Field last=null; | |
1033 while (field!=null) | |
1034 { | |
1035 String val = (field._value == null ? null : field._value.toString()); | |
1036 if (val!=null && val.startsWith(start)) | |
1037 { | |
1038 //existing cookie has same name, does it also match domain and path? | |
1039 if (((!hasDomain && !val.contains("Domain")) || (hasDomain && val.contains("Domain="+domain))) && | |
1040 ((!hasPath && !val.contains("Path")) || (hasPath && val.contains("Path="+path)))) | |
1041 { | |
1042 _fields.remove(field); | |
1043 if (last==null) | |
1044 _names.put(HttpHeaders.SET_COOKIE_BUFFER,field._next); | |
1045 else | |
1046 last._next=field._next; | |
1047 break; | |
1048 } | |
1049 } | |
1050 last=field; | |
1051 field=field._next; | |
1052 } | |
1053 | |
1054 add(HttpHeaders.SET_COOKIE_BUFFER, new ByteArrayBuffer(name_value_params)); | |
1055 | |
1056 // Expire responses with set-cookie headers so they do not get cached. | |
1057 put(HttpHeaders.EXPIRES_BUFFER, __01Jan1970_BUFFER); | |
1058 } | |
1059 | |
1060 /* -------------------------------------------------------------- */ | |
1061 public void putTo(Buffer buffer) throws IOException | |
1062 { | |
1063 for (int i = 0; i < _fields.size(); i++) | |
1064 { | |
1065 Field field = _fields.get(i); | |
1066 if (field != null) | |
1067 field.putTo(buffer); | |
1068 } | |
1069 BufferUtil.putCRLF(buffer); | |
1070 } | |
1071 | |
1072 /* -------------------------------------------------------------- */ | |
1073 public String toString() | |
1074 { | |
1075 try | |
1076 { | |
1077 StringBuffer buffer = new StringBuffer(); | |
1078 for (int i = 0; i < _fields.size(); i++) | |
1079 { | |
1080 Field field = (Field) _fields.get(i); | |
1081 if (field != null) | |
1082 { | |
1083 String tmp = field.getName(); | |
1084 if (tmp != null) buffer.append(tmp); | |
1085 buffer.append(": "); | |
1086 tmp = field.getValue(); | |
1087 if (tmp != null) buffer.append(tmp); | |
1088 buffer.append("\r\n"); | |
1089 } | |
1090 } | |
1091 buffer.append("\r\n"); | |
1092 return buffer.toString(); | |
1093 } | |
1094 catch (Exception e) | |
1095 { | |
1096 LOG.warn(e); | |
1097 return e.toString(); | |
1098 } | |
1099 } | |
1100 | |
1101 /* ------------------------------------------------------------ */ | |
1102 /** | |
1103 * Clear the header. | |
1104 */ | |
1105 public void clear() | |
1106 { | |
1107 _fields.clear(); | |
1108 _names.clear(); | |
1109 } | |
1110 | |
1111 /* ------------------------------------------------------------ */ | |
1112 /** | |
1113 * Add fields from another HttpFields instance. Single valued fields are replaced, while all | |
1114 * others are added. | |
1115 * | |
1116 * @param fields | |
1117 */ | |
1118 public void add(HttpFields fields) | |
1119 { | |
1120 if (fields == null) return; | |
1121 | |
1122 Enumeration e = fields.getFieldNames(); | |
1123 while (e.hasMoreElements()) | |
1124 { | |
1125 String name = (String) e.nextElement(); | |
1126 Enumeration values = fields.getValues(name); | |
1127 while (values.hasMoreElements()) | |
1128 add(name, (String) values.nextElement()); | |
1129 } | |
1130 } | |
1131 | |
1132 /* ------------------------------------------------------------ */ | |
1133 /** | |
1134 * Get field value parameters. Some field values can have parameters. This method separates the | |
1135 * value from the parameters and optionally populates a map with the parameters. For example: | |
1136 * | |
1137 * <PRE> | |
1138 * | |
1139 * FieldName : Value ; param1=val1 ; param2=val2 | |
1140 * | |
1141 * </PRE> | |
1142 * | |
1143 * @param value The Field value, possibly with parameteres. | |
1144 * @param parameters A map to populate with the parameters, or null | |
1145 * @return The value. | |
1146 */ | |
1147 public static String valueParameters(String value, Map<String,String> parameters) | |
1148 { | |
1149 if (value == null) return null; | |
1150 | |
1151 int i = value.indexOf(';'); | |
1152 if (i < 0) return value; | |
1153 if (parameters == null) return value.substring(0, i).trim(); | |
1154 | |
1155 StringTokenizer tok1 = new QuotedStringTokenizer(value.substring(i), ";", false, true); | |
1156 while (tok1.hasMoreTokens()) | |
1157 { | |
1158 String token = tok1.nextToken(); | |
1159 StringTokenizer tok2 = new QuotedStringTokenizer(token, "= "); | |
1160 if (tok2.hasMoreTokens()) | |
1161 { | |
1162 String paramName = tok2.nextToken(); | |
1163 String paramVal = null; | |
1164 if (tok2.hasMoreTokens()) paramVal = tok2.nextToken(); | |
1165 parameters.put(paramName, paramVal); | |
1166 } | |
1167 } | |
1168 | |
1169 return value.substring(0, i).trim(); | |
1170 } | |
1171 | |
1172 /* ------------------------------------------------------------ */ | |
1173 private static final Float __one = new Float("1.0"); | |
1174 private static final Float __zero = new Float("0.0"); | |
1175 private static final StringMap __qualities = new StringMap(); | |
1176 static | |
1177 { | |
1178 __qualities.put(null, __one); | |
1179 __qualities.put("1.0", __one); | |
1180 __qualities.put("1", __one); | |
1181 __qualities.put("0.9", new Float("0.9")); | |
1182 __qualities.put("0.8", new Float("0.8")); | |
1183 __qualities.put("0.7", new Float("0.7")); | |
1184 __qualities.put("0.66", new Float("0.66")); | |
1185 __qualities.put("0.6", new Float("0.6")); | |
1186 __qualities.put("0.5", new Float("0.5")); | |
1187 __qualities.put("0.4", new Float("0.4")); | |
1188 __qualities.put("0.33", new Float("0.33")); | |
1189 __qualities.put("0.3", new Float("0.3")); | |
1190 __qualities.put("0.2", new Float("0.2")); | |
1191 __qualities.put("0.1", new Float("0.1")); | |
1192 __qualities.put("0", __zero); | |
1193 __qualities.put("0.0", __zero); | |
1194 } | |
1195 | |
1196 /* ------------------------------------------------------------ */ | |
1197 public static Float getQuality(String value) | |
1198 { | |
1199 if (value == null) return __zero; | |
1200 | |
1201 int qe = value.indexOf(";"); | |
1202 if (qe++ < 0 || qe == value.length()) return __one; | |
1203 | |
1204 if (value.charAt(qe++) == 'q') | |
1205 { | |
1206 qe++; | |
1207 Map.Entry entry = __qualities.getEntry(value, qe, value.length() - qe); | |
1208 if (entry != null) return (Float) entry.getValue(); | |
1209 } | |
1210 | |
1211 HashMap params = new HashMap(3); | |
1212 valueParameters(value, params); | |
1213 String qs = (String) params.get("q"); | |
1214 Float q = (Float) __qualities.get(qs); | |
1215 if (q == null) | |
1216 { | |
1217 try | |
1218 { | |
1219 q = new Float(qs); | |
1220 } | |
1221 catch (Exception e) | |
1222 { | |
1223 q = __one; | |
1224 } | |
1225 } | |
1226 return q; | |
1227 } | |
1228 | |
1229 /* ------------------------------------------------------------ */ | |
1230 /** | |
1231 * List values in quality order. | |
1232 * | |
1233 * @param e Enumeration of values with quality parameters | |
1234 * @return values in quality order. | |
1235 */ | |
1236 public static List qualityList(Enumeration e) | |
1237 { | |
1238 if (e == null || !e.hasMoreElements()) return Collections.EMPTY_LIST; | |
1239 | |
1240 Object list = null; | |
1241 Object qual = null; | |
1242 | |
1243 // Assume list will be well ordered and just add nonzero | |
1244 while (e.hasMoreElements()) | |
1245 { | |
1246 String v = e.nextElement().toString(); | |
1247 Float q = getQuality(v); | |
1248 | |
1249 if (q.floatValue() >= 0.001) | |
1250 { | |
1251 list = LazyList.add(list, v); | |
1252 qual = LazyList.add(qual, q); | |
1253 } | |
1254 } | |
1255 | |
1256 List vl = LazyList.getList(list, false); | |
1257 if (vl.size() < 2) return vl; | |
1258 | |
1259 List ql = LazyList.getList(qual, false); | |
1260 | |
1261 // sort list with swaps | |
1262 Float last = __zero; | |
1263 for (int i = vl.size(); i-- > 0;) | |
1264 { | |
1265 Float q = (Float) ql.get(i); | |
1266 if (last.compareTo(q) > 0) | |
1267 { | |
1268 Object tmp = vl.get(i); | |
1269 vl.set(i, vl.get(i + 1)); | |
1270 vl.set(i + 1, tmp); | |
1271 ql.set(i, ql.get(i + 1)); | |
1272 ql.set(i + 1, q); | |
1273 last = __zero; | |
1274 i = vl.size(); | |
1275 continue; | |
1276 } | |
1277 last = q; | |
1278 } | |
1279 ql.clear(); | |
1280 return vl; | |
1281 } | |
1282 | |
1283 /* ------------------------------------------------------------ */ | |
1284 /* ------------------------------------------------------------ */ | |
1285 /* ------------------------------------------------------------ */ | |
1286 public static final class Field | |
1287 { | |
1288 private Buffer _name; | |
1289 private Buffer _value; | |
1290 private Field _next; | |
1291 | |
1292 /* ------------------------------------------------------------ */ | |
1293 private Field(Buffer name, Buffer value) | |
1294 { | |
1295 _name = name; | |
1296 _value = value; | |
1297 _next = null; | |
1298 } | |
1299 | |
1300 /* ------------------------------------------------------------ */ | |
1301 public void putTo(Buffer buffer) throws IOException | |
1302 { | |
1303 int o=(_name instanceof CachedBuffer)?((CachedBuffer)_name).getOrdinal():-1; | |
1304 if (o>=0) | |
1305 buffer.put(_name); | |
1306 else | |
1307 { | |
1308 int s=_name.getIndex(); | |
1309 int e=_name.putIndex(); | |
1310 while (s<e) | |
1311 { | |
1312 byte b=_name.peek(s++); | |
1313 switch(b) | |
1314 { | |
1315 case '\r': | |
1316 case '\n': | |
1317 case ':' : | |
1318 continue; | |
1319 default: | |
1320 buffer.put(b); | |
1321 } | |
1322 } | |
1323 } | |
1324 | |
1325 buffer.put((byte) ':'); | |
1326 buffer.put((byte) ' '); | |
1327 | |
1328 o=(_value instanceof CachedBuffer)?((CachedBuffer)_value).getOrdinal():-1; | |
1329 if (o>=0) | |
1330 buffer.put(_value); | |
1331 else | |
1332 { | |
1333 int s=_value.getIndex(); | |
1334 int e=_value.putIndex(); | |
1335 while (s<e) | |
1336 { | |
1337 byte b=_value.peek(s++); | |
1338 switch(b) | |
1339 { | |
1340 case '\r': | |
1341 case '\n': | |
1342 continue; | |
1343 default: | |
1344 buffer.put(b); | |
1345 } | |
1346 } | |
1347 } | |
1348 | |
1349 BufferUtil.putCRLF(buffer); | |
1350 } | |
1351 | |
1352 /* ------------------------------------------------------------ */ | |
1353 public String getName() | |
1354 { | |
1355 return BufferUtil.to8859_1_String(_name); | |
1356 } | |
1357 | |
1358 /* ------------------------------------------------------------ */ | |
1359 Buffer getNameBuffer() | |
1360 { | |
1361 return _name; | |
1362 } | |
1363 | |
1364 /* ------------------------------------------------------------ */ | |
1365 public int getNameOrdinal() | |
1366 { | |
1367 return HttpHeaders.CACHE.getOrdinal(_name); | |
1368 } | |
1369 | |
1370 /* ------------------------------------------------------------ */ | |
1371 public String getValue() | |
1372 { | |
1373 return BufferUtil.to8859_1_String(_value); | |
1374 } | |
1375 | |
1376 /* ------------------------------------------------------------ */ | |
1377 public Buffer getValueBuffer() | |
1378 { | |
1379 return _value; | |
1380 } | |
1381 | |
1382 /* ------------------------------------------------------------ */ | |
1383 public int getValueOrdinal() | |
1384 { | |
1385 return HttpHeaderValues.CACHE.getOrdinal(_value); | |
1386 } | |
1387 | |
1388 /* ------------------------------------------------------------ */ | |
1389 public int getIntValue() | |
1390 { | |
1391 return (int) getLongValue(); | |
1392 } | |
1393 | |
1394 /* ------------------------------------------------------------ */ | |
1395 public long getLongValue() | |
1396 { | |
1397 return BufferUtil.toLong(_value); | |
1398 } | |
1399 | |
1400 /* ------------------------------------------------------------ */ | |
1401 public String toString() | |
1402 { | |
1403 return ("[" + getName() + "=" + _value + (_next == null ? "" : "->") + "]"); | |
1404 } | |
1405 } | |
1406 } |