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