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