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