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 import org.eclipse.jetty.util.log.Log;
45
46
47
48
49
50
51
52
53
54
55 public class HttpFields
56 {
57
58 public static final TimeZone __GMT = TimeZone.getTimeZone("GMT");
59 public final static BufferDateCache __dateCache = new BufferDateCache("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
60
61
62 static
63 {
64 __GMT.setID("GMT");
65 __dateCache.setTimeZone(__GMT);
66 }
67
68
69 public final static String __separators = ", \t";
70
71
72 private static final String[] DAYS =
73 { "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
74 private static final String[] MONTHS =
75 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"};
76
77
78
79 private static class DateGenerator
80 {
81 private final StringBuilder buf = new StringBuilder(32);
82 private final GregorianCalendar gc = new GregorianCalendar(__GMT);
83
84 public String formatDate(long date)
85 {
86 buf.setLength(0);
87 gc.setTimeInMillis(date);
88
89 int day_of_week = gc.get(Calendar.DAY_OF_WEEK);
90 int day_of_month = gc.get(Calendar.DAY_OF_MONTH);
91 int month = gc.get(Calendar.MONTH);
92 int year = gc.get(Calendar.YEAR);
93 int century = year / 100;
94 year = year % 100;
95
96 int epoch = (int) ((date / 1000) % (60 * 60 * 24));
97 int seconds = epoch % 60;
98 epoch = epoch / 60;
99 int minutes = epoch % 60;
100 int hours = epoch / 60;
101
102 buf.append(DAYS[day_of_week]);
103 buf.append(',');
104 buf.append(' ');
105 StringUtil.append2digits(buf, day_of_month);
106
107 buf.append(' ');
108 buf.append(MONTHS[month]);
109 buf.append(' ');
110 StringUtil.append2digits(buf, century);
111 StringUtil.append2digits(buf, year);
112
113 buf.append(' ');
114 StringUtil.append2digits(buf, hours);
115 buf.append(':');
116 StringUtil.append2digits(buf, minutes);
117 buf.append(':');
118 StringUtil.append2digits(buf, seconds);
119 buf.append(" GMT");
120 return buf.toString();
121 }
122
123
124
125
126
127 public void formatCookieDate(StringBuilder buf, long date)
128 {
129 gc.setTimeInMillis(date);
130
131 int day_of_week = gc.get(Calendar.DAY_OF_WEEK);
132 int day_of_month = gc.get(Calendar.DAY_OF_MONTH);
133 int month = gc.get(Calendar.MONTH);
134 int year = gc.get(Calendar.YEAR);
135 year = year % 100;
136
137 int epoch = (int) ((date / 1000) % (60 * 60 * 24));
138 int seconds = epoch % 60;
139 epoch = epoch / 60;
140 int minutes = epoch % 60;
141 int hours = epoch / 60;
142
143 buf.append(DAYS[day_of_week]);
144 buf.append(',');
145 buf.append(' ');
146 StringUtil.append2digits(buf, day_of_month);
147
148 buf.append('-');
149 buf.append(MONTHS[month]);
150 buf.append('-');
151 StringUtil.append2digits(buf, year);
152
153 buf.append(' ');
154 StringUtil.append2digits(buf, hours);
155 buf.append(':');
156 StringUtil.append2digits(buf, minutes);
157 buf.append(':');
158 StringUtil.append2digits(buf, seconds);
159 buf.append(" GMT");
160 }
161
162
163 }
164
165
166 private static final ThreadLocal<DateGenerator> __dateGenerator =new ThreadLocal<DateGenerator>()
167 {
168 @Override
169 protected DateGenerator initialValue()
170 {
171 return new DateGenerator();
172 }
173 };
174
175
176
177
178
179
180 public static String formatDate(long date)
181 {
182 return __dateGenerator.get().formatDate(date);
183 }
184
185
186
187
188
189 public static void formatCookieDate(StringBuilder buf, long date)
190 {
191 __dateGenerator.get().formatCookieDate(buf,date);
192 }
193
194
195
196 private final static String __dateReceiveFmt[] =
197 {
198 "EEE, dd MMM yyyy HH:mm:ss zzz",
199 "EEE, dd-MMM-yy HH:mm:ss",
200 "EEE MMM dd HH:mm:ss yyyy",
201
202 "EEE, dd MMM yyyy HH:mm:ss", "EEE dd MMM yyyy HH:mm:ss zzz",
203 "EEE dd MMM yyyy HH:mm:ss", "EEE MMM dd yyyy HH:mm:ss zzz", "EEE MMM dd yyyy HH:mm:ss",
204 "EEE MMM-dd-yyyy HH:mm:ss zzz", "EEE MMM-dd-yyyy HH:mm:ss", "dd MMM yyyy HH:mm:ss zzz",
205 "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",
206 "MMM dd HH:mm:ss yyyy", "EEE MMM dd HH:mm:ss yyyy zzz",
207 "EEE, MMM dd HH:mm:ss yyyy zzz", "EEE, MMM dd HH:mm:ss yyyy", "EEE, dd-MMM-yy HH:mm:ss zzz",
208 "EEE dd-MMM-yy HH:mm:ss zzz", "EEE dd-MMM-yy HH:mm:ss",
209 };
210
211 private static class DateParser
212 {
213 final SimpleDateFormat _dateReceive[]= new SimpleDateFormat[__dateReceiveFmt.length];
214
215 long parse(final String dateVal)
216 {
217 for (int i = 0; i < _dateReceive.length; i++)
218 {
219 if (_dateReceive[i] == null)
220 {
221 _dateReceive[i] = new SimpleDateFormat(__dateReceiveFmt[i], Locale.US);
222 _dateReceive[i].setTimeZone(__GMT);
223 }
224
225 try
226 {
227 Date date = (Date) _dateReceive[i].parseObject(dateVal);
228 return date.getTime();
229 }
230 catch (java.lang.Exception e)
231 {
232
233 }
234 }
235
236 if (dateVal.endsWith(" GMT"))
237 {
238 final String val = dateVal.substring(0, dateVal.length() - 4);
239
240 for (int i = 0; i < _dateReceive.length; i++)
241 {
242 try
243 {
244 Date date = (Date) _dateReceive[i].parseObject(val);
245 return date.getTime();
246 }
247 catch (java.lang.Exception e)
248 {
249
250 }
251 }
252 }
253 return -1;
254 }
255 }
256
257
258 public static long parseDate(String date)
259 {
260 return __dateParser.get().parse(date);
261 }
262
263
264 private static final ThreadLocal<DateParser> __dateParser =new ThreadLocal<DateParser>()
265 {
266 @Override
267 protected DateParser initialValue()
268 {
269 return new DateParser();
270 }
271 };
272
273
274
275
276
277
278 public final static String __01Jan1970 = formatDate(0).trim();
279 public final static Buffer __01Jan1970_BUFFER = new ByteArrayBuffer(__01Jan1970);
280
281
282 protected final ArrayList<Field> _fields = new ArrayList<Field>(20);
283 protected final HashMap<Buffer,Field> _bufferMap = new HashMap<Buffer,Field>(32);
284 protected int _revision;
285
286
287
288
289
290 public HttpFields()
291 {
292 }
293
294
295
296
297
298
299 public Enumeration<String> getFieldNames()
300 {
301 final int revision=_revision;
302 return new Enumeration<String>()
303 {
304 int i = 0;
305 Field field = null;
306
307 public boolean hasMoreElements()
308 {
309 if (field != null) return true;
310 while (i < _fields.size())
311 {
312 Field f = _fields.get(i++);
313 if (f != null && f._prev == null && f._revision == revision)
314 {
315 field = f;
316 return true;
317 }
318 }
319 return false;
320 }
321
322 public String nextElement() throws NoSuchElementException
323 {
324 if (field != null || hasMoreElements())
325 {
326 String n = BufferUtil.to8859_1_String(field._name);
327 field = null;
328 return n;
329 }
330 throw new NoSuchElementException();
331 }
332 };
333 }
334
335
336 public int size()
337 {
338 return _fields.size();
339 }
340
341
342
343
344
345
346
347 public Field getField(int i)
348 {
349 final Field field = _fields.get(i);
350 if (field._revision!=_revision)
351 return null;
352 return field;
353 }
354
355
356 private Field getField(String name)
357 {
358 return _bufferMap.get(HttpHeaders.CACHE.lookup(name));
359 }
360
361
362 private Field getField(Buffer name)
363 {
364 return _bufferMap.get(name);
365 }
366
367
368 public boolean containsKey(Buffer name)
369 {
370 Field f = getField(name);
371 return (f != null && f._revision == _revision);
372 }
373
374
375 public boolean containsKey(String name)
376 {
377 Field f = getField(name);
378 return (f != null && f._revision == _revision);
379 }
380
381
382
383
384
385
386
387 public String getStringField(String name)
388 {
389
390 Field field = getField(name);
391 if (field != null && field._revision == _revision)
392 return field.getValue();
393 return null;
394 }
395
396
397
398
399
400
401
402 public String getStringField(Buffer name)
403 {
404
405 Field field = getField(name);
406 if (field != null && field._revision == _revision)
407 return BufferUtil.to8859_1_String(field._value);
408 return null;
409 }
410
411
412
413
414
415
416
417 public Buffer get(Buffer name)
418 {
419 Field field = getField(name);
420 if (field != null && field._revision == _revision)
421 return field._value;
422 return null;
423 }
424
425
426
427
428
429
430
431
432 public Enumeration<String> getValues(String name)
433 {
434 final Field field = getField(name);
435 if (field == null)
436 return null;
437 final int revision=_revision;
438
439 return new Enumeration<String>()
440 {
441 Field f = field;
442
443 public boolean hasMoreElements()
444 {
445 while (f != null && f._revision != revision)
446 f = f._next;
447 return f != null;
448 }
449
450 public String nextElement() throws NoSuchElementException
451 {
452 if (f == null) throw new NoSuchElementException();
453 Field n = f;
454 do
455 f = f._next;
456 while (f != null && f._revision != revision);
457 return n.getValue();
458 }
459 };
460 }
461
462
463
464
465
466
467
468
469 public Enumeration<String> getValues(Buffer name)
470 {
471 final Field field = getField(name);
472 if (field == null)
473 return null;
474 final int revision=_revision;
475
476 return new Enumeration<String>()
477 {
478 Field f = field;
479
480 public boolean hasMoreElements()
481 {
482 while (f != null && f._revision != revision)
483 f = f._next;
484 return f != null;
485 }
486
487 public String nextElement() throws NoSuchElementException
488 {
489 if (f == null) throw new NoSuchElementException();
490 Field n = f;
491 f = f._next;
492 while (f != null && f._revision != revision)
493 f = f._next;
494 return n.getValue();
495 }
496 };
497 }
498
499
500
501
502
503
504
505
506
507
508
509 public Enumeration<String> getValues(String name, final String separators)
510 {
511 final Enumeration<String> e = getValues(name);
512 if (e == null)
513 return null;
514 return new Enumeration<String>()
515 {
516 QuotedStringTokenizer tok = null;
517
518 public boolean hasMoreElements()
519 {
520 if (tok != null && tok.hasMoreElements()) return true;
521 while (e.hasMoreElements())
522 {
523 String value = e.nextElement();
524 tok = new QuotedStringTokenizer(value, separators, false, false);
525 if (tok.hasMoreElements()) return true;
526 }
527 tok = null;
528 return false;
529 }
530
531 public String nextElement() throws NoSuchElementException
532 {
533 if (!hasMoreElements()) throw new NoSuchElementException();
534 String next = (String) tok.nextElement();
535 if (next != null) next = next.trim();
536 return next;
537 }
538 };
539 }
540
541
542
543
544
545
546
547
548 public void put(String name, String value)
549 {
550 Buffer n = HttpHeaders.CACHE.lookup(name);
551 Buffer v = null;
552 if (value != null)
553 v = HttpHeaderValues.CACHE.lookup(value);
554 put(n, v, -1);
555 }
556
557
558
559
560
561
562
563
564 public void put(Buffer name, String value)
565 {
566 Buffer v = HttpHeaderValues.CACHE.lookup(value);
567 put(name, v, -1);
568 }
569
570
571
572
573
574
575
576
577 public void put(Buffer name, Buffer value)
578 {
579 put(name, value, -1);
580 }
581
582
583
584
585
586
587
588
589
590 public void put(Buffer name, Buffer value, long numValue)
591 {
592 if (value == null)
593 {
594 remove(name);
595 return;
596 }
597
598 if (!(name instanceof BufferCache.CachedBuffer)) name = HttpHeaders.CACHE.lookup(name);
599
600 Field field = _bufferMap.get(name);
601
602
603 if (field != null)
604 {
605 field.reset(value, numValue, _revision);
606 field = field._next;
607 while (field != null)
608 {
609 field.clear();
610 field = field._next;
611 }
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 = _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 = _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;
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 if (path.trim().startsWith("\""))
983 buf.append(path);
984 else
985 QuotedStringTokenizer.quoteIfNeeded(buf,path);
986 }
987 if (domain != null && domain.length() > 0)
988 {
989 buf.append(";Domain=");
990 QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase());
991 }
992
993 if (maxAge >= 0)
994 {
995 if (version == 0)
996 {
997 buf.append(";Expires=");
998 if (maxAge == 0)
999 buf.append(__01Jan1970);
1000 else
1001 formatCookieDate(buf, System.currentTimeMillis() + 1000L * maxAge);
1002 }
1003 else
1004 {
1005 buf.append(";Max-Age=");
1006 buf.append(maxAge);
1007 }
1008 }
1009 else if (version > 0)
1010 {
1011 buf.append(";Discard");
1012 }
1013
1014 if (isSecure)
1015 buf.append(";Secure");
1016 if (isHttpOnly)
1017 buf.append(";HttpOnly");
1018
1019
1020 name_value_params = buf.toString();
1021 put(HttpHeaders.EXPIRES_BUFFER, __01Jan1970_BUFFER);
1022 add(HttpHeaders.SET_COOKIE_BUFFER, new ByteArrayBuffer(name_value_params));
1023 }
1024
1025
1026 public void put(Buffer buffer) throws IOException
1027 {
1028 for (int i = 0; i < _fields.size(); i++)
1029 {
1030 Field field = _fields.get(i);
1031 if (field != null && field._revision == _revision) field.put(buffer);
1032 }
1033 BufferUtil.putCRLF(buffer);
1034 }
1035
1036
1037 public String toString()
1038 {
1039 try
1040 {
1041 ByteArrayBuffer buffer = new ByteArrayBuffer(4096);
1042 put(buffer);
1043 return BufferUtil.to8859_1_String(buffer);
1044 }
1045 catch (Exception e)
1046 {
1047 Log.warn(e);
1048 return e.toString();
1049 }
1050
1051 }
1052
1053
1054
1055
1056
1057 public void clear()
1058 {
1059 _revision++;
1060 if (_revision > 1000000)
1061 {
1062 _revision = 0;
1063 for (int i = _fields.size(); i-- > 0;)
1064 {
1065 Field field = _fields.get(i);
1066 if (field != null) field.clear();
1067 }
1068 }
1069 }
1070
1071
1072
1073
1074
1075 public void destroy()
1076 {
1077 if (_fields != null)
1078 {
1079 for (int i = _fields.size(); i-- > 0;)
1080 {
1081 Field field = _fields.get(i);
1082 if (field != null) field.destroy();
1083 }
1084 _fields.clear();
1085 }
1086 }
1087
1088
1089
1090
1091
1092
1093
1094
1095 public void add(HttpFields fields)
1096 {
1097 if (fields == null) return;
1098
1099 Enumeration e = fields.getFieldNames();
1100 while (e.hasMoreElements())
1101 {
1102 String name = (String) e.nextElement();
1103 Enumeration values = fields.getValues(name);
1104 while (values.hasMoreElements())
1105 add(name, (String) values.nextElement());
1106 }
1107 }
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124 public static String valueParameters(String value, Map<String,String> parameters)
1125 {
1126 if (value == null) return null;
1127
1128 int i = value.indexOf(';');
1129 if (i < 0) return value;
1130 if (parameters == null) return value.substring(0, i).trim();
1131
1132 StringTokenizer tok1 = new QuotedStringTokenizer(value.substring(i), ";", false, true);
1133 while (tok1.hasMoreTokens())
1134 {
1135 String token = tok1.nextToken();
1136 StringTokenizer tok2 = new QuotedStringTokenizer(token, "= ");
1137 if (tok2.hasMoreTokens())
1138 {
1139 String paramName = tok2.nextToken();
1140 String paramVal = null;
1141 if (tok2.hasMoreTokens()) paramVal = tok2.nextToken();
1142 parameters.put(paramName, paramVal);
1143 }
1144 }
1145
1146 return value.substring(0, i).trim();
1147 }
1148
1149
1150 private static final Float __one = new Float("1.0");
1151 private static final Float __zero = new Float("0.0");
1152 private static final StringMap __qualities = new StringMap();
1153 static
1154 {
1155 __qualities.put(null, __one);
1156 __qualities.put("1.0", __one);
1157 __qualities.put("1", __one);
1158 __qualities.put("0.9", new Float("0.9"));
1159 __qualities.put("0.8", new Float("0.8"));
1160 __qualities.put("0.7", new Float("0.7"));
1161 __qualities.put("0.66", new Float("0.66"));
1162 __qualities.put("0.6", new Float("0.6"));
1163 __qualities.put("0.5", new Float("0.5"));
1164 __qualities.put("0.4", new Float("0.4"));
1165 __qualities.put("0.33", new Float("0.33"));
1166 __qualities.put("0.3", new Float("0.3"));
1167 __qualities.put("0.2", new Float("0.2"));
1168 __qualities.put("0.1", new Float("0.1"));
1169 __qualities.put("0", __zero);
1170 __qualities.put("0.0", __zero);
1171 }
1172
1173
1174 public static Float getQuality(String value)
1175 {
1176 if (value == null) return __zero;
1177
1178 int qe = value.indexOf(";");
1179 if (qe++ < 0 || qe == value.length()) return __one;
1180
1181 if (value.charAt(qe++) == 'q')
1182 {
1183 qe++;
1184 Map.Entry entry = __qualities.getEntry(value, qe, value.length() - qe);
1185 if (entry != null) return (Float) entry.getValue();
1186 }
1187
1188 HashMap params = new HashMap(3);
1189 valueParameters(value, params);
1190 String qs = (String) params.get("q");
1191 Float q = (Float) __qualities.get(qs);
1192 if (q == null)
1193 {
1194 try
1195 {
1196 q = new Float(qs);
1197 }
1198 catch (Exception e)
1199 {
1200 q = __one;
1201 }
1202 }
1203 return q;
1204 }
1205
1206
1207
1208
1209
1210
1211
1212
1213 public static List qualityList(Enumeration e)
1214 {
1215 if (e == null || !e.hasMoreElements()) return Collections.EMPTY_LIST;
1216
1217 Object list = null;
1218 Object qual = null;
1219
1220
1221 while (e.hasMoreElements())
1222 {
1223 String v = e.nextElement().toString();
1224 Float q = getQuality(v);
1225
1226 if (q.floatValue() >= 0.001)
1227 {
1228 list = LazyList.add(list, v);
1229 qual = LazyList.add(qual, q);
1230 }
1231 }
1232
1233 List vl = LazyList.getList(list, false);
1234 if (vl.size() < 2) return vl;
1235
1236 List ql = LazyList.getList(qual, false);
1237
1238
1239 Float last = __zero;
1240 for (int i = vl.size(); i-- > 0;)
1241 {
1242 Float q = (Float) ql.get(i);
1243 if (last.compareTo(q) > 0)
1244 {
1245 Object tmp = vl.get(i);
1246 vl.set(i, vl.get(i + 1));
1247 vl.set(i + 1, tmp);
1248 ql.set(i, ql.get(i + 1));
1249 ql.set(i + 1, q);
1250 last = __zero;
1251 i = vl.size();
1252 continue;
1253 }
1254 last = q;
1255 }
1256 ql.clear();
1257 return vl;
1258 }
1259
1260
1261
1262
1263 public static final class Field
1264 {
1265 private Buffer _name;
1266 private Buffer _value;
1267 private String _stringValue;
1268 private long _numValue;
1269 private Field _next;
1270 private Field _prev;
1271 private int _revision;
1272
1273
1274 private Field(Buffer name, Buffer value, long numValue, int revision)
1275 {
1276 _name = name.asImmutableBuffer();
1277 _value = value.isImmutable() ? value : new View(value);
1278 _next = null;
1279 _prev = null;
1280 _revision = revision;
1281 _numValue = numValue;
1282 _stringValue=null;
1283 }
1284
1285
1286 private void clear()
1287 {
1288 _revision = -1;
1289 }
1290
1291
1292 private void destroy()
1293 {
1294 _name = null;
1295 _value = null;
1296 _next = null;
1297 _prev = null;
1298 _stringValue=null;
1299 }
1300
1301
1302
1303
1304
1305
1306 private void reset(Buffer value, long numValue, int revision)
1307 {
1308 _revision = revision;
1309 if (_value == null)
1310 {
1311 _value = value.isImmutable() ? value : new View(value);
1312 _numValue = numValue;
1313 _stringValue=null;
1314 }
1315 else if (value.isImmutable())
1316 {
1317 _value = value;
1318 _numValue = numValue;
1319 _stringValue=null;
1320 }
1321 else
1322 {
1323 if (_value instanceof View)
1324 ((View) _value).update(value);
1325 else
1326 _value = new View(value);
1327 _numValue = numValue;
1328
1329
1330 if (_stringValue!=null)
1331 {
1332 if (_stringValue.length()!=value.length())
1333 _stringValue=null;
1334 else
1335 {
1336 for (int i=value.length();i-->0;)
1337 {
1338 if (value.peek(value.getIndex()+i)!=_stringValue.charAt(i))
1339 {
1340 _stringValue=null;
1341 break;
1342 }
1343 }
1344 }
1345 }
1346 }
1347 }
1348
1349
1350
1351
1352 public void put(Buffer buffer) throws IOException
1353 {
1354 int o=(_name instanceof CachedBuffer)?((CachedBuffer)_name).getOrdinal():-1;
1355 if (o>=0)
1356 buffer.put(_name);
1357 else
1358 {
1359 int s=_name.getIndex();
1360 int e=_name.putIndex();
1361 while (s<e)
1362 {
1363 byte b=_name.peek(s++);
1364 switch(b)
1365 {
1366 case '\r':
1367 case '\n':
1368 case ':' :
1369 continue;
1370 default:
1371 buffer.put(b);
1372 }
1373 }
1374 }
1375
1376 buffer.put((byte) ':');
1377 buffer.put((byte) ' ');
1378
1379 o=(_value instanceof CachedBuffer)?((CachedBuffer)_value).getOrdinal():-1;
1380 if (o>=0 || _numValue>=0)
1381 buffer.put(_value);
1382 else
1383 {
1384 int s=_value.getIndex();
1385 int e=_value.putIndex();
1386 while (s<e)
1387 {
1388 byte b=_value.peek(s++);
1389 switch(b)
1390 {
1391 case '\r':
1392 case '\n':
1393 continue;
1394 default:
1395 buffer.put(b);
1396 }
1397 }
1398 }
1399
1400 BufferUtil.putCRLF(buffer);
1401 }
1402
1403
1404 public String getName()
1405 {
1406 return BufferUtil.to8859_1_String(_name);
1407 }
1408
1409
1410 Buffer getNameBuffer()
1411 {
1412 return _name;
1413 }
1414
1415
1416 public int getNameOrdinal()
1417 {
1418 return HttpHeaders.CACHE.getOrdinal(_name);
1419 }
1420
1421
1422 public String getValue()
1423 {
1424 if (_stringValue==null)
1425 {
1426 _stringValue=(_value instanceof CachedBuffer)
1427 ?_value.toString()
1428 :BufferUtil.to8859_1_String(_value);
1429 }
1430 return _stringValue;
1431 }
1432
1433
1434 public Buffer getValueBuffer()
1435 {
1436 return _value;
1437 }
1438
1439
1440 public int getValueOrdinal()
1441 {
1442 return HttpHeaderValues.CACHE.getOrdinal(_value);
1443 }
1444
1445
1446 public int getIntValue()
1447 {
1448 return (int) getLongValue();
1449 }
1450
1451
1452 public long getLongValue()
1453 {
1454 if (_numValue == -1) _numValue = BufferUtil.toLong(_value);
1455 return _numValue;
1456 }
1457
1458
1459 public String toString()
1460 {
1461 return ("[" + (_prev == null ? "" : "<-") + getName() + "="+_revision+"=" + _value + (_next == null ? "" : "->") + "]");
1462 }
1463 }
1464
1465 }