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