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