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