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