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