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