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