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 public void addSetCookie(HttpCookie cookie)
941 {
942 addSetCookie(
943 cookie.getName(),
944 cookie.getValue(),
945 cookie.getDomain(),
946 cookie.getPath(),
947 cookie.getMaxAge(),
948 cookie.getComment(),
949 cookie.isSecure(),
950 cookie.isHttpOnly(),
951 cookie.getVersion());
952 }
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967 public void addSetCookie(
968 final String name,
969 final String value,
970 final String domain,
971 final String path,
972 final long maxAge,
973 final String comment,
974 final boolean isSecure,
975 final boolean isHttpOnly,
976 final int version)
977 {
978
979 if (name == null || name.length() == 0) throw new IllegalArgumentException("Bad cookie name");
980
981
982 StringBuilder buf = new StringBuilder(128);
983 String name_value_params;
984 QuotedStringTokenizer.quoteIfNeeded(buf, name);
985 buf.append('=');
986 String start=buf.toString();
987 if (value != null && value.length() > 0)
988 QuotedStringTokenizer.quoteIfNeeded(buf, value);
989
990 if (version > 0)
991 {
992 buf.append(";Version=");
993 buf.append(version);
994 if (comment != null && comment.length() > 0)
995 {
996 buf.append(";Comment=");
997 QuotedStringTokenizer.quoteIfNeeded(buf, comment);
998 }
999 }
1000 if (path != null && path.length() > 0)
1001 {
1002 buf.append(";Path=");
1003 if (path.trim().startsWith("\""))
1004 buf.append(path);
1005 else
1006 QuotedStringTokenizer.quoteIfNeeded(buf,path);
1007 }
1008 if (domain != null && domain.length() > 0)
1009 {
1010 buf.append(";Domain=");
1011 QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase());
1012 }
1013
1014 if (maxAge >= 0)
1015 {
1016 if (version == 0)
1017 {
1018 buf.append(";Expires=");
1019 if (maxAge == 0)
1020 buf.append(__01Jan1970);
1021 else
1022 formatCookieDate(buf, System.currentTimeMillis() + 1000L * maxAge);
1023 }
1024 else
1025 {
1026 buf.append(";Max-Age=");
1027 buf.append(maxAge);
1028 }
1029 }
1030 else if (version > 0)
1031 {
1032 buf.append(";Discard");
1033 }
1034
1035 if (isSecure)
1036 buf.append(";Secure");
1037 if (isHttpOnly)
1038 buf.append(";HttpOnly");
1039
1040
1041 name_value_params = buf.toString();
1042 put(HttpHeaders.EXPIRES_BUFFER, __01Jan1970_BUFFER);
1043
1044
1045 Field field = getField(HttpHeaders.SET_COOKIE_BUFFER);
1046 if (field != null)
1047 {
1048 final int revision=_revision;
1049
1050 while (field!=null)
1051 {
1052 if (field._revision!=revision || field._value!=null && field._value.toString().startsWith(start))
1053 {
1054 field.reset(new ByteArrayBuffer(name_value_params),-1,revision);
1055 return;
1056 }
1057 field=field._next;
1058 }
1059 }
1060
1061 add(HttpHeaders.SET_COOKIE_BUFFER, new ByteArrayBuffer(name_value_params));
1062 }
1063
1064
1065 public void put(Buffer buffer) throws IOException
1066 {
1067 for (int i = 0; i < _fields.size(); i++)
1068 {
1069 Field field = _fields.get(i);
1070 if (field != null && field._revision == _revision) field.put(buffer);
1071 }
1072 BufferUtil.putCRLF(buffer);
1073 }
1074
1075
1076 public String toString()
1077 {
1078 try
1079 {
1080 StringBuffer buffer = new StringBuffer();
1081 for (int i = 0; i < _fields.size(); i++)
1082 {
1083 Field field = (Field) _fields.get(i);
1084 if (field != null && field._revision == _revision)
1085 {
1086 String tmp = field.getName();
1087 if (tmp != null) buffer.append(tmp);
1088 buffer.append(": ");
1089 tmp = field.getValue();
1090 if (tmp != null) buffer.append(tmp);
1091 buffer.append("\r\n");
1092 }
1093 }
1094 buffer.append("\r\n");
1095 return buffer.toString();
1096 }
1097 catch (Exception e)
1098 {
1099 Log.warn(e);
1100 return e.toString();
1101 }
1102 }
1103
1104
1105
1106
1107
1108 public void clear()
1109 {
1110 _revision++;
1111 if (_revision > 1000000)
1112 {
1113 _revision = 0;
1114 for (int i = _fields.size(); i-- > 0;)
1115 {
1116 Field field = _fields.get(i);
1117 if (field != null) field.clear();
1118 }
1119 }
1120 }
1121
1122
1123
1124
1125
1126 public void destroy()
1127 {
1128 if (_fields != null)
1129 {
1130 for (int i = _fields.size(); i-- > 0;)
1131 {
1132 Field field = _fields.get(i);
1133 if (field != null) {
1134 _bufferMap.remove(field.getNameBuffer());
1135 field.destroy();
1136 }
1137 }
1138 _fields.clear();
1139 }
1140 }
1141
1142
1143
1144
1145
1146
1147
1148
1149 public void add(HttpFields fields)
1150 {
1151 if (fields == null) return;
1152
1153 Enumeration e = fields.getFieldNames();
1154 while (e.hasMoreElements())
1155 {
1156 String name = (String) e.nextElement();
1157 Enumeration values = fields.getValues(name);
1158 while (values.hasMoreElements())
1159 add(name, (String) values.nextElement());
1160 }
1161 }
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178 public static String valueParameters(String value, Map<String,String> parameters)
1179 {
1180 if (value == null) return null;
1181
1182 int i = value.indexOf(';');
1183 if (i < 0) return value;
1184 if (parameters == null) return value.substring(0, i).trim();
1185
1186 StringTokenizer tok1 = new QuotedStringTokenizer(value.substring(i), ";", false, true);
1187 while (tok1.hasMoreTokens())
1188 {
1189 String token = tok1.nextToken();
1190 StringTokenizer tok2 = new QuotedStringTokenizer(token, "= ");
1191 if (tok2.hasMoreTokens())
1192 {
1193 String paramName = tok2.nextToken();
1194 String paramVal = null;
1195 if (tok2.hasMoreTokens()) paramVal = tok2.nextToken();
1196 parameters.put(paramName, paramVal);
1197 }
1198 }
1199
1200 return value.substring(0, i).trim();
1201 }
1202
1203
1204 private static final Float __one = new Float("1.0");
1205 private static final Float __zero = new Float("0.0");
1206 private static final StringMap __qualities = new StringMap();
1207 static
1208 {
1209 __qualities.put(null, __one);
1210 __qualities.put("1.0", __one);
1211 __qualities.put("1", __one);
1212 __qualities.put("0.9", new Float("0.9"));
1213 __qualities.put("0.8", new Float("0.8"));
1214 __qualities.put("0.7", new Float("0.7"));
1215 __qualities.put("0.66", new Float("0.66"));
1216 __qualities.put("0.6", new Float("0.6"));
1217 __qualities.put("0.5", new Float("0.5"));
1218 __qualities.put("0.4", new Float("0.4"));
1219 __qualities.put("0.33", new Float("0.33"));
1220 __qualities.put("0.3", new Float("0.3"));
1221 __qualities.put("0.2", new Float("0.2"));
1222 __qualities.put("0.1", new Float("0.1"));
1223 __qualities.put("0", __zero);
1224 __qualities.put("0.0", __zero);
1225 }
1226
1227
1228 public static Float getQuality(String value)
1229 {
1230 if (value == null) return __zero;
1231
1232 int qe = value.indexOf(";");
1233 if (qe++ < 0 || qe == value.length()) return __one;
1234
1235 if (value.charAt(qe++) == 'q')
1236 {
1237 qe++;
1238 Map.Entry entry = __qualities.getEntry(value, qe, value.length() - qe);
1239 if (entry != null) return (Float) entry.getValue();
1240 }
1241
1242 HashMap params = new HashMap(3);
1243 valueParameters(value, params);
1244 String qs = (String) params.get("q");
1245 Float q = (Float) __qualities.get(qs);
1246 if (q == null)
1247 {
1248 try
1249 {
1250 q = new Float(qs);
1251 }
1252 catch (Exception e)
1253 {
1254 q = __one;
1255 }
1256 }
1257 return q;
1258 }
1259
1260
1261
1262
1263
1264
1265
1266
1267 public static List qualityList(Enumeration e)
1268 {
1269 if (e == null || !e.hasMoreElements()) return Collections.EMPTY_LIST;
1270
1271 Object list = null;
1272 Object qual = null;
1273
1274
1275 while (e.hasMoreElements())
1276 {
1277 String v = e.nextElement().toString();
1278 Float q = getQuality(v);
1279
1280 if (q.floatValue() >= 0.001)
1281 {
1282 list = LazyList.add(list, v);
1283 qual = LazyList.add(qual, q);
1284 }
1285 }
1286
1287 List vl = LazyList.getList(list, false);
1288 if (vl.size() < 2) return vl;
1289
1290 List ql = LazyList.getList(qual, false);
1291
1292
1293 Float last = __zero;
1294 for (int i = vl.size(); i-- > 0;)
1295 {
1296 Float q = (Float) ql.get(i);
1297 if (last.compareTo(q) > 0)
1298 {
1299 Object tmp = vl.get(i);
1300 vl.set(i, vl.get(i + 1));
1301 vl.set(i + 1, tmp);
1302 ql.set(i, ql.get(i + 1));
1303 ql.set(i + 1, q);
1304 last = __zero;
1305 i = vl.size();
1306 continue;
1307 }
1308 last = q;
1309 }
1310 ql.clear();
1311 return vl;
1312 }
1313
1314
1315
1316
1317 public static final class Field
1318 {
1319 private Buffer _name;
1320 private Buffer _value;
1321 private String _stringValue;
1322 private long _numValue;
1323 private Field _next;
1324 private Field _prev;
1325 private int _revision;
1326
1327
1328 private Field(Buffer name, Buffer value, long numValue, int revision)
1329 {
1330 _name = name.asImmutableBuffer();
1331 _value = value.isImmutable() ? value : new View(value);
1332 _next = null;
1333 _prev = null;
1334 _revision = revision;
1335 _numValue = numValue;
1336 _stringValue=null;
1337 }
1338
1339
1340 private void clear()
1341 {
1342 _revision = -1;
1343 }
1344
1345
1346 private void destroy()
1347 {
1348 _name = null;
1349 _value = null;
1350 _next = null;
1351 _prev = null;
1352 _stringValue=null;
1353 }
1354
1355
1356
1357
1358
1359
1360 private void reset(Buffer value, long numValue, int revision)
1361 {
1362 _revision = revision;
1363 if (_value == null)
1364 {
1365 _value = value.isImmutable() ? value : new View(value);
1366 _numValue = numValue;
1367 _stringValue=null;
1368 }
1369 else if (value.isImmutable())
1370 {
1371 _value = value;
1372 _numValue = numValue;
1373 _stringValue=null;
1374 }
1375 else
1376 {
1377 if (_value instanceof View)
1378 ((View) _value).update(value);
1379 else
1380 _value = new View(value);
1381 _numValue = numValue;
1382
1383
1384 if (_stringValue!=null)
1385 {
1386 if (_stringValue.length()!=value.length())
1387 _stringValue=null;
1388 else
1389 {
1390 for (int i=value.length();i-->0;)
1391 {
1392 if (value.peek(value.getIndex()+i)!=_stringValue.charAt(i))
1393 {
1394 _stringValue=null;
1395 break;
1396 }
1397 }
1398 }
1399 }
1400 }
1401 }
1402
1403
1404
1405
1406 public void put(Buffer buffer) throws IOException
1407 {
1408 int o=(_name instanceof CachedBuffer)?((CachedBuffer)_name).getOrdinal():-1;
1409 if (o>=0)
1410 buffer.put(_name);
1411 else
1412 {
1413 int s=_name.getIndex();
1414 int e=_name.putIndex();
1415 while (s<e)
1416 {
1417 byte b=_name.peek(s++);
1418 switch(b)
1419 {
1420 case '\r':
1421 case '\n':
1422 case ':' :
1423 continue;
1424 default:
1425 buffer.put(b);
1426 }
1427 }
1428 }
1429
1430 buffer.put((byte) ':');
1431 buffer.put((byte) ' ');
1432
1433 o=(_value instanceof CachedBuffer)?((CachedBuffer)_value).getOrdinal():-1;
1434 if (o>=0 || _numValue>=0)
1435 buffer.put(_value);
1436 else
1437 {
1438 int s=_value.getIndex();
1439 int e=_value.putIndex();
1440 while (s<e)
1441 {
1442 byte b=_value.peek(s++);
1443 switch(b)
1444 {
1445 case '\r':
1446 case '\n':
1447 continue;
1448 default:
1449 buffer.put(b);
1450 }
1451 }
1452 }
1453
1454 BufferUtil.putCRLF(buffer);
1455 }
1456
1457
1458 public String getName()
1459 {
1460 return BufferUtil.to8859_1_String(_name);
1461 }
1462
1463
1464 Buffer getNameBuffer()
1465 {
1466 return _name;
1467 }
1468
1469
1470 public int getNameOrdinal()
1471 {
1472 return HttpHeaders.CACHE.getOrdinal(_name);
1473 }
1474
1475
1476 public String getValue()
1477 {
1478 if (_stringValue==null)
1479 {
1480 _stringValue=(_value instanceof CachedBuffer)
1481 ?_value.toString()
1482 :BufferUtil.to8859_1_String(_value);
1483 }
1484 return _stringValue;
1485 }
1486
1487
1488 public Buffer getValueBuffer()
1489 {
1490 return _value;
1491 }
1492
1493
1494 public int getValueOrdinal()
1495 {
1496 return HttpHeaderValues.CACHE.getOrdinal(_value);
1497 }
1498
1499
1500 public int getIntValue()
1501 {
1502 return (int) getLongValue();
1503 }
1504
1505
1506 public long getLongValue()
1507 {
1508 if (_numValue == -1) _numValue = BufferUtil.toLong(_value);
1509 return _numValue;
1510 }
1511
1512
1513 public String toString()
1514 {
1515 return ("[" + (_prev == null ? "" : "<-") + getName() + "="+_revision+"=" + _value + (_next == null ? "" : "->") + "]");
1516 }
1517 }
1518
1519 }